CodeDirectoryCompiler.cs source code in C# .NET

Source code for the .NET framework in C#



/ DotNET / DotNET / 8.0 / untmp / whidbey / REDBITS / ndp / fx / src / xsp / System / Web / Compilation / CodeDirectoryCompiler.cs / 2 / CodeDirectoryCompiler.cs

//     Copyright (c) Microsoft Corporation.  All rights reserved.

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 


        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) 
            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 

        // Give them to the BuildProvidersCompiler

        // 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)

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

                // 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;

        // 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)

    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 
        // Give them to the BuildProvidersCompiler

        // 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) {


        VirtualDirectory vdir = HostingEnvironment.VirtualPathProvider.GetDirectory(_virtualDir); 
        ProcessDirectoryRecursive(vdir, true /*topLevel*/); 
    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); 

        // 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)) {

                // Exclude the special FrontPage directory (VSWhidbey 116727) 
                if (child.Name == "_vti_cnf") 
                ProcessDirectoryRecursive(child as VirtualDirectory, false /*topLevel*/);
            // Don't look at individual files for WebReferences directories
            if (_dirType == CodeDirectoryType.WebReferences) 

            // Skip neutral files if _onlyBuildLocalizedResources is true 
            if (IsResourceCodeDirectoryType(_dirType)) {
                if (_onlyBuildLocalizedResources && System.Web.UI.Util.GetCultureName(child.VirtualPath) == null) {
            BuildProvider buildProvider = BuildManager.CreateBuildProvider(child.VirtualPathObject, 
                (IsResourceCodeDirectoryType(_dirType)) ?
                    BuildProviderAppliesTo.Resources : BuildProviderAppliesTo.Code, 
                _bpc.ReferencedAssemblies, false /*failIfUnknown*/);

            // Non-supported file type 
            if (buildProvider == null)
            // For Page resources, don't generate a strongly typed class
            if (_dirType == CodeDirectoryType.LocalResources && buildProvider is BaseResourcesBuildProvider) { 




Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK