ClientBuildManager.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ FX-1434 / FX-1434 / 1.0 / untmp / whidbey / REDBITS / ndp / fx / src / xsp / System / Web / Compilation / ClientBuildManager.cs / 4 / ClientBuildManager.cs

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

/************************************************************************************************************/ 
 

namespace System.Web.Compilation { 

using System;
using System.Collections;
using System.Collections.Specialized; 
using System.Configuration;
using System.Diagnostics; 
using System.IO; 
using System.Threading;
using System.Reflection; 
using System.Runtime.InteropServices;
using System.Security.Permissions;
using System.Globalization;
using System.CodeDom; 
using System.CodeDom.Compiler;
using System.Web; 
using System.Web.Configuration; 
using System.Web.Util;
using System.Web.UI; 
using System.Web.Hosting;
using System.Xml;
using Debug=System.Web.Util.Debug;
 

// Flags that drive the behavior of precompilation 
[Flags] 
public enum PrecompilationFlags {
 
    Default = 0x00000000,

    // determines whether the deployed app will be updatable
    Updatable = 0x00000001, 

    // determines whether the target directory can be overwritten 
    OverwriteTarget = 0x00000002, 

    // determines whether the compiler will emit debug information 
    ForceDebug = 0x00000004,

    // determines whether the application is built clean
    Clean = 0x00000008, 

    // determines whether the /define:CodeAnalysis flag needs to be added 
    // as compilation symbol 
    CodeAnalysis = 0x00000010,
 
    // determines whether to generate APTCA attribute.
    AllowPartiallyTrustedCallers = 0x00000020,

    // determines whether to delaySign the generate assemblies. 
    DelaySign = 0x00000040,
 
    // determines whether to use fixed assembly names 
    FixedNames = 0x00000080,
} 

[Serializable]
[AspNetHostingPermission(SecurityAction.LinkDemand, Level=AspNetHostingPermissionLevel.Minimal)]
[AspNetHostingPermission(SecurityAction.InheritanceDemand, Level=AspNetHostingPermissionLevel.Minimal)] 
public class ClientBuildManagerParameter {
    private string _strongNameKeyFile; 
    private string _strongNameKeyContainer; 
    private PrecompilationFlags _precompilationFlags = PrecompilationFlags.Default;
 
    // Determines the behavior of the precompilation
    public PrecompilationFlags PrecompilationFlags {
        get { return _precompilationFlags; }
        set { _precompilationFlags = value; } 
    }
 
    public string StrongNameKeyFile { 
        get { return _strongNameKeyFile; }
        set { _strongNameKeyFile = value; } 
    }

    public string StrongNameKeyContainer {
        get { return _strongNameKeyContainer; } 
        set { _strongNameKeyContainer = value; }
    } 
} 

// 
// This class provide access to the BuildManager outside of an IIS environment
// Instances of this class are created in the caller's App Domain.
//
// It creates and configures the new App Domain for handling BuildManager calls 
// using System.Web.Hosting.ApplicationHost.CreateApplicationHost()
// 
 
[PermissionSet(SecurityAction.LinkDemand, Unrestricted = true)]
[PermissionSet(SecurityAction.InheritanceDemand, Unrestricted = true)] 
public sealed class ClientBuildManager : MarshalByRefObject, IDisposable {

    private VirtualPath _virtualPath;
    private string _physicalPath; 
    private string _installPath;
    private string _appId; 
    private string _codeGenDir; 

    private HostingEnvironmentParameters _hostingParameters; 

    private WaitCallback _onAppDomainUnloadedCallback;
    private WaitCallback _onAppDomainShutdown;
    private ApplicationShutdownReason _reason; 

    private BuildManagerHost _host; 
    private Exception _hostCreationException; 
    private bool _hostCreationPending;
 
    public event BuildManagerHostUnloadEventHandler AppDomainUnloaded;

    public event EventHandler AppDomainStarted;
 
    public event BuildManagerHostUnloadEventHandler AppDomainShutdown;
    // internal lock used for host creation. 
    private object _lock = new object(); 

    // Whether to wait for the call back from the previous host unloading before creating a new one 
    private bool _waitForCallBack;

    /*
     * Creates an instance of the ClientBuildManager. 
     * appPhysicalSourceDir points to the physical root of the application (e.g "c:\myapp")
     * virtualPath is the virtual path to the app root. It can be anything (e.g. "/dummy"), 
     *      but ideally it should match the path later given to Cassini, in order for 
     *      compilation that happens here to be reused there.
     */ 

    public ClientBuildManager(string appVirtualDir, string appPhysicalSourceDir) :
        this(appVirtualDir, appPhysicalSourceDir,
        null /*appPhysicalTargetDir*/, null /*ClientBuildManagerParameter*/) { 
    }
 
    /* 
     * Creates an instance of the PrecompilationManager.
     * appPhysicalSourceDir points to the physical root of the application (e.g "c:\myapp") 
     * appVirtualDir is the virtual path to the app root. It can be anything (e.g. "/dummy"),
     *      but ideally it should match the path later given to Cassini, in order for
     *      compilation that happens here to be reused there.
     * appPhysicalTargetDir is the directory where the precompiled site is placed 
     */
    public ClientBuildManager(string appVirtualDir, string appPhysicalSourceDir, 
        string appPhysicalTargetDir) : this(appVirtualDir, appPhysicalSourceDir, 
            appPhysicalTargetDir, null /*ClientBuildManagerParameter*/) {
    } 

    /*
     * Creates an instance of the PrecompilationManager.
     * appPhysicalSourceDir points to the physical root of the application (e.g "c:\myapp") 
     * appVirtualDir is the virtual path to the app root. It can be anything (e.g. "/dummy"),
     *      but ideally it should match the path later given to Cassini, in order for 
     *      compilation that happens here to be reused there. 
     * appPhysicalTargetDir is the directory where the precompiled site is placed
     * flags determines the behavior of the precompilation 
     */
    public ClientBuildManager(string appVirtualDir, string appPhysicalSourceDir,
        string appPhysicalTargetDir, ClientBuildManagerParameter parameter) {
 
        if (parameter == null) {
            parameter = new ClientBuildManagerParameter(); 
        } 

        // Always build clean in precompilation for deployment mode, 
        // since building incrementally raises all kind of issues (VSWhidbey 382954).
        if (!String.IsNullOrEmpty(appPhysicalTargetDir)) {
            parameter.PrecompilationFlags |= PrecompilationFlags.Clean;
        } 

        _hostingParameters = new HostingEnvironmentParameters(); 
        _hostingParameters.HostingFlags = HostingEnvironmentFlags.DontCallAppInitialize | 
                                          HostingEnvironmentFlags.ClientBuildManager;
        _hostingParameters.ClientBuildManagerParameter = parameter; 
        _hostingParameters.PrecompilationTargetPhysicalDirectory = appPhysicalTargetDir;

        // Make sure the app virtual dir starts with /
        if (appVirtualDir[0] != '/') 
            appVirtualDir = "/" + appVirtualDir;
 
        Initialize(VirtualPath.CreateNonRelative(appVirtualDir), appPhysicalSourceDir); 
    }
 
    /*
     * returns the codegendir used by runtime appdomain
     */
    public string CodeGenDir { 
        get {
            if (_codeGenDir == null) { 
                EnsureHostCreated(); 
                _codeGenDir = _host.CodeGenDir;
            } 

            return _codeGenDir;
        }
    } 

    /* 
     * Indicates whether the host is created. 
     */
 
    public bool IsHostCreated {
        get {
            return _host != null;
        } 
    }
 
    /* 
     * Create an object in the runtime appdomain
     */ 

    public IRegisteredObject CreateObject(Type type, bool failIfExists) {
        if (type == null) {
            throw new ArgumentNullException("type"); 
        }
 
        EnsureHostCreated(); 
        Debug.Assert(_appId != null);
 
        _host.RegisterAssembly(type.Assembly.FullName, type.Assembly.Location);

        ApplicationManager appManager = ApplicationManager.GetApplicationManager();
        return appManager.CreateObjectInternal(_appId, type, _host.ApplicationHost, failIfExists); 
    }
 
    /* 
     * Return the list of directories that would cause appdomain shutdown.
     */ 
    public string[] GetAppDomainShutdownDirectories() {
        Debug.Trace("CBM", "GetAppDomainShutdownDirectories");

        return FileChangesMonitor.s_dirsToMonitor; 
    }
 
    /* 
     * Makes sure that all the top level files are compiled (code, global.asax, ...)
     */ 

    public void CompileApplicationDependencies() {
        Debug.Trace("CBM", "CompileApplicationDependencies");
 
        EnsureHostCreated();
 
        _host.CompileApplicationDependencies(); 
    }
 

    public IDictionary GetBrowserDefinitions() {
        Debug.Trace("CBM", "GetBrowserDefinitions");
 
        EnsureHostCreated();
 
        return _host.GetBrowserDefinitions(); 
    }
 
    /*
     * Returns the physical path of the generated file corresponding to the virtual directory.
     * Note the virtualPath needs to use this format:
     * "/[appname]/App_WebReferences/{[subDir]/}" 
     */
    public string GetGeneratedSourceFile(string virtualPath) { 
        Debug.Trace("CBM", "GetGeneratedSourceFile " + virtualPath); 

        if (virtualPath == null) { 
            throw new ArgumentNullException("virtualPath");
        }

        EnsureHostCreated(); 

        return _host.GetGeneratedSourceFile(VirtualPath.CreateTrailingSlash(virtualPath)); 
    } 

    /* 
    * Returns the virtual path of the corresponding generated file.
    * Note the filepath needs to be a full path.
    */
    public string GetGeneratedFileVirtualPath(string filePath) { 
        Debug.Trace("CBM", "GetGeneratedFileVirtualPath " + filePath);
 
        if (filePath == null) { 
            throw new ArgumentNullException("filePath");
        } 

        EnsureHostCreated();

        return _host.GetGeneratedFileVirtualPath(filePath); 
    }
    /* 
     * Returns an array of the virtual paths to all the code directories in the app thru the hosted appdomain 
     */
 
    public string[] GetVirtualCodeDirectories() {
        Debug.Trace("CBM", "GetHostedVirtualCodeDirectories");

        EnsureHostCreated(); 

        return _host.GetVirtualCodeDirectories(); 
    } 

    /* 
     * Returns an array of the assemblies defined in the bin and assembly reference config section
     */

    public String[] GetTopLevelAssemblyReferences(string virtualPath) { 
        Debug.Trace("CBM", "GetHostedVirtualCodeDirectories");
 
        if (virtualPath == null) { 
            throw new ArgumentNullException("virtualPath");
        } 

        EnsureHostCreated();

        return _host.GetTopLevelAssemblyReferences(VirtualPath.Create(virtualPath)); 
    }
 
    /* 
     * Returns the compiler type and parameters that need to be used to build
     * a given code directory.  Also, returns the directory containing all the code 
     * files generated from non-code files in the code directory (e.g. wsdl files)
     */

    public void GetCodeDirectoryInformation(string virtualCodeDir, 
        out Type codeDomProviderType, out CompilerParameters compilerParameters,
        out string generatedFilesDir) { 
        Debug.Trace("CBM", "GetCodeDirectoryInformation " + virtualCodeDir); 

        if (virtualCodeDir == null) { 
            throw new ArgumentNullException("virtualCodeDir");
        }

        EnsureHostCreated(); 

        _host.GetCodeDirectoryInformation(VirtualPath.CreateTrailingSlash(virtualCodeDir), 
            out codeDomProviderType, out compilerParameters, out generatedFilesDir); 

        Debug.Trace("CBM", "GetCodeDirectoryInformation " + virtualCodeDir + " end"); 
    }

    /*
     * Returns the compiler type and parameters that need to be used to build 
     * a given file.
     */ 
 
    public void GetCompilerParameters(string virtualPath,
        out Type codeDomProviderType, out CompilerParameters compilerParameters) { 
        Debug.Trace("CBM", "GetCompilerParameters " + virtualPath);

        if (virtualPath == null) {
            throw new ArgumentNullException("virtualPath"); 
        }
 
        EnsureHostCreated(); 

        _host.GetCompilerParams(VirtualPath.Create(virtualPath), out codeDomProviderType, out compilerParameters); 
    }

    /*
     * Returns the codedom tree and the compiler type/param for a given file. 
     */
 
    public CodeCompileUnit GenerateCodeCompileUnit( 
        string virtualPath, out Type codeDomProviderType,
        out CompilerParameters compilerParameters, out IDictionary linePragmasTable) { 
        Debug.Trace("CBM", "GenerateCodeCompileUnit " + virtualPath);

        return GenerateCodeCompileUnit(virtualPath, null,
            out codeDomProviderType, out compilerParameters, out linePragmasTable); 
    }
 
 
    public CodeCompileUnit GenerateCodeCompileUnit(
        string virtualPath, String virtualFileString, out Type codeDomProviderType, 
        out CompilerParameters compilerParameters, out IDictionary linePragmasTable) {
        Debug.Trace("CBM", "GenerateCodeCompileUnit " + virtualPath);

        if (virtualPath == null) { 
            throw new ArgumentNullException("virtualPath");
        } 
 
        EnsureHostCreated();
 
        return _host.GenerateCodeCompileUnit(VirtualPath.Create(virtualPath), virtualFileString,
            out codeDomProviderType, out compilerParameters, out linePragmasTable);
    }
 
    public string GenerateCode(
        string virtualPath, String virtualFileString, out IDictionary linePragmasTable) { 
        Debug.Trace("CBM", "GenerateCode " + virtualPath); 

        if (virtualPath == null) { 
            throw new ArgumentNullException("virtualPath");
        }

        EnsureHostCreated(); 

        return _host.GenerateCode(VirtualPath.Create(virtualPath), virtualFileString, out linePragmasTable); 
    } 

    /* 
     * Returns the compiled type for an input file
     */

    public Type GetCompiledType(string virtualPath) { 
        Debug.Trace("CBM", "GetCompiledType " + virtualPath);
 
        if (virtualPath == null) { 
            throw new ArgumentNullException("virtualPath");
        } 

        EnsureHostCreated();

        string[] typeAndAsemblyName = _host.GetCompiledTypeAndAssemblyName(VirtualPath.Create(virtualPath), null); 
        if (typeAndAsemblyName == null)
            return null; 
 
        Assembly a = Assembly.LoadFrom(typeAndAsemblyName[1]);
        Type t = a.GetType(typeAndAsemblyName[0]); 
        return t;
    }

    /* 
     * Compile a file
     */ 
    public void CompileFile(string virtualPath) { 
        CompileFile(virtualPath, null);
    } 

    public void CompileFile(string virtualPath, ClientBuildManagerCallback callback) {
        Debug.Trace("CBM", "CompileFile " + virtualPath);
 
        if (virtualPath == null) {
            throw new ArgumentNullException("virtualPath"); 
        } 

        EnsureHostCreated(); 

        _host.GetCompiledTypeAndAssemblyName(VirtualPath.Create(virtualPath), callback);
    }
 
    /*
     * Indicates whether an assembly is a code assembly. 
     */ 
    public bool IsCodeAssembly(string assemblyName) {
        Debug.Trace("CBM", "IsCodeAssembly " + assemblyName); 

        if (assemblyName == null) {
            throw new ArgumentNullException("assemblyName");
        } 

        // 
 
        EnsureHostCreated();
        bool result = _host.IsCodeAssembly(assemblyName); 

        Debug.Trace("CBM", "IsCodeAssembly " + result.ToString());
        return result;
    } 

 
    public bool Unload() { 
        Debug.Trace("CBM", "Unload");
 
        BuildManagerHost host = _host;
        if (host != null) {
            _host = null;
            return host.UnloadAppDomain(); 
        }
 
        return false; 
    }
 
    /*
     * Precompile an application
     */
    public void PrecompileApplication() { 
        PrecompileApplication(null);
    } 
 
    /*
     * Precompile an application with callback support 
     */
    public void PrecompileApplication(ClientBuildManagerCallback callback) {
        PrecompileApplication(callback, false);
    } 

    public void PrecompileApplication(ClientBuildManagerCallback callback, bool forceCleanBuild) { 
        Debug.Trace("CBM", "PrecompileApplication"); 

        PrecompilationFlags savedFlags = _hostingParameters.ClientBuildManagerParameter.PrecompilationFlags; 

        if (forceCleanBuild) {

            // If there was a previous host, it will be unloaded by CBM and we will wait for the callback. 
            // If there was no previous host, we don't do any waiting.
            // DevDiv 46290 
            _waitForCallBack = _host != null; 

            Debug.Trace("CBM", "Started Unload"); 
            // Unload the existing appdomain so the new one will be created with the clean flag
            Unload();

            _hostingParameters.ClientBuildManagerParameter.PrecompilationFlags = 
                savedFlags | PrecompilationFlags.Clean;
 
            WaitForCallBack(); 
        }
 
        try {
            EnsureHostCreated();

            _host.PrecompileApp(callback); 
        }
        finally { 
            if (forceCleanBuild) { 
                // Revert precompilationFlags
                _hostingParameters.ClientBuildManagerParameter.PrecompilationFlags = savedFlags; 
            }
        }
    }
 
    // _waitForCallBack is set to false in OnAppDomainUnloaded.
    // This method waits until it is set to false before continuing, so that 
    // we do not run into a concurrency issue where _host could be set to null. 
    // DevDiv 46290
    private void WaitForCallBack() { 
        Debug.Trace("CBM", "WaitForCallBack");
        int waited = 0;
        while (_waitForCallBack && waited <= 50) {
            Thread.Sleep(200); 
            waited++;
        } 
        if (_waitForCallBack) { 
            Debug.Trace("CBM", "timeout while waiting for callback");
        } 
        else {
            Debug.Trace("CBM", "callback received before timeout");
        }
    } 

    public override Object InitializeLifetimeService() { 
        return null; // never expire lease 
    }
 
    internal void Initialize(VirtualPath virtualPath, string physicalPath) {
        Debug.Trace("CBM", "Initialize");

        _virtualPath = virtualPath; 

        _physicalPath = FileUtil.FixUpPhysicalDirectory(physicalPath); 
 
        _onAppDomainUnloadedCallback = new WaitCallback(OnAppDomainUnloadedCallback);
        _onAppDomainShutdown = new WaitCallback(OnAppDomainShutdownCallback); 

        _installPath = RuntimeEnvironment.GetRuntimeDirectory();

        // Do not create host during intialization. It will be done on demand. 
        //CreateHost();
    } 
 
    private void EnsureHostCreated() {
 
        if (_host == null) {
            lock (_lock) {
                // Create the host if necessary
                if (_host == null) { 
                    CreateHost();
                    Debug.Trace("CBM", "EnsureHostCreated: after CreateHost()"); 
                } 
            }
        } 

        // If an exception happened during host creation, rethrow it
        if (_hostCreationException != null) {
            Debug.Trace("CBM", "EnsureHostCreated: failed. " + _hostCreationException); 

            // We need to wrap it in a new exception, otherwise we lose the original stack. 
            throw new HttpException(_hostCreationException.Message, 
                _hostCreationException);
        } 
    }

    private void CreateHost() {
        Debug.Trace("CBM", "CreateHost"); 
        Debug.Assert(_host == null);
 
        Debug.Assert(!_hostCreationPending, "CreateHost: creation already pending"); 

        _hostCreationPending = true; 

        // Use a local to avoid having a partially created _host
        BuildManagerHost host = null;
 
        try {
            string appId; 
 
            ApplicationManager appManager = ApplicationManager.GetApplicationManager();
 
            host = (BuildManagerHost) appManager.CreateObjectWithDefaultAppHostAndAppId(
                _physicalPath, _virtualPath,
                typeof(BuildManagerHost), false /*failIfExists*/,
                _hostingParameters, out appId); 

            // host appdomain cannot be unloaded during creation. 
            host.AddPendingCall(); 

            host.Configure(this); 

            _host = host;
            _appId = appId;
 
            _hostCreationException = _host.InitializationException;
        } 
        catch (Exception e) { 
            // If an exception happens, keep track of it
            _hostCreationException = e; 

            // Even though the host initialization failed, keep track of it so subsequent
            // request will see the error
            _host = host; 
        }
        finally { 
            _hostCreationPending = false; 

            if (host != null) { 
                // Notify the client that the host is ready
                if (AppDomainStarted != null) {
                    AppDomainStarted(this, EventArgs.Empty);
                } 

                // The host can be unloaded safely now. 
                host.RemovePendingCall(); 
            }
        } 

        Debug.Trace("CBM", "CreateHost LEAVE");
    }
 
    // Called by BuildManagerHost when the ASP appdomain is unloaded
    internal void OnAppDomainUnloaded(ApplicationShutdownReason reason) { 
        Debug.Trace("CBM", "OnAppDomainUnloaded " + reason.ToString()); 

        // Don't try to use this host anymore 
        _host = null;
        _hostCreationException = null;
        _reason = reason;
 
        _waitForCallBack = false;
 
        // Don't do anything that can be slow here.  Instead queue in a worker thread 
        ThreadPool.QueueUserWorkItem(_onAppDomainUnloadedCallback);
    } 

    private void OnAppDomainUnloadedCallback(Object unused) {
        Debug.Trace("CBM", "OnAppDomainUnloadedCallback");
 
        // Notify the client that the appdomain is unloaded
        if (AppDomainUnloaded != null) { 
            AppDomainUnloaded(this, new BuildManagerHostUnloadEventArgs(_reason)); 
        }
    } 

    private void OnAppDomainShutdownCallback(Object o) {
        if (AppDomainShutdown != null) {
            AppDomainShutdown(this, new BuildManagerHostUnloadEventArgs((ApplicationShutdownReason)o)); 
        }
    } 
 
    internal void OnAppDomainShutdown(ApplicationShutdownReason reason) {
        // Don't do anything that can be slow here. Instead queue in a worker thread 
        ThreadPool.QueueUserWorkItem(_onAppDomainShutdown, reason);
    }

    #region IDisposable 
    //Dispose the runtime appdomain properly when CBM is disposed
    void IDisposable.Dispose() { 
        Unload(); 
    }
    #endregion 
}


[PermissionSet(SecurityAction.LinkDemand, Unrestricted = true)] 
[PermissionSet(SecurityAction.InheritanceDemand, Unrestricted = true)]
public class BuildManagerHostUnloadEventArgs : EventArgs { 
    ApplicationShutdownReason _reason; 

    public BuildManagerHostUnloadEventArgs(ApplicationShutdownReason reason) { 
        _reason = reason;
    }

    // Get the reason for the hosted appdomain shutdown 

    public ApplicationShutdownReason Reason { get { return _reason; } } 
} 

 
public delegate void BuildManagerHostUnloadEventHandler(object sender, BuildManagerHostUnloadEventArgs e);

/*
 * Type of the entries in the table returned by GenerateCodeCompileUnit 
 */
 
[Serializable] 
[AspNetHostingPermission(SecurityAction.LinkDemand, Level=AspNetHostingPermissionLevel.Minimal)]
public sealed class LinePragmaCodeInfo { 

    public LinePragmaCodeInfo() {
    }
 
    public LinePragmaCodeInfo(int startLine, int startColumn, int startGeneratedColumn, int codeLength, bool isCodeNugget) {
        this._startLine = startLine; 
        this._startColumn = startColumn; 
        this._startGeneratedColumn = startGeneratedColumn;
        this._codeLength = codeLength; 
        this._isCodeNugget = isCodeNugget;
    }

    // Starting line in ASPX file 
    internal int _startLine;
 
    public int StartLine { get { return _startLine; } } 

    // Starting column in the ASPX file 
    internal int _startColumn;

    public int StartColumn { get { return _startColumn; } }
 
    // Starting column in the generated source file (assuming no indentations are used)
    internal int _startGeneratedColumn; 
 
    public int StartGeneratedColumn { get { return _startGeneratedColumn; } }
 
    // Length of the code snippet
    internal int _codeLength;

    public int CodeLength { get { return _codeLength; } } 

    // Whether the script block is a nugget. 
    internal bool _isCodeNugget; 

    public bool IsCodeNugget { get { return _isCodeNugget; } } 
}

}
                        

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