关于动态编译

       如果将配置性文件编译为程序集,在执行的时候,它的性能将会高很多。

 

      参看一下, System.Web.HttpApplicationFactory 中方法 CompileApplication()

 

private void CompileApplication() { 

            // Get the Application Type and AppState from the global file

 

            _theApplicationType = BuildManager.GetGlobalAsaxType(); 



            BuildResultCompiledGlobalAsaxType result = BuildManager.GetGlobalAsaxBuildResult(); 



            if (result != null) {



                // Even if global.asax was already compiled, we need to get the collections 

                // of application and session objects, since they are not persisted when

                // global.asax is compiled.  Ideally, they would be, but since <object> tags 

                // are only there for ASP compat, it's not worth the trouble. 

                // Note that we only do this is the rare case where we know global.asax contains

                // <object> tags, to avoid always paying the price (VSWhidbey 453101) 

                if (result.HasAppOrSessionObjects) {

                    GetAppStateByParsingGlobalAsax();

                }

 

                // Remember file dependencies

                _fileDependencies = result.VirtualPathDependencies; 

            } 



            if (_state == null) { 

                _state = new HttpApplicationState();

            }



 

            // Prepare to hookup event handlers via reflection

 

            ReflectOnApplicationType(); 

        }

 

 

//------------------------------------------------------------------------------ 

// <copyright file="CodeDirectoryCompiler.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.CodeDom.Compiler; 

using System.Configuration;

using System.Globalization; 

using System.Web.Configuration; 

using System.Reflection;

using System.Web.Hosting; 

using System.Web.Util;

using System.Web.UI;



// The different types of directory that we treat as 'Code' (with minor differences) 

internal enum CodeDirectoryType {

    MainCode,       // The main /code directory 

    SubCode,        // Code subdirectories registered to be compiled separately 

    AppResources,   // The /Resources directory

    LocalResources, // A /LocalResources directory (at any level) 

    WebReferences   // The /WebReferences directory

}



internal class CodeDirectoryCompiler { 



    private VirtualPath _virtualDir; 

    private CodeDirectoryType _dirType; 

    private StringSet _excludedSubdirectories;

 

    private BuildProvidersCompiler _bpc;

    private BuildProviderSet _buildProviders = new BuildProviderSet();



    private bool _onlyBuildLocalizedResources; 



    static internal BuildResultMainCodeAssembly _mainCodeBuildResult; 

 

    internal static bool IsResourceCodeDirectoryType(CodeDirectoryType dirType) {

        return dirType == CodeDirectoryType.AppResources || dirType == CodeDirectoryType.LocalResources; 

    }



    internal static Assembly GetCodeDirectoryAssembly(VirtualPath virtualDir,

        CodeDirectoryType dirType, string assemblyName, 

        StringSet excludedSubdirectories, bool isDirectoryAllowed) {

 

        string physicalDir = virtualDir.MapPath(); 



        if (!isDirectoryAllowed) { 



            // The directory should never exist in a precompiled app

            if (Directory.Exists(physicalDir)) {

                throw new HttpException(SR.GetString( 

                    SR.Bar_dir_in_precompiled_app, virtualDir));

            } 

        } 



        bool supportLocalization = IsResourceCodeDirectoryType(dirType); 



        // Determine the proper cache key based on the type of directory we're processing

        string cacheKey = assemblyName;

 

        // Try the cache first

        BuildResult result = BuildManager.GetBuildResultFromCache(cacheKey); 

        Assembly resultAssembly = null; 



        // If it's cached, just return it 

        if (result != null) {



            // It should always be a BuildResultCompiledAssembly, though if there is

            // a VirtualPathProvider doing very bad things, it may not (VSWhidbey 341701) 

            Debug.Assert(result is BuildResultCompiledAssembly);

            if (result is BuildResultCompiledAssembly) { 

 

                // If it's the main code assembly, keep track of it so we can later call

                // the AppInitialize method 

                if (result is BuildResultMainCodeAssembly) {

                    Debug.Assert(dirType == CodeDirectoryType.MainCode);

                    Debug.Assert(_mainCodeBuildResult == null);

                    _mainCodeBuildResult = (BuildResultMainCodeAssembly) result; 

                }

 

                resultAssembly = ((BuildResultCompiledAssembly)result).ResultAssembly; 



                if (!supportLocalization) 

                    return resultAssembly;



                // We found a preserved resource assembly.  However, we may not be done,

                // as the culture specific files may have changed. 



                // But don't make any further checks if the directory is not allowed (precomp secenario). 

                // In that case, we should always return the assembly (VSWhidbey 533498) 

                if (!isDirectoryAllowed)

                    return resultAssembly; 



                BuildResultResourceAssembly buildResultResAssembly = (BuildResultResourceAssembly)result;



                string newResourcesDependenciesHash = HashCodeCombiner.GetDirectoryHash(virtualDir); 



                // If the resources hash (which includes satellites) is up to date, we're done 

                if (newResourcesDependenciesHash == buildResultResAssembly.ResourcesDependenciesHash) 

                    return resultAssembly;

           } 

        }



        // If app was precompiled, don't attempt compilation

        if (!isDirectoryAllowed) 

            return null;

 

        // Check whether the virtual dir is mapped to a different application, 

        // which we don't support (VSWhidbey 218603).  But don't do this for LocalResource (VSWhidbey 237935)

        if (dirType != CodeDirectoryType.LocalResources && !StringUtil.StringStartsWithIgnoreCase(physicalDir, HttpRuntime.AppDomainAppPathInternal)) { 

            throw new HttpException(SR.GetString(SR.Virtual_codedir, virtualDir.VirtualPathString));

        }



        // If the directory doesn't exist, we may be done 

        if (!Directory.Exists(physicalDir)) {

 

            // We're definitely done if it's not the main code dir 

            if (dirType != CodeDirectoryType.MainCode)

                return null; 



            // If it is the main code dir, we're only done is there is no profile to compile

            // since the profice gets built as part of the main assembly.

            if (!ProfileBuildProvider.HasCompilableProfile) 

                return null;

        } 

 



        // Otherwise, compile it 



        BuildManager.ReportDirectoryCompilationProgress(virtualDir);



        DateTime utcStart = DateTime.UtcNow; 



        CodeDirectoryCompiler cdc = new CodeDirectoryCompiler(virtualDir, 

            dirType, excludedSubdirectories); 



        string outputAssemblyName = null; 



        if (resultAssembly != null) {

            // If resultAssembly is not null, we are in the case where we just need to build

            // the localized resx file in a resources dir (local or global) 

            Debug.Assert(supportLocalization);

            outputAssemblyName = resultAssembly.GetName().Name; 

            cdc._onlyBuildLocalizedResources = true; 

        }

        else { 

            outputAssemblyName = BuildManager.GenerateRandomAssemblyName(assemblyName);

        }



        BuildProvidersCompiler bpc = 

            new BuildProvidersCompiler(virtualDir, supportLocalization, outputAssemblyName);

 

        cdc._bpc = bpc; 



        // Find all the build provider we want to compile from the code directory 

        cdc.FindBuildProviders();



        // Give them to the BuildProvidersCompiler

        bpc.SetBuildProviders(cdc._buildProviders); 



        // Compile them into an assembly 

        CompilerResults results = bpc.PerformBuild(); 



        // Did we just compile something? 

        if (results != null) {

            Debug.Assert(result == null);

            Debug.Assert(resultAssembly == null);

 

            // If there is already a loaded module with the same path, try to wait for it to be unloaded.

            // Otherwise, we would end up loading this old assembly instead of the new one (VSWhidbey 554697) 

            DateTime waitLimit = DateTime.UtcNow.AddMilliseconds(3000); 

            for (;;) {

                IntPtr hModule = UnsafeNativeMethods.GetModuleHandle(results.PathToAssembly); 

                if (hModule == IntPtr.Zero)

                    break;



                Debug.Trace("CodeDirectoryCompiler", results.PathToAssembly + " is already loaded. Waiting a bit"); 



                System.Threading.Thread.Sleep(250); 

 

                // Stop trying if the timeout was reached

                if (DateTime.UtcNow > waitLimit) { 

                    Debug.Trace("CodeDirectoryCompiler", "Timeout waiting for old assembly to unload: " + results.PathToAssembly);

                    throw new HttpException(SR.GetString(SR.Assembly_already_loaded, results.PathToAssembly));

                }

            } 



            resultAssembly = results.CompiledAssembly; 

        } 



        // It is possible that there was nothing to compile (and we're not in the 

        // satellite resources case)

        if (resultAssembly == null)

            return null;

 

        // For the main code directory, use a special BuildResult that takes care of

        // calling AppInitialize if it finds one 

        if (dirType == CodeDirectoryType.MainCode) { 

            // Keep track of it so we can later call the AppInitialize method

            _mainCodeBuildResult = new BuildResultMainCodeAssembly(resultAssembly); 



            result = _mainCodeBuildResult;

        }

        else if (supportLocalization) { 

            result = new BuildResultResourceAssembly(resultAssembly);

        } 

        else { 

            result = new BuildResultCompiledAssembly(resultAssembly);

        } 



        result.VirtualPath = virtualDir;



        // If compilations are optimized, we need to include the right dependencies, since we can no longer 

        // rely on everything getting wiped out when something in App_Code changes.

        // But don't do this for local resources, since they have their own special way of 

        // dealing with dependencies (in BuildResultResourceAssembly.ComputeSourceDependenciesHashCode). 

        // It's crucial *not* to do it as it triggers a tricky infinite recursion due to the fact

        // that GetBuildResultFromCacheInternal calls EnsureFirstTimeDirectoryInitForDependencies if 

        // there is at least one dependency

        if (BuildManager.OptimizeCompilations && dirType != CodeDirectoryType.LocalResources) {

            result.AddVirtualPathDependencies(new SingleObjectCollection(virtualDir.AppRelativeVirtualPathString));

        } 



        // Top level assembly should not be cached to memory.  But LocalResources are *not* 

        // top level files, and do benefit from memory caching 

        if (dirType != CodeDirectoryType.LocalResources)

            result.CacheToMemory = false; 



        // Cache it for next time

        BuildManager.CacheBuildResult(cacheKey, result, utcStart);

 

        return resultAssembly;

    } 

 

    // Call the AppInitialize method in the Code assembly if there is one

    internal static void CallAppInitializeMethod() { 

        if (_mainCodeBuildResult != null)

            _mainCodeBuildResult.CallAppInitializeMethod();

    }

 

    internal const string sourcesDirectoryPrefix = "Sources_";

 

    internal static void GetCodeDirectoryInformation( 

        VirtualPath virtualDir, CodeDirectoryType dirType, StringSet excludedSubdirectories, int index,

        out Type codeDomProviderType, out CompilerParameters compilerParameters, 

        out string generatedFilesDir) {



        // Compute the full path to the directory we'll use to generate all

        // the code files 

        generatedFilesDir = HttpRuntime.CodegenDirInternal + "\\" +

            sourcesDirectoryPrefix + virtualDir.FileName; 

 

        bool supportLocalization = IsResourceCodeDirectoryType(dirType);

 

        // the index is used to retrieve the correct referenced assemblies

        BuildProvidersCompiler bpc = new BuildProvidersCompiler(virtualDir, supportLocalization,

            generatedFilesDir, index);

 

        CodeDirectoryCompiler cdc = new CodeDirectoryCompiler(virtualDir,

            dirType, excludedSubdirectories); 

        cdc._bpc = bpc; 



        // Find all the build provider we want to compile from the code directory 

        cdc.FindBuildProviders();



        // Give them to the BuildProvidersCompiler

        bpc.SetBuildProviders(cdc._buildProviders); 



        // Generate all the sources into the directory generatedFilesDir 

        bpc.GenerateSources(out codeDomProviderType, out compilerParameters); 

    }

 

    private CodeDirectoryCompiler(VirtualPath virtualDir, CodeDirectoryType dirType,

        StringSet excludedSubdirectories) {



        _virtualDir = virtualDir; 

        _dirType = dirType;

        _excludedSubdirectories = excludedSubdirectories; 

    } 



    private void FindBuildProviders() { 



        // If we need to build the profile, add its build provider

        if (_dirType == CodeDirectoryType.MainCode && ProfileBuildProvider.HasCompilableProfile) {

            _buildProviders.Add(ProfileBuildProvider.Create()); 



        } 

 

        VirtualDirectory vdir = HostingEnvironment.VirtualPathProvider.GetDirectory(_virtualDir);

        ProcessDirectoryRecursive(vdir, true /*topLevel*/); 

    }



    private void AddFolderLevelBuildProviders(VirtualDirectory vdir, FolderLevelBuildProviderAppliesTo appliesTo) {

        BuildManager.AddFolderLevelBuildProviders(_buildProviders, vdir.VirtualPathObject, 

            appliesTo, _bpc.CompConfig, _bpc.ReferencedAssemblies);

    } 

 

    private void ProcessDirectoryRecursive(VirtualDirectory vdir, bool topLevel) {

 

        // If it's a WebReferences directory, handle it using a single WebReferencesBuildProvider

        // instead of creating a different BuildProvider for each file.

        if (_dirType == CodeDirectoryType.WebReferences) {

            // Create a build provider for the current directory 

            BuildProvider buildProvider = new WebReferencesBuildProvider(vdir);

            buildProvider.SetVirtualPath(vdir.VirtualPathObject); 

            _buildProviders.Add(buildProvider); 



            AddFolderLevelBuildProviders(vdir, FolderLevelBuildProviderAppliesTo.WebReferences); 

        }

        else if (_dirType == CodeDirectoryType.AppResources) {

            AddFolderLevelBuildProviders(vdir, FolderLevelBuildProviderAppliesTo.GlobalResources);

        } 

        else if (_dirType == CodeDirectoryType.LocalResources) {

            AddFolderLevelBuildProviders(vdir, FolderLevelBuildProviderAppliesTo.LocalResources); 

        } 

        else if (_dirType == CodeDirectoryType.MainCode || _dirType == CodeDirectoryType.SubCode) {

            AddFolderLevelBuildProviders(vdir, FolderLevelBuildProviderAppliesTo.Code); 

        }



        // Go through all the files in the directory

        foreach (VirtualFileBase child in vdir.Children) { 



            if (child.IsDirectory) { 

 

                // If we are at the top level of this code directory, and the current

                // subdirectory is in the exclude list, skip it 

                if (topLevel && _excludedSubdirectories != null &&

                    _excludedSubdirectories.Contains(child.Name)) {

                    continue;

                } 



                // Exclude the special FrontPage directory (VSWhidbey 116727) 

                if (child.Name == "_vti_cnf") 

                    continue;

 

                ProcessDirectoryRecursive(child as VirtualDirectory, false /*topLevel*/);

                continue;

            }

 

            // Don't look at individual files for WebReferences directories

            if (_dirType == CodeDirectoryType.WebReferences) 

                continue; 



            // Skip neutral files if _onlyBuildLocalizedResources is true 

            if (IsResourceCodeDirectoryType(_dirType)) {

                if (_onlyBuildLocalizedResources && System.Web.UI.Util.GetCultureName(child.VirtualPath) == null) {

                    continue;

                } 

            }

 

            BuildProvider buildProvider = BuildManager.CreateBuildProvider(child.VirtualPathObject, 

                (IsResourceCodeDirectoryType(_dirType)) ?

                    BuildProviderAppliesTo.Resources : BuildProviderAppliesTo.Code, 

                _bpc.CompConfig,

                _bpc.ReferencedAssemblies, false /*failIfUnknown*/);



            // Non-supported file type 

            if (buildProvider == null)

                continue; 

 

            // For Page resources, don't generate a strongly typed class

            if (_dirType == CodeDirectoryType.LocalResources && buildProvider is BaseResourcesBuildProvider) { 

                ((BaseResourcesBuildProvider)buildProvider).DontGenerateStronglyTypedClass();

            }



            _buildProviders.Add(buildProvider); 

        }

    } 

} 



} 



// File provided for Reference Use Only by Microsoft Corporation (c) 2007.

抄吧。

 

 

参考:https://msdn.microsoft.com/zh-cn/library/vstudio/system.web.compilation.assemblybuilder(v=vs.90).aspx

 

 

另 : http://blogs.msdn.com/b/digitalnetbizz/archive/2004/01/31/create-assembly-in-memory-and-run-it.aspx

using System;

using Specialized = System.Collections.Specialized;

using Reflection = System.Reflection;

using CSharp = Microsoft.CSharp;

using CodeDom = System.CodeDom.Compiler;



public sealed class TestCompile

{



static string ScriptCodeToCompileInMem = "public class Script {public void ScriptExecute(){System.Console.WriteLine(123);} }";

public static void Main()

{

  TestCompile tc = new TestCompile();

  tc.Execute(TestCompile.ScriptCodeToCompileInMem);

}



public void Execute(string scriptCode)

{

  string [] source = new string[1];

  source[0] = scriptCode;

  CSharp.CSharpCodeProvider cscp = new CSharp.CSharpCodeProvider();

  this.Compile(cscp, source[0]);

}





private void Compile(CodeDom.CodeDomProvider provider, string source)

{

  CodeDom.CompilerParameters param = new CodeDom.CompilerParameters();

  param.GenerateExecutable = false;

  param.IncludeDebugInformation = false;

  param.GenerateInMemory = true;

  CodeDom.ICodeCompiler cc = provider.CreateCompiler();

  CodeDom.CompilerResults cr = cc.CompileAssemblyFromSource(param, source);

  Specialized.StringCollection output = cr.Output;

  if(cr.Errors.Count !=0)

  {

    System.Console.WriteLine("Error invoking scripts.");

    CodeDom.CompilerErrorCollection es = cr.Errors;

    foreach(CodeDom.CompilerError s in es)

      System.Console.WriteLine(s.ErrorText);

  }

  else

  {

    object o = cr.CompiledAssembly.CreateInstance("Script");

    System.Type type = o.GetType();

    type.InvokeMember ("ScriptExecute",

            Reflection.BindingFlags.InvokeMethod |

            Reflection.BindingFlags.Default, null, o, null);

  }

}

}

你可能感兴趣的:(动态编译)