Code:
/ Net / Net / 3.5.50727.3053 / DEVDIV / depot / DevDiv / releases / whidbey / netfxsp / ndp / fx / src / xsp / System / Web / Compilation / ClientBuildManager.cs / 6 / 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.Runtime.Remoting;
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");
}
try {
EnsureHostCreated();
_host.GetCompiledTypeAndAssemblyName(VirtualPath.Create(virtualPath), callback);
}
finally {
// DevDiv 180798. We are returning null in ClientBuildManagerCallback.InitializeLifetimeService,
// so we need to manually disconnect the instance so that it will be released.
if (callback != null) {
RemotingServices.Disconnect(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;
}
// DevDiv 180798. We are returning null in ClientBuildManagerCallback.InitializeLifetimeService,
// so we need to manually disconnect the instance so that it will be released.
if (callback != null) {
RemotingServices.Disconnect(callback);
}
}
}
// _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; } }
}
}
// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
//------------------------------------------------------------------------------
//
// 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.Runtime.Remoting;
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");
}
try {
EnsureHostCreated();
_host.GetCompiledTypeAndAssemblyName(VirtualPath.Create(virtualPath), callback);
}
finally {
// DevDiv 180798. We are returning null in ClientBuildManagerCallback.InitializeLifetimeService,
// so we need to manually disconnect the instance so that it will be released.
if (callback != null) {
RemotingServices.Disconnect(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;
}
// DevDiv 180798. We are returning null in ClientBuildManagerCallback.InitializeLifetimeService,
// so we need to manually disconnect the instance so that it will be released.
if (callback != null) {
RemotingServices.Disconnect(callback);
}
}
}
// _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; } }
}
}
// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
Link Menu

This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- NetworkInterface.cs
- ExpressionLexer.cs
- FormsAuthenticationCredentials.cs
- Graphics.cs
- ScrollBar.cs
- EndOfStreamException.cs
- XmlSchemaSimpleTypeList.cs
- PropertyEmitter.cs
- QueuedDeliveryRequirementsMode.cs
- COMException.cs
- OdbcErrorCollection.cs
- ProcessingInstructionAction.cs
- SctClaimDictionary.cs
- XsltInput.cs
- InternalPermissions.cs
- UpdatePanel.cs
- ZipIOFileItemStream.cs
- FormsAuthentication.cs
- SystemException.cs
- SqlInternalConnectionSmi.cs
- AssociationEndMember.cs
- SharedTcpTransportManager.cs
- DrawingCollection.cs
- HwndTarget.cs
- ExtendLockAsyncResult.cs
- SearchForVirtualItemEventArgs.cs
- RichTextBox.cs
- FontEditor.cs
- TextEditorTables.cs
- TableLayoutCellPaintEventArgs.cs
- ReaderWriterLock.cs
- StringFunctions.cs
- XmlAttributeProperties.cs
- JsonByteArrayDataContract.cs
- LightweightCodeGenerator.cs
- TraceInternal.cs
- DataGridCommandEventArgs.cs
- DbProviderFactoriesConfigurationHandler.cs
- SamlDoNotCacheCondition.cs
- Int32Storage.cs
- IisTraceListener.cs
- ConstraintEnumerator.cs
- RowType.cs
- ClaimTypeElement.cs
- TagPrefixCollection.cs
- XmlSequenceWriter.cs
- GacUtil.cs
- ResourceContainer.cs
- InitializingNewItemEventArgs.cs
- SystemException.cs
- WebPartMinimizeVerb.cs
- AsyncCompletedEventArgs.cs
- DbgUtil.cs
- ListViewGroupItemCollection.cs
- ExtractorMetadata.cs
- ObjectResult.cs
- RegistryPermission.cs
- ImageSource.cs
- GenericXmlSecurityToken.cs
- SystemIcons.cs
- TypeBuilder.cs
- ListItemCollection.cs
- XmlAggregates.cs
- X509CertificateCollection.cs
- NameNode.cs
- RequestUriProcessor.cs
- ReliabilityContractAttribute.cs
- RequestSecurityToken.cs
- XmlWrappingReader.cs
- SchemaNamespaceManager.cs
- WebControlsSection.cs
- ThicknessAnimationUsingKeyFrames.cs
- FilterException.cs
- DocumentGridContextMenu.cs
- PopOutPanel.cs
- CounterNameConverter.cs
- RepeatButton.cs
- PeerCollaboration.cs
- EllipseGeometry.cs
- AssemblyUtil.cs
- ZipIOCentralDirectoryFileHeader.cs
- DocumentAutomationPeer.cs
- UnsupportedPolicyOptionsException.cs
- ToolboxBitmapAttribute.cs
- FloaterParagraph.cs
- TargetPerspective.cs
- RightsManagementPermission.cs
- CodeAttributeDeclarationCollection.cs
- CreateParams.cs
- SynchronizationScope.cs
- WindowsSlider.cs
- MasterPageCodeDomTreeGenerator.cs
- XmlObjectSerializerReadContextComplex.cs
- StorageMappingItemCollection.cs
- EncodingConverter.cs
- StringArrayConverter.cs
- HatchBrush.cs
- NavigatingCancelEventArgs.cs
- ElementHost.cs
- ZipIOExtraField.cs