1 //------------------------------------------------------------------------------
2 // <copyright file="ClientBuildManager.cs" company="Microsoft">
3 //     Copyright (c) Microsoft Corporation.  All rights reserved.
4 // </copyright>
5 //------------------------------------------------------------------------------
6 
7 /************************************************************************************************************/
8 
9 
10 namespace System.Web.Compilation {
11 
12 using System;
13 using System.CodeDom;
14 using System.CodeDom.Compiler;
15 using System.Collections;
16 using System.Collections.Generic;
17 using System.ComponentModel;
18 using System.Reflection;
19 using System.Runtime.InteropServices;
20 using System.Runtime.Remoting;
21 using System.Security.Permissions;
22 using System.Threading;
23 using System.Web;
24 using System.Web.Hosting;
25 using System.Web.Util;
26 using Debug = System.Web.Util.Debug;
27 
28 
29 // Flags that drive the behavior of precompilation
30 [Flags]
31 public enum PrecompilationFlags {
32 
33     Default = 0x00000000,
34 
35     // determines whether the deployed app will be updatable
36     Updatable = 0x00000001,
37 
38     // determines whether the target directory can be overwritten
39     OverwriteTarget = 0x00000002,
40 
41     // determines whether the compiler will emit debug information
42     ForceDebug = 0x00000004,
43 
44     // determines whether the application is built clean
45     Clean = 0x00000008,
46 
47     // determines whether the /define:CodeAnalysis flag needs to be added
48     // as compilation symbol
49     CodeAnalysis = 0x00000010,
50 
51     // determines whether to generate APTCA attribute.
52     AllowPartiallyTrustedCallers = 0x00000020,
53 
54     // determines whether to delaySign the generate assemblies.
55     DelaySign = 0x00000040,
56 
57     // determines whether to use fixed assembly names
58     FixedNames = 0x00000080,
59 
60     // determines whether to skip BadImageFormatException
61     IgnoreBadImageFormatException = 0x00000100,
62 }
63 
64 [Serializable]
65 public class ClientBuildManagerParameter {
66     private string _strongNameKeyFile;
67     private string _strongNameKeyContainer;
68     private PrecompilationFlags _precompilationFlags = PrecompilationFlags.Default;
69     private List<string> _excludedVirtualPaths;
70 
71     public List<string> ExcludedVirtualPaths {
72         get {
73             if (_excludedVirtualPaths == null) {
74                 _excludedVirtualPaths = new List<string>();
75             }
76             return _excludedVirtualPaths;
77         }
78     }
79 
80     // Determines the behavior of the precompilation
81     public PrecompilationFlags PrecompilationFlags {
82         get { return _precompilationFlags; }
83         set { _precompilationFlags = value; }
84     }
85 
86     public string StrongNameKeyFile {
87         get { return _strongNameKeyFile; }
88         set { _strongNameKeyFile = value; }
89     }
90 
91     public string StrongNameKeyContainer {
92         get { return _strongNameKeyContainer; }
93         set { _strongNameKeyContainer = value; }
94     }
95 }
96 
97 //
98 // This class provide access to the BuildManager outside of an IIS environment
99 // Instances of this class are created in the caller's App Domain.
100 //
101 // It creates and configures the new App Domain for handling BuildManager calls
102 // using System.Web.Hosting.ApplicationHost.CreateApplicationHost()
103 //
104 
105 [PermissionSet(SecurityAction.LinkDemand, Unrestricted = true)]
106 [PermissionSet(SecurityAction.InheritanceDemand, Unrestricted = true)]
107 public sealed class ClientBuildManager : MarshalByRefObject, IDisposable {
108 
109     private VirtualPath _virtualPath;
110     private string _physicalPath;
111     private string _installPath;
112     private string _appId;
113     private IApplicationHost _appHost;
114     private string _codeGenDir;
115 
116     private HostingEnvironmentParameters _hostingParameters;
117     private ClientBuildManagerTypeDescriptionProviderBridge _cbmTdpBridge;
118 
119     private WaitCallback _onAppDomainUnloadedCallback;
120     private WaitCallback _onAppDomainShutdown;
121     private ApplicationShutdownReason _reason;
122 
123     private BuildManagerHost _host;
124     private Exception _hostCreationException;
125     private bool _hostCreationPending;
126 
127     public event BuildManagerHostUnloadEventHandler AppDomainUnloaded;
128 
129     public event EventHandler AppDomainStarted;
130 
131     public event BuildManagerHostUnloadEventHandler AppDomainShutdown;
132     // internal lock used for host creation.
133     private object _lock = new object();
134 
135     // Whether to wait for the call back from the previous host unloading before creating a new one
136     private bool _waitForCallBack;
137 
138     private const string IISExpressPrefix = "/IISExpress/";
139 
140     /*
141      * Creates an instance of the ClientBuildManager.
142      * appPhysicalSourceDir points to the physical root of the application (e.g "c:\myapp")
143      * virtualPath is the virtual path to the app root. It can be anything (e.g. "/dummy"),
144      *      but ideally it should match the path later given to Cassini, in order for
145      *      compilation that happens here to be reused there.
146      */
147 
ClientBuildManager(string appVirtualDir, string appPhysicalSourceDir)148     public ClientBuildManager(string appVirtualDir, string appPhysicalSourceDir) :
149         this(appVirtualDir, appPhysicalSourceDir,
150         appPhysicalTargetDir: null, parameter: null) {
151     }
152 
153     /*
154      * Creates an instance of the PrecompilationManager.
155      * appPhysicalSourceDir points to the physical root of the application (e.g "c:\myapp")
156      * appVirtualDir is the virtual path to the app root. It can be anything (e.g. "/dummy"),
157      *      but ideally it should match the path later given to Cassini, in order for
158      *      compilation that happens here to be reused there.
159      * appPhysicalTargetDir is the directory where the precompiled site is placed
160      */
ClientBuildManager(string appVirtualDir, string appPhysicalSourceDir, string appPhysicalTargetDir)161     public ClientBuildManager(string appVirtualDir, string appPhysicalSourceDir,
162         string appPhysicalTargetDir) : this(appVirtualDir, appPhysicalSourceDir,
163             appPhysicalTargetDir, parameter: null) {
164     }
165 
166     /*
167      * Creates an instance of the PrecompilationManager.
168      * appPhysicalSourceDir points to the physical root of the application (e.g "c:\myapp")
169      * appVirtualDir is the virtual path to the app root. It can be anything (e.g. "/dummy"),
170      *      but ideally it should match the path later given to Cassini, in order for
171      *      compilation that happens here to be reused there.
172      * appPhysicalTargetDir is the directory where the precompiled site is placed
173      * flags determines the behavior of the precompilation
174      */
ClientBuildManager(string appVirtualDir, string appPhysicalSourceDir, string appPhysicalTargetDir, ClientBuildManagerParameter parameter)175     public ClientBuildManager(string appVirtualDir, string appPhysicalSourceDir,
176         string appPhysicalTargetDir, ClientBuildManagerParameter parameter) :
177         this(appVirtualDir, appPhysicalSourceDir,
178             appPhysicalTargetDir, parameter, typeDescriptionProvider: null) {
179     }
180 
181     /*
182      * Creates an instance of the PrecompilationManager.
183      * appPhysicalSourceDir points to the physical root of the application (e.g "c:\myapp")
184      * appVirtualDir is the virtual path to the app root. It can be anything (e.g. "/dummy"),
185      *      but ideally it should match the path later given to Cassini, in order for
186      *      compilation that happens here to be reused there.
187      * appPhysicalTargetDir is the directory where the precompiled site is placed
188      * typeDescriptionProvider is the provider used for retrieving type
189      * information for multi-targeting
190      */
ClientBuildManager(string appVirtualDir, string appPhysicalSourceDir, string appPhysicalTargetDir, ClientBuildManagerParameter parameter, TypeDescriptionProvider typeDescriptionProvider)191     public ClientBuildManager(string appVirtualDir, string appPhysicalSourceDir,
192         string appPhysicalTargetDir, ClientBuildManagerParameter parameter,
193         TypeDescriptionProvider typeDescriptionProvider) {
194 
195         if (parameter == null) {
196             parameter = new ClientBuildManagerParameter();
197         }
198 
199         InitializeCBMTDPBridge(typeDescriptionProvider);
200 
201         // Always build clean in precompilation for deployment mode,
202         // since building incrementally raises all kind of issues (VSWhidbey 382954).
203         if (!String.IsNullOrEmpty(appPhysicalTargetDir)) {
204             parameter.PrecompilationFlags |= PrecompilationFlags.Clean;
205         }
206 
207         _hostingParameters = new HostingEnvironmentParameters();
208         _hostingParameters.HostingFlags = HostingEnvironmentFlags.DontCallAppInitialize |
209                                           HostingEnvironmentFlags.ClientBuildManager;
210         _hostingParameters.ClientBuildManagerParameter = parameter;
211         _hostingParameters.PrecompilationTargetPhysicalDirectory = appPhysicalTargetDir;
212         if (typeDescriptionProvider != null) {
213             _hostingParameters.HostingFlags |= HostingEnvironmentFlags.SupportsMultiTargeting;
214         }
215 
216         // Make sure the app virtual dir starts with /
217         if (appVirtualDir[0] != '/')
218             appVirtualDir = "/" + appVirtualDir;
219 
220         if (appPhysicalSourceDir == null
221             && appVirtualDir.StartsWith(IISExpressPrefix, StringComparison.OrdinalIgnoreCase)
222             && appVirtualDir.Length > IISExpressPrefix.Length) {
223             // appVirtualDir should have the form "/IISExpress/<version>/LM/W3SVC/",
224             // and we will try to extract the version.  The version will be validated
225             // when it is passed to IISVersionHelper..ctor.
226             int endSlash = appVirtualDir.IndexOf('/', IISExpressPrefix.Length);
227             if (endSlash > 0) {
228                 _hostingParameters.IISExpressVersion = appVirtualDir.Substring(IISExpressPrefix.Length, endSlash - IISExpressPrefix.Length);
229                 appVirtualDir = appVirtualDir.Substring(endSlash);
230             }
231         }
232 
233         Initialize(VirtualPath.CreateNonRelative(appVirtualDir), appPhysicalSourceDir);
234     }
235 
236     /*
237      * returns the codegendir used by runtime appdomain
238      */
239     public string CodeGenDir {
240         get {
241             if (_codeGenDir == null) {
242                 EnsureHostCreated();
243                 _codeGenDir = _host.CodeGenDir;
244             }
245 
246             return _codeGenDir;
247         }
248     }
249 
250     /*
251      * Indicates whether the host is created.
252      */
253 
254     public bool IsHostCreated {
255         get {
256             return _host != null;
257         }
258     }
259 
260     /*
261      * Create an object in the runtime appdomain
262      */
263 
CreateObject(Type type, bool failIfExists)264     public IRegisteredObject CreateObject(Type type, bool failIfExists) {
265         if (type == null) {
266             throw new ArgumentNullException("type");
267         }
268 
269         EnsureHostCreated();
270         Debug.Assert(_appId != null);
271         Debug.Assert(_appHost != null);
272 
273         _host.RegisterAssembly(type.Assembly.FullName, type.Assembly.Location);
274 
275         ApplicationManager appManager = ApplicationManager.GetApplicationManager();
276         return appManager.CreateObjectInternal(_appId, type, _appHost, failIfExists, _hostingParameters);
277     }
278 
279     /*
280      * Return the list of directories that would cause appdomain shutdown.
281      */
GetAppDomainShutdownDirectories()282     public string[] GetAppDomainShutdownDirectories() {
283         Debug.Trace("CBM", "GetAppDomainShutdownDirectories");
284 
285         return FileChangesMonitor.s_dirsToMonitor;
286     }
287 
288     /*
289      * Makes sure that all the top level files are compiled (code, global.asax, ...)
290      */
291 
CompileApplicationDependencies()292     public void CompileApplicationDependencies() {
293         Debug.Trace("CBM", "CompileApplicationDependencies");
294 
295         EnsureHostCreated();
296 
297         _host.CompileApplicationDependencies();
298     }
299 
300 
GetBrowserDefinitions()301     public IDictionary GetBrowserDefinitions() {
302         Debug.Trace("CBM", "GetBrowserDefinitions");
303 
304         EnsureHostCreated();
305 
306         return _host.GetBrowserDefinitions();
307     }
308 
309     /*
310      * Returns the physical path of the generated file corresponding to the virtual directory.
311      * Note the virtualPath needs to use this format:
312      * "/[appname]/App_WebReferences/{[subDir]/}"
313      */
GetGeneratedSourceFile(string virtualPath)314     public string GetGeneratedSourceFile(string virtualPath) {
315         Debug.Trace("CBM", "GetGeneratedSourceFile " + virtualPath);
316 
317         if (virtualPath == null) {
318             throw new ArgumentNullException("virtualPath");
319         }
320 
321         EnsureHostCreated();
322 
323         return _host.GetGeneratedSourceFile(VirtualPath.CreateTrailingSlash(virtualPath));
324     }
325 
326     /*
327     * Returns the virtual path of the corresponding generated file.
328     * Note the filepath needs to be a full path.
329     */
GetGeneratedFileVirtualPath(string filePath)330     public string GetGeneratedFileVirtualPath(string filePath) {
331         Debug.Trace("CBM", "GetGeneratedFileVirtualPath " + filePath);
332 
333         if (filePath == null) {
334             throw new ArgumentNullException("filePath");
335         }
336 
337         EnsureHostCreated();
338 
339         return _host.GetGeneratedFileVirtualPath(filePath);
340     }
341     /*
342      * Returns an array of the virtual paths to all the code directories in the app thru the hosted appdomain
343      */
344 
GetVirtualCodeDirectories()345     public string[] GetVirtualCodeDirectories() {
346         Debug.Trace("CBM", "GetHostedVirtualCodeDirectories");
347 
348         EnsureHostCreated();
349 
350         return _host.GetVirtualCodeDirectories();
351     }
352 
353     /*
354      * Returns an array of the assemblies defined in the bin and assembly reference config section
355      */
356 
GetTopLevelAssemblyReferences(string virtualPath)357     public String[] GetTopLevelAssemblyReferences(string virtualPath) {
358         Debug.Trace("CBM", "GetHostedVirtualCodeDirectories");
359 
360         if (virtualPath == null) {
361             throw new ArgumentNullException("virtualPath");
362         }
363 
364         EnsureHostCreated();
365 
366         return _host.GetTopLevelAssemblyReferences(VirtualPath.Create(virtualPath));
367     }
368 
369     /*
370      * Returns the compiler type and parameters that need to be used to build
371      * a given code directory.  Also, returns the directory containing all the code
372      * files generated from non-code files in the code directory (e.g. wsdl files)
373      */
374 
GetCodeDirectoryInformation(string virtualCodeDir, out Type codeDomProviderType, out CompilerParameters compilerParameters, out string generatedFilesDir)375     public void GetCodeDirectoryInformation(string virtualCodeDir,
376         out Type codeDomProviderType, out CompilerParameters compilerParameters,
377         out string generatedFilesDir) {
378         Debug.Trace("CBM", "GetCodeDirectoryInformation " + virtualCodeDir);
379 
380         if (virtualCodeDir == null) {
381             throw new ArgumentNullException("virtualCodeDir");
382         }
383 
384         EnsureHostCreated();
385 
386         _host.GetCodeDirectoryInformation(VirtualPath.CreateTrailingSlash(virtualCodeDir),
387             out codeDomProviderType, out compilerParameters, out generatedFilesDir);
388 
389         Debug.Trace("CBM", "GetCodeDirectoryInformation " + virtualCodeDir + " end");
390     }
391 
392     /*
393      * Returns the compiler type and parameters that need to be used to build
394      * a given file.
395      */
396 
GetCompilerParameters(string virtualPath, out Type codeDomProviderType, out CompilerParameters compilerParameters)397     public void GetCompilerParameters(string virtualPath,
398         out Type codeDomProviderType, out CompilerParameters compilerParameters) {
399         Debug.Trace("CBM", "GetCompilerParameters " + virtualPath);
400 
401         if (virtualPath == null) {
402             throw new ArgumentNullException("virtualPath");
403         }
404 
405         EnsureHostCreated();
406 
407         _host.GetCompilerParams(VirtualPath.Create(virtualPath), out codeDomProviderType, out compilerParameters);
408     }
409 
410     /*
411      * Returns the codedom tree and the compiler type/param for a given file.
412      */
413 
GenerateCodeCompileUnit( string virtualPath, out Type codeDomProviderType, out CompilerParameters compilerParameters, out IDictionary linePragmasTable)414     public CodeCompileUnit GenerateCodeCompileUnit(
415         string virtualPath, out Type codeDomProviderType,
416         out CompilerParameters compilerParameters, out IDictionary linePragmasTable) {
417         Debug.Trace("CBM", "GenerateCodeCompileUnit " + virtualPath);
418 
419         return GenerateCodeCompileUnit(virtualPath, null,
420             out codeDomProviderType, out compilerParameters, out linePragmasTable);
421     }
422 
423 
GenerateCodeCompileUnit( string virtualPath, String virtualFileString, out Type codeDomProviderType, out CompilerParameters compilerParameters, out IDictionary linePragmasTable)424     public CodeCompileUnit GenerateCodeCompileUnit(
425         string virtualPath, String virtualFileString, out Type codeDomProviderType,
426         out CompilerParameters compilerParameters, out IDictionary linePragmasTable) {
427         Debug.Trace("CBM", "GenerateCodeCompileUnit " + virtualPath);
428 
429         if (virtualPath == null) {
430             throw new ArgumentNullException("virtualPath");
431         }
432 
433         EnsureHostCreated();
434 
435         return _host.GenerateCodeCompileUnit(VirtualPath.Create(virtualPath), virtualFileString,
436             out codeDomProviderType, out compilerParameters, out linePragmasTable);
437     }
438 
GenerateCode( string virtualPath, String virtualFileString, out IDictionary linePragmasTable)439     public string GenerateCode(
440         string virtualPath, String virtualFileString, out IDictionary linePragmasTable) {
441         Debug.Trace("CBM", "GenerateCode " + virtualPath);
442 
443         if (virtualPath == null) {
444             throw new ArgumentNullException("virtualPath");
445         }
446 
447         EnsureHostCreated();
448 
449         return _host.GenerateCode(VirtualPath.Create(virtualPath), virtualFileString, out linePragmasTable);
450     }
451 
452     /*
453      * Returns the compiled type for an input file
454      */
455 
GetCompiledType(string virtualPath)456     public Type GetCompiledType(string virtualPath) {
457         Debug.Trace("CBM", "GetCompiledType " + virtualPath);
458 
459         if (virtualPath == null) {
460             throw new ArgumentNullException("virtualPath");
461         }
462 
463         EnsureHostCreated();
464 
465         string[] typeAndAsemblyName = _host.GetCompiledTypeAndAssemblyName(VirtualPath.Create(virtualPath), null);
466         if (typeAndAsemblyName == null)
467             return null;
468 
469         Assembly a = Assembly.LoadFrom(typeAndAsemblyName[1]);
470         Type t = a.GetType(typeAndAsemblyName[0]);
471         return t;
472     }
473 
474     /*
475      * Compile a file
476      */
CompileFile(string virtualPath)477     public void CompileFile(string virtualPath) {
478         CompileFile(virtualPath, null);
479     }
480 
CompileFile(string virtualPath, ClientBuildManagerCallback callback)481     public void CompileFile(string virtualPath, ClientBuildManagerCallback callback) {
482         Debug.Trace("CBM", "CompileFile " + virtualPath);
483 
484         if (virtualPath == null) {
485             throw new ArgumentNullException("virtualPath");
486         }
487 
488         try {
489             EnsureHostCreated();
490             _host.GetCompiledTypeAndAssemblyName(VirtualPath.Create(virtualPath), callback);
491         }
492         finally {
493             // DevDiv 180798. We are returning null in ClientBuildManagerCallback.InitializeLifetimeService,
494             // so we need to manually disconnect the instance so that it will be released.
495             if (callback != null) {
496                 RemotingServices.Disconnect(callback);
497             }
498         }
499     }
500 
501     /*
502      * Indicates whether an assembly is a code assembly.
503      */
IsCodeAssembly(string assemblyName)504     public bool IsCodeAssembly(string assemblyName) {
505         Debug.Trace("CBM", "IsCodeAssembly " + assemblyName);
506 
507         if (assemblyName == null) {
508             throw new ArgumentNullException("assemblyName");
509         }
510 
511         //
512 
513         EnsureHostCreated();
514         bool result = _host.IsCodeAssembly(assemblyName);
515 
516         Debug.Trace("CBM", "IsCodeAssembly " + result.ToString());
517         return result;
518     }
519 
520 
Unload()521     public bool Unload() {
522         Debug.Trace("CBM", "Unload");
523 
524         BuildManagerHost host = _host;
525         if (host != null) {
526             _host = null;
527             return host.UnloadAppDomain();
528         }
529 
530         return false;
531     }
532 
533     /*
534      * Precompile an application
535      */
PrecompileApplication()536     public void PrecompileApplication() {
537         PrecompileApplication(null);
538     }
539 
540     /*
541      * Precompile an application with callback support
542      */
PrecompileApplication(ClientBuildManagerCallback callback)543     public void PrecompileApplication(ClientBuildManagerCallback callback) {
544         PrecompileApplication(callback, false);
545     }
546 
PrecompileApplication(ClientBuildManagerCallback callback, bool forceCleanBuild)547     public void PrecompileApplication(ClientBuildManagerCallback callback, bool forceCleanBuild) {
548         Debug.Trace("CBM", "PrecompileApplication");
549 
550         PrecompilationFlags savedFlags = _hostingParameters.ClientBuildManagerParameter.PrecompilationFlags;
551 
552         if (forceCleanBuild) {
553 
554             // If there was a previous host, it will be unloaded by CBM and we will wait for the callback.
555             // If there was no previous host, we don't do any waiting.
556             // DevDiv 46290
557             _waitForCallBack = _host != null;
558 
559             Debug.Trace("CBM", "Started Unload");
560             // Unload the existing appdomain so the new one will be created with the clean flag
561             Unload();
562 
563             _hostingParameters.ClientBuildManagerParameter.PrecompilationFlags =
564                 savedFlags | PrecompilationFlags.Clean;
565 
566             WaitForCallBack();
567         }
568 
569         try {
570             EnsureHostCreated();
571             _host.PrecompileApp(callback, _hostingParameters.ClientBuildManagerParameter.ExcludedVirtualPaths);
572         }
573         finally {
574             if (forceCleanBuild) {
575                 // Revert precompilationFlags
576                 _hostingParameters.ClientBuildManagerParameter.PrecompilationFlags = savedFlags;
577             }
578             // DevDiv 180798. We are returning null in ClientBuildManagerCallback.InitializeLifetimeService,
579             // so we need to manually disconnect the instance so that it will be released.
580             if (callback != null) {
581                 RemotingServices.Disconnect(callback);
582             }
583         }
584     }
585 
586     // _waitForCallBack is set to false in OnAppDomainUnloaded.
587     // This method waits until it is set to false before continuing, so that
588     // we do not run into a concurrency issue where _host could be set to null.
589     // DevDiv 46290
WaitForCallBack()590     private void WaitForCallBack() {
591         Debug.Trace("CBM", "WaitForCallBack");
592         int waited = 0;
593         while (_waitForCallBack && waited <= 50) {
594             Thread.Sleep(200);
595             waited++;
596         }
597         if (_waitForCallBack) {
598             Debug.Trace("CBM", "timeout while waiting for callback");
599         }
600         else {
601             Debug.Trace("CBM", "callback received before timeout");
602         }
603     }
604 
InitializeLifetimeService()605     public override Object InitializeLifetimeService() {
606         return null; // never expire lease
607     }
608 
Initialize(VirtualPath virtualPath, string physicalPath)609     internal void Initialize(VirtualPath virtualPath, string physicalPath) {
610         Debug.Trace("CBM", "Initialize");
611 
612         _virtualPath = virtualPath;
613 
614         _physicalPath = FileUtil.FixUpPhysicalDirectory(physicalPath);
615 
616         _onAppDomainUnloadedCallback = new WaitCallback(OnAppDomainUnloadedCallback);
617         _onAppDomainShutdown = new WaitCallback(OnAppDomainShutdownCallback);
618 
619         _installPath = RuntimeEnvironment.GetRuntimeDirectory();
620 
621         // Do not create host during intialization. It will be done on demand.
622         //CreateHost();
623     }
624 
EnsureHostCreated()625     private void EnsureHostCreated() {
626 
627         if (_host == null) {
628             lock (_lock) {
629                 // Create the host if necessary
630                 if (_host == null) {
631                     CreateHost();
632                     Debug.Trace("CBM", "EnsureHostCreated: after CreateHost()");
633                 }
634             }
635         }
636 
637         // If an exception happened during host creation, rethrow it
638         if (_hostCreationException != null) {
639             Debug.Trace("CBM", "EnsureHostCreated: failed. " + _hostCreationException);
640 
641             // We need to wrap it in a new exception, otherwise we lose the original stack.
642             throw new HttpException(_hostCreationException.Message,
643                 _hostCreationException);
644         }
645     }
646 
CreateHost()647     private void CreateHost() {
648         Debug.Trace("CBM", "CreateHost");
649         Debug.Assert(_host == null);
650 
651         Debug.Assert(!_hostCreationPending, "CreateHost: creation already pending");
652 
653         _hostCreationPending = true;
654 
655         // Use a local to avoid having a partially created _host
656         BuildManagerHost host = null;
657 
658         try {
659             string appId;
660             IApplicationHost appHost;
661 
662             ApplicationManager appManager = ApplicationManager.GetApplicationManager();
663 
664             host = (BuildManagerHost) appManager.CreateObjectWithDefaultAppHostAndAppId(
665                 _physicalPath, _virtualPath,
666                 typeof(BuildManagerHost), false /*failIfExists*/,
667                 _hostingParameters, out appId, out appHost);
668 
669             // host appdomain cannot be unloaded during creation.
670             host.AddPendingCall();
671 
672             host.Configure(this);
673 
674             _host = host;
675             _appId = appId;
676             _appHost = appHost;
677 
678             _hostCreationException = _host.InitializationException;
679         }
680         catch (Exception e) {
681             // If an exception happens, keep track of it
682             _hostCreationException = e;
683 
684             // Even though the host initialization failed, keep track of it so subsequent
685             // request will see the error
686             _host = host;
687         }
688         finally {
689             _hostCreationPending = false;
690 
691             if (host != null) {
692                 // Notify the client that the host is ready
693                 if (AppDomainStarted != null) {
694                     AppDomainStarted(this, EventArgs.Empty);
695                 }
696 
697                 // The host can be unloaded safely now.
698                 host.RemovePendingCall();
699             }
700         }
701 
702         Debug.Trace("CBM", "CreateHost LEAVE");
703     }
704 
705     // Called by BuildManagerHost when the ASP appdomain is unloaded
OnAppDomainUnloaded(ApplicationShutdownReason reason)706     internal void OnAppDomainUnloaded(ApplicationShutdownReason reason) {
707         Debug.Trace("CBM", "OnAppDomainUnloaded " + reason.ToString());
708 
709         _reason = reason;
710         _waitForCallBack = false;
711 
712         // Don't do anything that can be slow here.  Instead queue in a worker thread
713         ThreadPool.QueueUserWorkItem(_onAppDomainUnloadedCallback);
714     }
715 
ResetHost()716     internal void ResetHost() {
717         lock (_lock) {
718             // Though _appId and _appHost are created along with _host,
719             // we need not reset those here as they always correspond to
720             // default app id and app host.
721             _host = null;
722             _hostCreationException = null;
723         }
724     }
725 
726     [PermissionSet(SecurityAction.Assert, Unrestricted = true)]
OnAppDomainUnloadedCallback(Object unused)727     private void OnAppDomainUnloadedCallback(Object unused) {
728         Debug.Trace("CBM", "OnAppDomainUnloadedCallback");
729 
730         // Notify the client that the appdomain is unloaded
731         if (AppDomainUnloaded != null) {
732             AppDomainUnloaded(this, new BuildManagerHostUnloadEventArgs(_reason));
733         }
734     }
735 
736     [PermissionSet(SecurityAction.Assert, Unrestricted = true)]
OnAppDomainShutdownCallback(Object o)737     private void OnAppDomainShutdownCallback(Object o) {
738         if (AppDomainShutdown != null) {
739             AppDomainShutdown(this, new BuildManagerHostUnloadEventArgs((ApplicationShutdownReason)o));
740         }
741     }
742 
OnAppDomainShutdown(ApplicationShutdownReason reason)743     internal void OnAppDomainShutdown(ApplicationShutdownReason reason) {
744         // Don't do anything that can be slow here. Instead queue in a worker thread
745         ThreadPool.QueueUserWorkItem(_onAppDomainShutdown, reason);
746     }
747 
InitializeCBMTDPBridge(TypeDescriptionProvider typeDescriptionProvider)748     private void InitializeCBMTDPBridge(TypeDescriptionProvider typeDescriptionProvider) {
749         if (typeDescriptionProvider == null){
750             return;
751         }
752         _cbmTdpBridge = new ClientBuildManagerTypeDescriptionProviderBridge(typeDescriptionProvider);
753     }
754 
755     internal ClientBuildManagerTypeDescriptionProviderBridge CBMTypeDescriptionProviderBridge {
756         get {
757             return _cbmTdpBridge;
758         }
759     }
760 
761     #region IDisposable
762     //Dispose the runtime appdomain properly when CBM is disposed
IDisposable.Dispose()763     void IDisposable.Dispose() {
764         Unload();
765     }
766     #endregion
767 
768 }
769 
770 
771 [PermissionSet(SecurityAction.LinkDemand, Unrestricted = true)]
772 [PermissionSet(SecurityAction.InheritanceDemand, Unrestricted = true)]
773 public class BuildManagerHostUnloadEventArgs : EventArgs {
774     ApplicationShutdownReason _reason;
775 
BuildManagerHostUnloadEventArgs(ApplicationShutdownReason reason)776     public BuildManagerHostUnloadEventArgs(ApplicationShutdownReason reason) {
777         _reason = reason;
778     }
779 
780     // Get the reason for the hosted appdomain shutdown
781 
782     public ApplicationShutdownReason Reason { get { return _reason; } }
783 }
784 
785 
BuildManagerHostUnloadEventHandler(object sender, BuildManagerHostUnloadEventArgs e)786 public delegate void BuildManagerHostUnloadEventHandler(object sender, BuildManagerHostUnloadEventArgs e);
787 
788 /*
789  * Type of the entries in the table returned by GenerateCodeCompileUnit
790  */
791 
792 [Serializable]
793 public sealed class LinePragmaCodeInfo {
794 
LinePragmaCodeInfo()795     public LinePragmaCodeInfo() {
796     }
797 
LinePragmaCodeInfo(int startLine, int startColumn, int startGeneratedColumn, int codeLength, bool isCodeNugget)798     public LinePragmaCodeInfo(int startLine, int startColumn, int startGeneratedColumn, int codeLength, bool isCodeNugget) {
799         this._startLine = startLine;
800         this._startColumn = startColumn;
801         this._startGeneratedColumn = startGeneratedColumn;
802         this._codeLength = codeLength;
803         this._isCodeNugget = isCodeNugget;
804     }
805 
806     // Starting line in ASPX file
807     internal int _startLine;
808 
809     public int StartLine { get { return _startLine; } }
810 
811     // Starting column in the ASPX file
812     internal int _startColumn;
813 
814     public int StartColumn { get { return _startColumn; } }
815 
816     // Starting column in the generated source file (assuming no indentations are used)
817     internal int _startGeneratedColumn;
818 
819     public int StartGeneratedColumn { get { return _startGeneratedColumn; } }
820 
821     // Length of the code snippet
822     internal int _codeLength;
823 
824     public int CodeLength { get { return _codeLength; } }
825 
826     // Whether the script block is a nugget.
827     internal bool _isCodeNugget;
828 
829     public bool IsCodeNugget { get { return _isCodeNugget; } }
830 }
831 
832 }
833 
834 
835