File: Compilation\BaseTemplateBuildProvider.cs
Project: ndp\fx\src\xsp\system\Web\System.Web.csproj (System.Web)
//------------------------------------------------------------------------------
// <copyright file="BaseTemplateBuildProvider.cs" company="Microsoft">
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// </copyright>
//------------------------------------------------------------------------------
 
 
 
namespace System.Web.Compilation {
 
using System;
using System.IO;
using System.Collections;
using System.Collections.Specialized;
using System.Reflection;
using System.CodeDom;
using System.CodeDom.Compiler;
using System.Web.Util;
using System.Web.UI;
 
internal abstract class BaseTemplateBuildProvider: InternalBuildProvider {
 
    private TemplateParser _parser;
    internal TemplateParser Parser { get { return _parser; } }
 
    internal override IAssemblyDependencyParser AssemblyDependencyParser {
        get { return _parser; }
    }
 
    private string _instantiatableFullTypeName;
    private string _intermediateFullTypeName;
 
    protected abstract TemplateParser CreateParser();
 
    internal abstract BaseCodeDomTreeGenerator CreateCodeDomTreeGenerator(TemplateParser parser);
 
    protected internal override CodeCompileUnit GetCodeCompileUnit(out IDictionary linePragmasTable) {
        Debug.Assert(_parser != null);
 
        // Return the provider type and compiler params
        Type codeDomProviderType = _parser.CompilerType.CodeDomProviderType;
 
        // Create a code generator for the language
        CodeDomProvider codeDomProvider = CompilationUtil.CreateCodeDomProviderNonPublic(
            codeDomProviderType);
 
        // Create a designer mode codedom tree for the page
        BaseCodeDomTreeGenerator treeGenerator = CreateCodeDomTreeGenerator(_parser);
        treeGenerator.SetDesignerMode();
        CodeCompileUnit ccu = treeGenerator.GetCodeDomTree(codeDomProvider,
            new StringResourceBuilder(), VirtualPathObject);
        linePragmasTable = treeGenerator.LinePragmasTable;
 
// This code is used to see the full generated code in the debugger.  Just uncomment and look at
// generatedCode in the debugger.  Don't check in with this code uncommented!
#if TESTCODE
        Stream stream = new MemoryStream();
        StreamWriter writer = new StreamWriter(stream, System.Text.Encoding.Unicode);
        codeDomProvider.GenerateCodeFromCompileUnit(ccu, writer, null /*CodeGeneratorOptions*/);
        writer.Flush();
        stream.Seek(0, SeekOrigin.Begin);
        TextReader reader = new StreamReader(stream);
        string generatedCode = reader.ReadToEnd();
#endif
 
        return ccu;
    }
 
    public override CompilerType CodeCompilerType {
        get {
            Debug.Assert(_parser == null);
 
            _parser = CreateParser();
 
            if (IgnoreParseErrors)
                _parser.IgnoreParseErrors = true;
 
            if (IgnoreControlProperties)
                _parser.IgnoreControlProperties = true;
 
            if (!ThrowOnFirstParseError)
                _parser.ThrowOnFirstParseError = false;
 
            _parser.Parse(ReferencedAssemblies, VirtualPathObject);
 
            // If the page is non-compiled, don't ask for a language
            if (!Parser.RequiresCompilation)
                return null;
 
            return _parser.CompilerType;
        }
    }
 
    internal override ICollection GetCompileWithDependencies() {
 
        // If there is a code besides file, return it
 
        if (_parser.CodeFileVirtualPath == null)
            return null;
 
        // no-compile pages should not have any compile with dependencies
        Debug.Assert(Parser.RequiresCompilation);
 
        return new SingleObjectCollection(_parser.CodeFileVirtualPath);
    }
 
    public override void GenerateCode(AssemblyBuilder assemblyBuilder) {
 
        // Don't generate any code for no-compile pages
        if (!Parser.RequiresCompilation)
            return;
 
        BaseCodeDomTreeGenerator treeGenerator = CreateCodeDomTreeGenerator(_parser);
 
        CodeCompileUnit ccu = treeGenerator.GetCodeDomTree(assemblyBuilder.CodeDomProvider,
            assemblyBuilder.StringResourceBuilder, VirtualPathObject);
 
        if (ccu != null) {
            // Add all the assemblies
            if (_parser.AssemblyDependencies != null) {
                foreach (Assembly assembly in _parser.AssemblyDependencies) {
                    assemblyBuilder.AddAssemblyReference(assembly, ccu);
                }
            }
 
            assemblyBuilder.AddCodeCompileUnit(this, ccu);
        }
 
        // Get the name of the generated type that can be instantiated.  It may be null
        // in updatable compilation scenarios.
        _instantiatableFullTypeName = treeGenerator.GetInstantiatableFullTypeName();
 
        // tell the assembly builder to generate a fast factory for this type
        if (_instantiatableFullTypeName != null)
            assemblyBuilder.GenerateTypeFactory(_instantiatableFullTypeName, ccu);
 
        _intermediateFullTypeName = treeGenerator.GetIntermediateFullTypeName();
    }
 
    public override Type GetGeneratedType(CompilerResults results) {
        return GetGeneratedType(results, useDelayLoadTypeIfEnabled: false);
    }
 
    internal Type GetGeneratedType(CompilerResults results, bool useDelayLoadTypeIfEnabled) {
 
        // No Type is generated for no-compile pages
        if (!Parser.RequiresCompilation)
            return null;
 
        // Figure out the Type that needs to be persisted
        string typeName;
 
        if (_instantiatableFullTypeName == null) {
 
            if (Parser.CodeFileVirtualPath != null) {
                // Updatable precomp of a code separation page: use the intermediate type
                typeName = _intermediateFullTypeName;
            }
            else {
                // Updatable precomp of a single page: use the base type, since nothing got compiled
                return Parser.BaseType;
            }
        }
        else {
            typeName = _instantiatableFullTypeName;
        }
 
        Debug.Assert(typeName != null);
 
        Type generatedType;
        if (useDelayLoadTypeIfEnabled && DelayLoadType.Enabled) {
            string assemblyFilename = Path.GetFileName(results.PathToAssembly);
            string assemblyName = Util.GetAssemblyNameFromFileName(assemblyFilename);
            generatedType = new DelayLoadType(assemblyName, typeName);
        }
        else {
            generatedType = results.CompiledAssembly.GetType(typeName);
        }
 
        // It should always extend the required base type
        // Note: removing this assert as advanced ControlBuilder scenarios allow changing the base type
        //Debug.Assert(Parser.BaseType.IsAssignableFrom(generatedType));
 
        return generatedType;
    }
 
    internal override BuildResultCompiledType CreateBuildResult(Type t) {
        return new BuildResultCompiledTemplateType(t);
    }
 
    public override ICollection VirtualPathDependencies {
        get {
            return _parser.SourceDependencies;
        }
    }
 
    internal override ICollection GetGeneratedTypeNames() {
        if (_parser.GeneratedClassName == null && _parser.BaseTypeName == null) {
            return null;
        }
 
        ArrayList collection = new ArrayList();
        if (_parser.GeneratedClassName != null) {
            collection.Add(_parser.GeneratedClassName);
        }
 
        if (_parser.BaseTypeName != null) {
            collection.Add(Util.MakeFullTypeName(_parser.BaseTypeNamespace, _parser.BaseTypeName));
        }
 
        return collection;
    }
}
 
}