Merge pull request #3389 from lambdageek/bug-43099
[mono.git] / mcs / class / referencesource / System.Web / Hosting / ApplicationManager.cs
1 //------------------------------------------------------------------------------
2 // <copyright file="ApplicationManager.cs" company="Microsoft">
3 //     Copyright (c) Microsoft Corporation.  All rights reserved.
4 // </copyright>
5 //------------------------------------------------------------------------------
6
7
8 namespace System.Web.Hosting {
9     using System;
10     using System.Collections;
11     using System.Collections.Generic;
12     using System.Configuration;
13     using System.Diagnostics.CodeAnalysis;
14     using System.Globalization;
15     using System.IO;
16     using System.Linq;
17     using System.Reflection;
18     using System.Runtime.ExceptionServices;
19     using System.Runtime.InteropServices;
20     using System.Runtime.Remoting;
21     using System.Runtime.Versioning;
22     using System.Security;
23     using System.Security.Permissions;
24     using System.Security.Policy;
25     using System.Text;
26     using System.Threading;
27     using System.Threading.Tasks;
28     using System.Web;
29     using System.Web.Compilation;
30     using System.Web.Configuration;
31     using System.Web.Util;
32
33     public enum HostSecurityPolicyResults {
34         DefaultPolicy = 0,
35         FullTrust = 1,
36         AppDomainTrust = 2,
37         Nothing = 3
38     };
39
40     [PermissionSet(SecurityAction.InheritanceDemand, Unrestricted = true)]
41     public class HostSecurityPolicyResolver {
42         public virtual HostSecurityPolicyResults ResolvePolicy(Evidence evidence) {
43             return HostSecurityPolicyResults.DefaultPolicy;
44         }
45     }
46
47
48
49     internal class LockableAppDomainContext {
50         internal HostingEnvironment HostEnv { get; set; }
51         internal string PreloadContext { get; set; }
52         internal bool RetryingPreload { get; set; }
53
54         internal LockableAppDomainContext() {
55         }
56     }
57
58     public sealed class ApplicationManager : MarshalByRefObject {
59
60         private const string _clrQuirkAppSettingsAppContextPrefix = "AppContext.SetSwitch:";
61         private const string _regexMatchTimeoutKey = "REGEX_DEFAULT_MATCH_TIMEOUT";
62         private static readonly StrongName _mwiV1StrongName = GetMicrosoftWebInfrastructureV1StrongName();
63
64         private static Object _applicationManagerStaticLock = new Object();
65
66         // open count (when last close goes to 0 it shuts down everything)
67         int _openCount = 0;
68         bool _shutdownInProgress = false;
69
70         // table of app domains (LockableAppDomainContext objects) by app id
71         // To simplify per-appdomain synchronization we will never remove LockableAppDomainContext objects from this table even when the AD is unloaded
72         // We may need to fix it if profiling shows a noticeable impact on performance
73         private Dictionary <string, LockableAppDomainContext> _appDomains = new Dictionary<string, LockableAppDomainContext>(StringComparer.OrdinalIgnoreCase);
74         // count of HostingEnvironment instances that is referenced in _appDomains collection
75         private int _accessibleHostingEnvCount;
76
77         // could differ from _appDomains or _accessibleHostingEnvCount count (host env is active some time after it is removed)
78         private int _activeHostingEnvCount;
79
80         // pending callback to respond to ping (typed as Object to do Interlocked operations)
81         private Object _pendingPingCallback;
82         // delegate OnRespondToPing
83         private WaitCallback _onRespondToPingWaitCallback;
84
85         // flag indicates whether any fatal exception has been recorded
86         private bool _fatalExceptionRecorded = false;
87
88         // single instance of app manager
89         private static ApplicationManager _theAppManager;
90
91         // single instance of cache manager
92         private static CacheManager _cm;
93
94         // store fatal exception to assist debugging
95         private static Exception _fatalException = null;
96
97         internal ApplicationManager() {
98             _onRespondToPingWaitCallback = new WaitCallback(this.OnRespondToPingWaitCallback);
99
100             // VSWhidbey 555767: Need better logging for unhandled exceptions (http://support.microsoft.com/?id=911816)
101             // We only add a handler in the default domain because it will be notified when an unhandled exception 
102             // occurs in ANY domain.  
103             // WOS 1983175: (weird) only the handler in the default domain is notified when there is an AV in a native module
104             // while we're in a call to MgdIndicateCompletion.
105             AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(OnUnhandledException);
106         }
107
108         private void InitCacheManager(long privateBytesLimit) {
109             if (_cm == null) {
110                 lock (_applicationManagerStaticLock) {
111                     if (_cm == null && !_shutdownInProgress) {
112                         _cm = new CacheManager(this, privateBytesLimit);
113                     }
114                 }
115             }
116         }
117
118         private void DisposeCacheManager() {
119             if (_cm != null) {
120                 lock (_applicationManagerStaticLock) {
121                     if (_cm != null) {
122                         _cm.Dispose();
123                         _cm = null;
124                     }
125                 }
126             }
127         }
128
129         // Each cache must update the total with the difference between it's current size and it's previous size.
130         // To reduce cross-domain costs, this also returns the updated total size.
131         internal long GetUpdatedTotalCacheSize(long sizeUpdate) {
132             CacheManager cm = _cm;
133             return (cm != null) ? cm.GetUpdatedTotalCacheSize(sizeUpdate) : 0;
134         }
135
136         internal long TrimCaches(int percent) {
137             long trimmedOrExpired = 0;
138             Dictionary<string, LockableAppDomainContext> apps = CloneAppDomainsCollection();
139             foreach (LockableAppDomainContext ac in apps.Values) {
140                 lock (ac) {
141                     HostingEnvironment env = ac.HostEnv;
142                     if (_shutdownInProgress) {
143                         break;
144                     }
145                     if (env == null) {
146                         continue;
147                     }
148                     trimmedOrExpired += env.TrimCache(percent);
149                 }
150             }
151             return trimmedOrExpired;
152         }
153
154         internal bool ShutdownInProgress {
155             get {
156                 return _shutdownInProgress;
157             }
158         }
159
160         private bool FatalExceptionRecorded
161         {
162             get {
163                 return _fatalExceptionRecorded;
164             }
165             set {
166                 _fatalExceptionRecorded = value;
167             }
168         }
169
170         internal static void RecordFatalException(Exception e) {
171             RecordFatalException(AppDomain.CurrentDomain, e);
172         }
173
174         internal static void RecordFatalException(AppDomain appDomain, Exception e) {
175             // store the exception from the first caller to assist debugging
176             object originalValue = Interlocked.CompareExchange(ref _fatalException, e, null);
177
178             if (originalValue == null) {
179                 // create event log entry
180                 Misc.WriteUnhandledExceptionToEventLog(appDomain, e);
181             }
182         }
183
184         internal static void OnUnhandledException(Object sender, UnhandledExceptionEventArgs eventArgs) {
185             // if the CLR is not terminating, ignore the notification
186             if (!eventArgs.IsTerminating) {
187                 return;
188             }
189
190             Exception exception = eventArgs.ExceptionObject as Exception;
191             if (exception == null) {
192                 return;
193             }
194
195             AppDomain appDomain = sender as AppDomain;
196             if (appDomain == null) {
197                 return;
198             }
199
200             // If any fatal exception was recorded in applicaiton AppDomains,
201             // we wouldn't record exceptions in the default AppDomain. 
202             var appManager = GetApplicationManager();
203             if (AppDomain.CurrentDomain.IsDefaultAppDomain() && appManager.FatalExceptionRecorded) {
204                 return;
205             }
206
207             appManager.FatalExceptionRecorded = true;
208
209             RecordFatalException(appDomain, exception);
210         }
211
212         public override Object InitializeLifetimeService() {
213             return null; // never expire lease
214         }
215
216         //
217         // public ApplicationManager methods
218         //
219
220
221         public static ApplicationManager GetApplicationManager() {
222             if (_theAppManager == null) {
223                 lock (_applicationManagerStaticLock) {
224                     if (_theAppManager == null) {
225                         if (HostingEnvironment.IsHosted)
226                             _theAppManager = HostingEnvironment.GetApplicationManager();
227
228                         if (_theAppManager == null)
229                             _theAppManager = new ApplicationManager();
230                     }
231                 }
232             }
233
234             return _theAppManager;
235         }
236
237
238         [SecurityPermission(SecurityAction.Demand, Unrestricted=true)]
239         public void Open() {
240             Interlocked.Increment(ref _openCount);
241         }
242
243
244         [SecurityPermission(SecurityAction.Demand, Unrestricted = true)]
245         public void Close() {
246             if (Interlocked.Decrement(ref _openCount) > 0)
247                 return;
248
249             // need to shutdown everything
250             ShutdownAll();
251         }
252
253         private string CreateSimpleAppID(VirtualPath virtualPath, string physicalPath, string siteName) {
254             // Put together some unique app id
255             string appId = String.Concat(virtualPath.VirtualPathString, physicalPath);
256
257             if (!String.IsNullOrEmpty(siteName)) {
258                 appId = String.Concat(appId, siteName);
259             }
260
261             return appId.GetHashCode().ToString("x", CultureInfo.InvariantCulture);
262         }
263
264         [SecurityPermission(SecurityAction.Demand, Unrestricted = true)]
265         public IRegisteredObject CreateObject(IApplicationHost appHost, Type type) {
266             if (appHost == null) {
267                 throw new ArgumentNullException("appHost");
268             }
269             if (type == null) {
270                 throw new ArgumentNullException("type");
271             }
272
273             string appID = CreateSimpleAppID(appHost);
274             return CreateObjectInternal(appID, type, appHost, false);            
275         }
276
277         [SecurityPermission(SecurityAction.Demand, UnmanagedCode=true)]
278         public IRegisteredObject CreateObject(String appId, Type type, string virtualPath, string physicalPath, bool failIfExists) {
279             return CreateObject(appId, type, virtualPath, physicalPath, failIfExists, false /*throwOnError*/);
280         }
281
282         [SecurityPermission(SecurityAction.Demand, Unrestricted = true)]
283         public IRegisteredObject CreateObject(String appId, Type type, string virtualPath, string physicalPath,
284                                               bool failIfExists, bool throwOnError) {
285             // check args
286             if (appId == null)
287                 throw new ArgumentNullException("appId");
288
289             SimpleApplicationHost appHost = new SimpleApplicationHost(VirtualPath.CreateAbsolute(virtualPath), physicalPath);
290
291             // if throw on error flag is set, create hosting parameters accordingly
292             HostingEnvironmentParameters hostingParameters = null;
293
294             if (throwOnError) {
295                 hostingParameters = new HostingEnvironmentParameters();
296                 hostingParameters.HostingFlags = HostingEnvironmentFlags.ThrowHostingInitErrors;
297
298             }
299
300             // call the internal method
301             return CreateObjectInternal(appId, type, appHost, failIfExists, hostingParameters);
302         }
303
304         [SecurityPermission(SecurityAction.Demand, Unrestricted = true)]
305         internal IRegisteredObject CreateObjectInternal(String appId, Type type, IApplicationHost appHost, bool failIfExists) {
306             // check args
307             if (appId == null)
308                 throw new ArgumentNullException("appId");
309
310             if (type == null)
311                 throw new ArgumentNullException("type");
312
313             if (appHost == null)
314                 throw new ArgumentNullException("appHost");
315
316             // call the internal method
317             return CreateObjectInternal(appId, type, appHost, failIfExists, null /*hostingParameters*/);
318         }
319
320         [PermissionSet(SecurityAction.Assert, Unrestricted = true)]
321         internal IRegisteredObject CreateObjectInternal(
322                                         String appId,
323                                         Type type,
324                                         IApplicationHost appHost,
325                                         bool failIfExists,
326                                         HostingEnvironmentParameters hostingParameters) {
327
328             // check that type is as IRegisteredObject
329             if (!typeof(IRegisteredObject).IsAssignableFrom(type))
330                 throw new ArgumentException(SR.GetString(SR.Not_IRegisteredObject, type.FullName), "type");
331
332             // get hosting environment
333             HostingEnvironment env = GetAppDomainWithHostingEnvironment(appId, appHost, hostingParameters);
334
335             // create the managed object in the worker app domain
336             // When marshaling Type, the AppDomain must have FileIoPermission to the assembly, which is not
337             // always the case, so we marshal the assembly qualified name instead
338             ObjectHandle h = env.CreateWellKnownObjectInstance(type.AssemblyQualifiedName, failIfExists);
339             return (h != null) ? h.Unwrap() as IRegisteredObject : null;
340         }
341
342         internal IRegisteredObject CreateObjectWithDefaultAppHostAndAppId(
343                                         String physicalPath,
344                                         string virtualPath,
345                                         Type type,
346                                         out String appId,
347                                         out IApplicationHost appHost) {
348             return CreateObjectWithDefaultAppHostAndAppId(physicalPath,
349                 VirtualPath.CreateNonRelative(virtualPath), type, out appId, out appHost);
350         }
351
352         internal IRegisteredObject CreateObjectWithDefaultAppHostAndAppId(
353                                         String physicalPath,
354                                         VirtualPath virtualPath,
355                                         Type type,
356                                         out String appId,
357                                         out IApplicationHost appHost) {
358
359             HostingEnvironmentParameters hostingParameters = new HostingEnvironmentParameters();
360             hostingParameters.HostingFlags = HostingEnvironmentFlags.DontCallAppInitialize;
361
362             return CreateObjectWithDefaultAppHostAndAppId(
363                         physicalPath,
364                         virtualPath,
365                         type,
366                         false,
367                         hostingParameters,
368                         out appId,
369                         out appHost);
370         }
371
372         internal IRegisteredObject CreateObjectWithDefaultAppHostAndAppId(
373                                         String physicalPath,
374                                         VirtualPath virtualPath,
375                                         Type type,
376                                         bool failIfExists,
377                                         HostingEnvironmentParameters hostingParameters,
378                                         out String appId,
379                                         out IApplicationHost appHost) {
380
381 #if !FEATURE_PAL // FEATURE_PAL does not enable IIS-based hosting features
382             if (physicalPath == null) { 
383
384                 // If the physical path is null, we use an ISAPIApplicationHost based
385                 // on the virtual path (or metabase id).
386
387                 // Make sure the static HttpRuntime is created so isapi assembly can be loaded properly.
388                 HttpRuntime.ForceStaticInit();
389
390                 ISAPIApplicationHost isapiAppHost = new ISAPIApplicationHost(virtualPath.VirtualPathString, null, true, null, hostingParameters.IISExpressVersion);
391
392                 appHost = isapiAppHost;
393                 appId = isapiAppHost.AppId;
394                 virtualPath = VirtualPath.Create(appHost.GetVirtualPath());
395                 physicalPath = FileUtil.FixUpPhysicalDirectory(appHost.GetPhysicalPath());
396             }
397             else {
398 #endif // !FEATURE_PAL
399                 // If the physical path was passed in, don't use an Isapi host. Instead,
400                 // use a simple app host which does simple virtual to physical mappings
401
402                 // Put together some unique app id
403                 appId = CreateSimpleAppID(virtualPath, physicalPath, null);
404
405                 appHost = new SimpleApplicationHost(virtualPath, physicalPath);
406             }
407
408             string precompTargetPhysicalDir = hostingParameters.PrecompilationTargetPhysicalDirectory;
409             if (precompTargetPhysicalDir != null) {
410                 // Change the appID so we use a different codegendir in precompile for deployment scenario,
411                 // this ensures we don't use or pollute the regular codegen files.  Also, use different
412                 // ID's depending on whether the precompilation is Updatable (VSWhidbey 383239)
413                 if ((hostingParameters.ClientBuildManagerParameter != null) && 
414                     (hostingParameters.ClientBuildManagerParameter.PrecompilationFlags & PrecompilationFlags.Updatable) == 0)
415                     appId = appId + "_precompile";
416                 else
417                     appId = appId + "_precompile_u";
418             }
419
420             return CreateObjectInternal(appId, type, appHost, failIfExists, hostingParameters);
421         }
422
423
424         [SecurityPermission(SecurityAction.Demand, Unrestricted = true)]
425         public IRegisteredObject GetObject(String appId, Type type) {
426             // check args
427             if (appId == null)
428                 throw new ArgumentNullException("appId");
429             if (type == null)
430                 throw new ArgumentNullException("type");
431
432             LockableAppDomainContext ac = GetLockableAppDomainContext(appId);
433             lock (ac) {
434                 HostingEnvironment env = ac.HostEnv;
435                 if (env == null)
436                     return null;
437
438                 // find the instance by type
439                 // When marshaling Type, the AppDomain must have FileIoPermission to the assembly, which is not
440                 // always the case, so we marshal the assembly qualified name instead
441                 ObjectHandle h = env.FindWellKnownObject(type.AssemblyQualifiedName);
442                 return (h != null) ? h.Unwrap() as IRegisteredObject : null;
443             }
444         }
445
446         [SecurityPermission(SecurityAction.Demand, Unrestricted = true)]
447         public AppDomain GetAppDomain(string appId) {
448             if (appId == null) {
449                 throw new ArgumentNullException("appId");
450             }
451
452             LockableAppDomainContext ac = GetLockableAppDomainContext(appId);
453             lock (ac) {
454                 HostingEnvironment env = ac.HostEnv;
455                 if (env == null) {
456                     return null;
457                 }
458
459                 return env.HostedAppDomain;
460             }
461         }
462
463         public AppDomain GetAppDomain(IApplicationHost appHost) {
464             if (appHost == null) {
465                 throw new ArgumentNullException("appHost");
466             }
467             string appID = CreateSimpleAppID(appHost);
468             return GetAppDomain(appID);
469         }
470
471         [SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands", Justification = "This isn't a dangerous method.")]
472         private string CreateSimpleAppID(IApplicationHost appHost) {
473             if (appHost == null) {
474                 throw new ArgumentNullException("appHost");
475             }
476             return CreateSimpleAppID(VirtualPath.Create(appHost.GetVirtualPath()),
477                                      appHost.GetPhysicalPath(), appHost.GetSiteName());
478         }
479         
480
481         // if a "well-known" object of the specified type already exists in the application,
482         // remove the app from the managed application table.  This is
483         // used in IIS7 integrated mode when IIS7 determines that it is necessary to create
484         // a new application and shutdown the old one.
485         internal void RemoveFromTableIfRuntimeExists(String appId, Type runtimeType) {
486             // check args
487             if (appId == null)
488                 throw new ArgumentNullException("appId");
489             if (runtimeType == null)
490                 throw new ArgumentNullException("runtimeType");
491
492             LockableAppDomainContext ac = GetLockableAppDomainContext(appId);
493             lock (ac) {
494                 // get hosting environment
495                 HostingEnvironment env = ac.HostEnv;
496                 if (env == null)
497                     return;
498
499                 // find the instance by type
500                 // When marshaling Type, the AppDomain must have FileIoPermission to the assembly, which is not
501                 // always the case, so we marshal the assembly qualified name instead
502                 ObjectHandle h = env.FindWellKnownObject(runtimeType.AssemblyQualifiedName);
503                 if (h != null)
504                 {
505                     // ensure that it is removed from _appDomains by calling
506                     // HostingEnvironmentShutdownInitiated directly.
507                     HostingEnvironmentShutdownInitiated(appId, env);
508                 }
509             }
510         }
511
512         [SecurityPermission(SecurityAction.Demand, Unrestricted = true)]
513         public void StopObject(String appId, Type type) {
514             // check args
515             if (appId == null)
516                 throw new ArgumentNullException("appId");
517             if (type == null)
518                 throw new ArgumentNullException("type");
519
520             LockableAppDomainContext ac = GetLockableAppDomainContext(appId);
521             lock (ac) {
522                 HostingEnvironment env = ac.HostEnv;
523                 if (env != null) {
524                     // When marshaling Type, the AppDomain must have FileIoPermission to the assembly, which is not
525                     // always the case, so we marshal the assembly qualified name instead
526                     env.StopWellKnownObject(type.AssemblyQualifiedName);
527                 }
528             }
529         }
530
531
532         public bool IsIdle() {
533             Dictionary<string, LockableAppDomainContext> apps = CloneAppDomainsCollection();
534
535             foreach (LockableAppDomainContext ac in apps.Values) {
536                 lock (ac) {
537                     HostingEnvironment env = ac.HostEnv;
538                     bool idle = (null == env) ? true : env.IsIdle();
539
540                     if (!idle)
541                         return false;
542                 }
543             }
544
545             return true;
546         }
547
548
549         [SecurityPermission(SecurityAction.Demand, Unrestricted = true)]
550         public void ShutdownApplication(String appId) {
551             if (appId == null)
552                 throw new ArgumentNullException("appId");
553
554             LockableAppDomainContext ac = GetLockableAppDomainContext(appId);
555             lock (ac) {
556                 if (ac.HostEnv != null) {
557                     ac.HostEnv.InitiateShutdownInternal();
558                 }
559             }
560         }
561
562
563         [SecurityPermission(SecurityAction.Demand, Unrestricted = true)]
564         public void ShutdownAll() {
565             _shutdownInProgress = true;
566             Dictionary <string, LockableAppDomainContext> oldTable = null;
567
568             DisposeCacheManager();
569
570             lock (this) {
571                 oldTable = _appDomains;
572                 // don't keep references to hosting environments anymore
573                 _appDomains = new Dictionary<string, LockableAppDomainContext>(StringComparer.OrdinalIgnoreCase);
574             }
575
576
577             foreach (KeyValuePair <string, LockableAppDomainContext> p in oldTable) {
578                 LockableAppDomainContext ac = p.Value;
579                 lock (ac) {
580                     HostingEnvironment env = ac.HostEnv;
581                     if (null != env) {
582                         env.InitiateShutdownInternal();
583                     }
584                 }
585             }
586         
587             for (int iter=0; _activeHostingEnvCount > 0 && iter < 3000; iter++) // Wait at most 5 minutes
588                 Thread.Sleep(100);
589         }
590
591
592         [SecurityPermission(SecurityAction.Demand, Unrestricted = true)]
593         public ApplicationInfo[] GetRunningApplications() {
594             ArrayList appList = new ArrayList();
595
596             Dictionary<string, LockableAppDomainContext> apps = CloneAppDomainsCollection();
597
598             foreach (LockableAppDomainContext ac in apps.Values) {
599                 lock (ac) {
600                     HostingEnvironment env = ac.HostEnv;
601                     if (env != null) {
602                         appList.Add(env.GetApplicationInfo());
603                     }
604                 }
605             }
606
607             int n = appList.Count;
608             ApplicationInfo[] result = new ApplicationInfo[n];
609
610             if (n > 0) {
611                 appList.CopyTo(result);
612             }
613
614             return result;
615         }
616
617         [SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands", Justification = "This method fails due to serialization issues if not called by ASP.NET.")]
618         internal AppDomainInfo [] GetAppDomainInfos()
619         {
620             ArrayList appList = new ArrayList();
621             Dictionary<string, LockableAppDomainContext> apps = CloneAppDomainsCollection();
622
623             foreach (LockableAppDomainContext ac in apps.Values) {
624                 lock (ac) {
625                     HostingEnvironment hostEnv = ac.HostEnv;
626                     if (hostEnv == null) {
627                         continue;
628                     }
629
630                     IApplicationHost appHost = hostEnv.InternalApplicationHost;
631                     ApplicationInfo appInfo = hostEnv.GetApplicationInfo();
632                     int siteId = 0;
633
634                     if (appHost != null) {
635                         try {
636                             siteId = Int32.Parse(appHost.GetSiteID(), CultureInfo.InvariantCulture);
637                         }
638                         catch {
639                         }
640                     }
641
642                     AppDomainInfo appDomainInfo = new AppDomainInfo(appInfo.ID,
643                                                       appInfo.VirtualPath,
644                                                       appInfo.PhysicalPath,
645                                                       siteId,
646                                                       hostEnv.GetIdleValue());
647
648                     appList.Add(appDomainInfo);
649                 }
650             }
651
652             return (AppDomainInfo[]) appList.ToArray(typeof(AppDomainInfo));
653         }
654
655         //
656         // APIs for the process host to suspend / resume all running applications
657         //
658
659         [SuppressMessage("Microsoft.Reliability", "CA2002:DoNotLockOnObjectsWithWeakIdentity", Justification = "'this' is never a MBRO proxy object.")]
660         internal object SuspendAllApplications() {
661             LockableAppDomainContext[] allAppDomainContexts;
662
663             lock (this) {
664                 allAppDomainContexts = _appDomains.Values.ToArray();
665             }
666
667             ApplicationResumeStateContainer[] resumeContainers = Task.WhenAll(allAppDomainContexts.Select(CreateSuspendTask)).Result;
668             return resumeContainers;
669         }
670
671         private static Task<ApplicationResumeStateContainer> _dummyCompletedSuspendTask = Task.FromResult<ApplicationResumeStateContainer>(null);
672         private static Task<ApplicationResumeStateContainer> CreateSuspendTask(LockableAppDomainContext appDomainContext) {
673             // dictionary contained a null entry?
674             if (appDomainContext == null) {
675                 return _dummyCompletedSuspendTask;
676             }
677
678             HostingEnvironment hostEnv;
679             lock (appDomainContext) {
680                 hostEnv = appDomainContext.HostEnv;
681             }
682
683             // Quick check: is this a dummy context that had no associated application?
684             if (hostEnv == null) {
685                 return _dummyCompletedSuspendTask;
686             }
687
688             // QUWI since we want to run each application's suspend method in parallel.
689             // Unsafe since we don't care about impersonation, identity, etc.
690             // Don't use Task.Run since it captures the EC and could execute inline.
691             TaskCompletionSource<ApplicationResumeStateContainer> tcs = new TaskCompletionSource<ApplicationResumeStateContainer>();
692             ThreadPool.UnsafeQueueUserWorkItem(_ => {
693
694                 // We're not locking on the appDomainContext here. The reason for this is two-fold:
695                 // a) We don't want to cause a potential deadlock issue whereby Suspend could kick
696                 //    off user code that tries calling InitiateShutdown and thus taking a lock on
697                 //    appDomainContext.
698                 // b) It's easier to try calling into the captured HostingEnvironment and just
699                 //    ---- the "no AD" exception than it is to try to synchronize the Suspend,
700                 //    Resume, and Stop methods. The CLR protects us from ourselves here.
701                 //
702                 // We need to use the captured 'hostEnv' to prevent null refs.
703
704                 IntPtr state;
705                 try {
706                     state = hostEnv.SuspendApplication();
707                 }
708                 catch (AppDomainUnloadedException) {
709                     // AD unloads aren't considered a failure
710                     tcs.TrySetResult(null);
711                     return;
712                 }
713
714                 tcs.TrySetResult(new ApplicationResumeStateContainer(hostEnv, state));
715             }, null);
716             return tcs.Task;
717         }
718
719         internal void ResumeAllApplications(object state) {
720             foreach (var resumeContainer in (ApplicationResumeStateContainer[])state) {
721                 if (resumeContainer != null) { // could be null if the application went away
722                     resumeContainer.Resume();
723                 }
724             }
725         }
726
727         //
728         // ping implementation
729         //
730
731         // called from process host
732         internal void Ping(IProcessPingCallback callback) {
733             if (callback == null || _pendingPingCallback != null)
734                 return;
735
736             // remember active callback but only if none is remembered already
737             if (Interlocked.CompareExchange(ref _pendingPingCallback, callback, null) == null) {
738                 // queue a work item to respond to ping
739                 ThreadPool.QueueUserWorkItem(_onRespondToPingWaitCallback);
740             }
741         }
742
743         // threadpool callback (also called on some activity from hosting environment)
744         internal void OnRespondToPingWaitCallback(Object state) {
745             RespondToPingIfNeeded();
746         }
747
748         // respond to ping on callback
749         internal void RespondToPingIfNeeded() {
750             IProcessPingCallback callback = _pendingPingCallback as IProcessPingCallback;
751
752             // make sure we call the callback once
753             if (callback != null) {
754                 if (Interlocked.CompareExchange(ref _pendingPingCallback, null, callback) == callback) {
755                     callback.Respond();
756                 }
757             }
758         }
759
760         // ApplicationManager is loaded into the default AppDomain
761         // ASP.NET doesn't set string hash randomization for the defaul AppDomain, so we can assume the existing CLR implementation here is unchanged
762         // Note, it won't work if <runtime/UseRandomizedStringHashAlgorithm enabled="1"> is used, because the entire process is subject to string hash randomization
763         internal int GetNonRandomizedStringComparerHashCode(string s, bool ignoreCase) { 
764             StringComparer comparer = ignoreCase ? StringComparer.InvariantCultureIgnoreCase : StringComparer.InvariantCulture;
765             return comparer.GetHashCode(s);
766         }
767
768         //
769         // communication with hosting environments
770         //
771
772         internal void HostingEnvironmentActivated(long privateBytesLimit) {
773             int count = Interlocked.Increment(ref _activeHostingEnvCount);
774             
775             // initialize CacheManager once, without blocking
776             if (count == 1) {
777                 InitCacheManager(privateBytesLimit);
778             }
779         }
780
781         internal void HostingEnvironmentShutdownComplete(String appId, IApplicationHost appHost) {
782             try {
783                 if (appHost != null) {
784                     // make sure application host can be GC'd
785                     MarshalByRefObject realApplicationHost = appHost as MarshalByRefObject;
786                     if (realApplicationHost != null) {
787                         RemotingServices.Disconnect(realApplicationHost);
788                     }
789                 }
790             }
791             finally {
792                 Interlocked.Decrement(ref _activeHostingEnvCount);
793             }
794         }
795
796         internal void HostingEnvironmentShutdownInitiated(String appId, HostingEnvironment env) {
797             if (!_shutdownInProgress) { // don't bother during shutdown (while enumerating)
798                 LockableAppDomainContext ac = GetLockableAppDomainContext (appId);
799
800                 lock (ac){
801                     if (!env.HasBeenRemovedFromAppManagerTable) {
802                         env.HasBeenRemovedFromAppManagerTable = true;
803
804                         ac.HostEnv = null;
805                         Interlocked.Decrement(ref _accessibleHostingEnvCount);
806
807                         // Autorestart the application right away
808                         if (ac.PreloadContext != null && !ac.RetryingPreload) {
809                             ProcessHost.PreloadApplicationIfNotShuttingdown(appId, ac);
810                         }
811                     }
812                 }
813             }
814         }
815
816         internal int AppDomainsCount {
817             get { return _accessibleHostingEnvCount; }
818         }
819
820
821         internal void ReduceAppDomainsCount(int limit) {
822             // 
823
824
825
826
827             Dictionary<string, LockableAppDomainContext> apps = CloneAppDomainsCollection();
828             while (_accessibleHostingEnvCount >= limit && !_shutdownInProgress)
829             {
830                 LockableAppDomainContext bestCandidateForShutdown = null;
831                 int bestCandidateLruScore = 0;
832                 
833                 foreach (LockableAppDomainContext ac in apps.Values) {
834                     // Don't lock on LockableAppDomainContext before we check that ac.HostEnv != null.
835                     // Otherwise we may end up with a deadlock between 2 app domains trying to unload each other
836                     HostingEnvironment h = ac.HostEnv;
837                     if (h == null) {
838                         continue;
839                     }
840                     lock (ac) {
841                         h = ac.HostEnv;
842
843                         // Avoid ---- by checking again under lock
844                         if (h == null) {
845                             continue;
846                         }
847                         int newLruScore = h.LruScore;
848
849                         if (bestCandidateForShutdown == null || bestCandidateForShutdown.HostEnv == null || 
850                                 newLruScore < bestCandidateLruScore) {
851
852                             bestCandidateLruScore = newLruScore;
853                             bestCandidateForShutdown = ac;
854                         }
855                     }
856                 }
857
858                 if (bestCandidateForShutdown == null)
859                     break;
860
861                 lock (bestCandidateForShutdown) {
862                     if (bestCandidateForShutdown.HostEnv != null) {
863                         bestCandidateForShutdown.HostEnv.InitiateShutdownInternal();
864                     }
865                 }
866             }
867         }
868
869         //
870         // helper to support legacy APIs (AppHost.CreateAppHost)
871         //
872
873         internal ObjectHandle CreateInstanceInNewWorkerAppDomain(
874                                 Type type,
875                                 String appId,
876                                 VirtualPath virtualPath,
877                                 String physicalPath) {
878
879             Debug.Trace("AppManager", "CreateObjectInNewWorkerAppDomain, type=" + type.FullName);
880
881             IApplicationHost appHost = new SimpleApplicationHost(virtualPath, physicalPath);
882
883             HostingEnvironmentParameters hostingParameters = new HostingEnvironmentParameters();
884             hostingParameters.HostingFlags = HostingEnvironmentFlags.HideFromAppManager;
885
886             HostingEnvironment env = CreateAppDomainWithHostingEnvironmentAndReportErrors(appId, appHost, hostingParameters);
887             // When marshaling Type, the AppDomain must have FileIoPermission to the assembly, which is not
888             // always the case, so we marshal the assembly qualified name instead
889             return env.CreateInstance(type.AssemblyQualifiedName);
890         }
891
892         //
893         // helpers to facilitate app domain creation
894         //
895         private HostingEnvironment GetAppDomainWithHostingEnvironment(String appId, IApplicationHost appHost, HostingEnvironmentParameters hostingParameters) {
896             LockableAppDomainContext ac = GetLockableAppDomainContext (appId);
897
898             lock (ac) {
899                 HostingEnvironment env = ac.HostEnv;
900
901                 if (env != null) {
902                     try {
903                         env.IsUnloaded();
904                     } catch(AppDomainUnloadedException) {
905                         env = null;
906                     }
907                 }
908                 if (env == null) {
909                     env = CreateAppDomainWithHostingEnvironmentAndReportErrors(appId, appHost, hostingParameters);
910                     ac.HostEnv = env;
911                     Interlocked.Increment(ref _accessibleHostingEnvCount);
912                 }
913
914                 return env;
915             }
916            
917         }
918
919         private HostingEnvironment CreateAppDomainWithHostingEnvironmentAndReportErrors(
920                                         String appId,
921                                         IApplicationHost appHost,
922                                         HostingEnvironmentParameters hostingParameters) {
923             try {
924                 return CreateAppDomainWithHostingEnvironment(appId, appHost, hostingParameters);
925             }
926             catch (Exception e) {
927                 Misc.ReportUnhandledException(e, new string[] {SR.GetString(SR.Failed_to_initialize_AppDomain), appId});
928                 throw;
929             }
930         }
931
932         [SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands", Justification = "We carefully control the callers.")]
933         [SuppressMessage("Microsoft.Usage", "CA1806:DoNotIgnoreMethodResults", MessageId = "System.Boolean.TryParse(System.String,System.Boolean@)", Justification = "Sets parameter to default(bool) on conversion failure, which is semantic we need.")]
934         private HostingEnvironment CreateAppDomainWithHostingEnvironment(
935                                                 String appId,
936                                                 IApplicationHost appHost,
937                                                 HostingEnvironmentParameters hostingParameters) {
938
939             String physicalPath = appHost.GetPhysicalPath();
940             if (!StringUtil.StringEndsWith(physicalPath, Path.DirectorySeparatorChar))
941                 physicalPath = physicalPath + Path.DirectorySeparatorChar;
942
943             String domainId = ConstructAppDomainId(appId);
944             String appName = (StringUtil.GetStringHashCode(String.Concat(appId.ToLower(CultureInfo.InvariantCulture),
945                 physicalPath.ToLower(CultureInfo.InvariantCulture)))).ToString("x", CultureInfo.InvariantCulture);
946             VirtualPath virtualPath = VirtualPath.Create(appHost.GetVirtualPath());
947
948             Debug.Trace("AppManager", "CreateAppDomainWithHostingEnvironment, path=" + physicalPath + "; appId=" + appId + "; domainId=" + domainId);
949
950             IDictionary bindings = new Hashtable(20);
951             AppDomainSetup setup = new AppDomainSetup();
952             AppDomainSwitches switches = new AppDomainSwitches();
953             PopulateDomainBindings(domainId, appId, appName, physicalPath, virtualPath, setup, bindings);
954
955             //  Create the app domain
956
957             AppDomain appDomain = null;
958             Dictionary<string, object> appDomainAdditionalData = new Dictionary<string, object>();
959             Exception appDomainCreationException = null;
960
961             string siteID = appHost.GetSiteID();
962             string appSegment = virtualPath.VirtualPathStringNoTrailingSlash;
963             bool inClientBuildManager = false;
964             Configuration appConfig = null;
965             PolicyLevel policyLevel = null;
966             PermissionSet permissionSet = null;
967             List<StrongName> fullTrustAssemblies = new List<StrongName>();
968             string[] defaultPartialTrustVisibleAssemblies = new[] { "System.Web, PublicKey=002400000480000094000000060200000024000052534131000400000100010007d1fa57c4aed9f0a32e84aa0faefd0de9e8fd6aec8f87fb03766c834c99921eb23be79ad9d5dcc1dd9ad236132102900b723cf980957fc4e177108fc607774f29e8320e92ea05ece4e821c0a5efe8f1645c4c0c93c1ab99285d622caa652c1dfad63d745d6f2de5f17e5eaf0fc4963d261c8a12436518206dc093344d5ad293",
969                                                                     "System.Web.Extensions, PublicKey=0024000004800000940000000602000000240000525341310004000001000100b5fc90e7027f67871e773a8fde8938c81dd402ba65b9201d60593e96c492651e889cc13f1415ebb53fac1131ae0bd333c5ee6021672d9718ea31a8aebd0da0072f25d87dba6fc90ffd598ed4da35e44c398c454307e8e33b8426143daec9f596836f97c8f74750e5975c64e2189f45def46b2a2b1247adc3652bf5c308055da9",
970                                                                     "System.Web.Abstractions, PublicKey=0024000004800000940000000602000000240000525341310004000001000100b5fc90e7027f67871e773a8fde8938c81dd402ba65b9201d60593e96c492651e889cc13f1415ebb53fac1131ae0bd333c5ee6021672d9718ea31a8aebd0da0072f25d87dba6fc90ffd598ed4da35e44c398c454307e8e33b8426143daec9f596836f97c8f74750e5975c64e2189f45def46b2a2b1247adc3652bf5c308055da9",
971                                                                     "System.Web.Routing, PublicKey=0024000004800000940000000602000000240000525341310004000001000100b5fc90e7027f67871e773a8fde8938c81dd402ba65b9201d60593e96c492651e889cc13f1415ebb53fac1131ae0bd333c5ee6021672d9718ea31a8aebd0da0072f25d87dba6fc90ffd598ed4da35e44c398c454307e8e33b8426143daec9f596836f97c8f74750e5975c64e2189f45def46b2a2b1247adc3652bf5c308055da9",
972                                                                     "System.Web.DynamicData, PublicKey=0024000004800000940000000602000000240000525341310004000001000100b5fc90e7027f67871e773a8fde8938c81dd402ba65b9201d60593e96c492651e889cc13f1415ebb53fac1131ae0bd333c5ee6021672d9718ea31a8aebd0da0072f25d87dba6fc90ffd598ed4da35e44c398c454307e8e33b8426143daec9f596836f97c8f74750e5975c64e2189f45def46b2a2b1247adc3652bf5c308055da9",
973                                                                     "System.Web.DataVisualization, PublicKey=0024000004800000940000000602000000240000525341310004000001000100b5fc90e7027f67871e773a8fde8938c81dd402ba65b9201d60593e96c492651e889cc13f1415ebb53fac1131ae0bd333c5ee6021672d9718ea31a8aebd0da0072f25d87dba6fc90ffd598ed4da35e44c398c454307e8e33b8426143daec9f596836f97c8f74750e5975c64e2189f45def46b2a2b1247adc3652bf5c308055da9",
974                                                                     "System.Web.ApplicationServices, PublicKey=0024000004800000940000000602000000240000525341310004000001000100b5fc90e7027f67871e773a8fde8938c81dd402ba65b9201d60593e96c492651e889cc13f1415ebb53fac1131ae0bd333c5ee6021672d9718ea31a8aebd0da0072f25d87dba6fc90ffd598ed4da35e44c398c454307e8e33b8426143daec9f596836f97c8f74750e5975c64e2189f45def46b2a2b1247adc3652bf5c308055da9" };
975
976             Exception appDomainStartupConfigurationException = null;
977             ImpersonationContext ictxConfig = null;
978             IntPtr uncTokenConfig = IntPtr.Zero;
979             HostingEnvironmentFlags hostingFlags = HostingEnvironmentFlags.Default;
980             if (hostingParameters != null) {
981                 hostingFlags = hostingParameters.HostingFlags;
982                 if ((hostingFlags & HostingEnvironmentFlags.ClientBuildManager) != 0) {
983                     inClientBuildManager = true;
984                     // The default hosting policy in VS has changed (from MultiDomainHost to MultiDomain), 
985                     // so we need to specify explicitly to allow generated assemblies 
986                     // to be unloaded subsequently. (Dev10 bug)
987                     setup.LoaderOptimization = LoaderOptimization.MultiDomainHost;
988                 }
989             }
990             try {
991                 bool requireHostExecutionContextManager = false;
992                 bool requireHostSecurityManager = false;
993
994                 uncTokenConfig = appHost.GetConfigToken();
995                 if (uncTokenConfig != IntPtr.Zero) {
996                     ictxConfig = new ImpersonationContext(uncTokenConfig);
997                 }
998
999                 try {
1000                     // Did the custom loader fail to load?
1001                     ExceptionDispatchInfo customLoaderException = ProcessHost.GetExistingCustomLoaderFailureAndClear(appId);
1002                     if (customLoaderException != null) {
1003                         customLoaderException.Throw();
1004                     }
1005
1006                     // We support randomized string hash code, but not for the default AppDomain
1007                     // Don't allow string hash randomization for the defaul AppDomain (i.e. <runtime/UseRandomizedStringHashAlgorithm enabled="1">)
1008                     // Application should use AppSettings instead to opt-in.
1009                     if (EnvironmentInfo.IsStringHashCodeRandomizationDetected) {
1010                         throw new ConfigurationErrorsException(SR.GetString(SR.Require_stable_string_hash_codes));
1011                     }
1012
1013                     bool skipAdditionalConfigChecks = false;
1014                     if (inClientBuildManager && hostingParameters.IISExpressVersion != null) {
1015                         permissionSet = new PermissionSet(PermissionState.Unrestricted);
1016                         setup.PartialTrustVisibleAssemblies = defaultPartialTrustVisibleAssemblies;
1017                         appConfig = GetAppConfigIISExpress(siteID, appSegment, hostingParameters.IISExpressVersion);
1018                         skipAdditionalConfigChecks = true;
1019                     }
1020                     else {
1021                         //Hosted by IIS, we already have an IISMap.
1022                         if (appHost is ISAPIApplicationHost) {
1023                             string cacheKey = System.Web.Caching.CacheInternal.PrefixMapPath + siteID + virtualPath.VirtualPathString;
1024                             MapPathCacheInfo cacheInfo = (MapPathCacheInfo)HttpRuntime.CacheInternal.Remove(cacheKey);
1025                             appConfig = WebConfigurationManager.OpenWebConfiguration(appSegment, siteID);
1026                         }
1027                         // For non-IIS hosting scenarios, we need to get config map from application host in a generic way.
1028                         else {
1029                             appConfig = GetAppConfigGeneric(appHost, siteID, appSegment, virtualPath, physicalPath);
1030                         }
1031                     }
1032
1033                     HttpRuntimeSection httpRuntimeSection = (HttpRuntimeSection)appConfig.GetSection("system.web/httpRuntime");
1034                     if (httpRuntimeSection == null) {
1035                         throw new ConfigurationErrorsException(SR.GetString(SR.Config_section_not_present, "httpRuntime"));
1036                     }
1037
1038                     // DevDiv #403846 - Change certain config defaults if <httpRuntime targetFramework="4.5" /> exists in config.
1039                     // We store this information in the AppDomain data because certain configuration sections (like <compilation>)
1040                     // are loaded before config is "baked" in the child AppDomain, and if we make <compilation> and other sections
1041                     // dependent on <httpRuntime> which may not have been loaded yet, we risk introducing ----s. Putting this value
1042                     // in the AppDomain data guarantees that it is available before the first call to the config system.
1043                     FrameworkName targetFrameworkName = httpRuntimeSection.GetTargetFrameworkName();
1044                     if (targetFrameworkName != null) {
1045                         appDomainAdditionalData[System.Web.Util.BinaryCompatibility.TargetFrameworkKey] = targetFrameworkName;
1046                     }
1047
1048                     if (!skipAdditionalConfigChecks) {
1049                         // DevDiv #71268 - Add <httpRuntime defaultRegexMatchTimeout="HH:MM:SS" /> configuration attribute
1050                         if (httpRuntimeSection.DefaultRegexMatchTimeout != TimeSpan.Zero) {
1051                             appDomainAdditionalData[_regexMatchTimeoutKey] = httpRuntimeSection.DefaultRegexMatchTimeout;
1052                         }
1053
1054                         // DevDiv #258274 - Add support for CLR quirks mode to ASP.NET
1055                         if (targetFrameworkName != null) {
1056                             setup.TargetFrameworkName = targetFrameworkName.ToString();
1057                         }
1058
1059                         // DevDiv #286354 - Having a Task-friendly SynchronizationContext requires overriding the AppDomain's HostExecutionContextManager.
1060                         // DevDiv #403846 - If we can't parse the <appSettings> switch, use the <httpRuntime/targetFramework> setting to determine the default.
1061                         AppSettingsSection appSettingsSection = appConfig.AppSettings;
1062                         KeyValueConfigurationElement useTaskFriendlySynchronizationContextElement = appSettingsSection.Settings["aspnet:UseTaskFriendlySynchronizationContext"];
1063                         if (!(useTaskFriendlySynchronizationContextElement != null && Boolean.TryParse(useTaskFriendlySynchronizationContextElement.Value, out requireHostExecutionContextManager))) {
1064                             requireHostExecutionContextManager = new System.Web.Util.BinaryCompatibility(targetFrameworkName).TargetsAtLeastFramework45 ? true : false;
1065                         }
1066
1067                         // DevDiv #390704 - Add support for randomized string hash algorithm
1068                         KeyValueConfigurationElement useRandomizedStringHashAlgorithmElement = appSettingsSection.Settings["aspnet:UseRandomizedStringHashAlgorithm"];
1069                         bool useRandomizedStringHashAlgorithm = false;
1070                         if (useRandomizedStringHashAlgorithmElement != null && Boolean.TryParse(useRandomizedStringHashAlgorithmElement.Value, out useRandomizedStringHashAlgorithm)) {
1071                             switches.UseRandomizedStringHashAlgorithm = useRandomizedStringHashAlgorithm;
1072                         }
1073
1074                         // DevDiv #1041102 - Allow specifying quirks via <appSettings> switches
1075                         // The keys must begin with "AppContext.SetSwitch" and have a non-zero key name length,
1076                         // and the values must be parseable as Booleans.
1077                         Dictionary<string, bool> clrQuirks = null;
1078                         foreach (KeyValueConfigurationElement element in appSettingsSection.Settings) {
1079                             if (element.Key != null && element.Key.Length > _clrQuirkAppSettingsAppContextPrefix.Length && element.Key.StartsWith(_clrQuirkAppSettingsAppContextPrefix, StringComparison.OrdinalIgnoreCase)) {
1080                                 bool value;
1081                                 if (Boolean.TryParse(element.Value, out value)) {
1082                                     if (clrQuirks == null) {
1083                                         clrQuirks = new Dictionary<string, bool>();
1084                                     }
1085                                     
1086                                     clrQuirks[element.Key.Substring(_clrQuirkAppSettingsAppContextPrefix.Length)] = value;
1087                                 }
1088                             }
1089                         }
1090                         
1091                         if (clrQuirks != null && clrQuirks.Count > 0) {
1092                             if (hostingParameters == null) {
1093                                 hostingParameters = new HostingEnvironmentParameters();
1094                             }
1095                             
1096                             hostingParameters.ClrQuirksSwitches = clrQuirks.ToArray();
1097                         }
1098
1099                         // DevDiv #248126 - Allow configuration of FileChangeMonitor behavior
1100                         if (httpRuntimeSection.FcnMode != FcnMode.NotSet) {
1101                             if (hostingParameters == null) {
1102                                 hostingParameters = new HostingEnvironmentParameters();
1103                             }
1104                             hostingParameters.FcnMode = httpRuntimeSection.FcnMode;
1105                         }
1106
1107                         // DevDiv #322858 - Allow FileChangesMonitor to skip reading DACLs as a perf improvement
1108                         KeyValueConfigurationElement disableFcnDaclReadElement = appSettingsSection.Settings["aspnet:DisableFcnDaclRead"];
1109                         if (disableFcnDaclReadElement != null) {
1110                             bool skipReadingAndCachingDacls;
1111                             Boolean.TryParse(disableFcnDaclReadElement.Value, out skipReadingAndCachingDacls);
1112                             if (skipReadingAndCachingDacls) {
1113                                 if (hostingParameters == null) {
1114                                     hostingParameters = new HostingEnvironmentParameters();
1115                                 }
1116                                 hostingParameters.FcnSkipReadAndCacheDacls = true;
1117                             }
1118                         }
1119
1120                         // If we were launched from a development environment, we might want to enable the application to do things
1121                         // it otherwise wouldn't normally allow, such as enabling an administrative control panel. For security reasons,
1122                         // we only do this check if <deployment retail="false" /> [the default value] is specified, since the
1123                         // <deployment> element can only be set at machine-level in a hosted environment.
1124                         DeploymentSection deploymentSection = (DeploymentSection)appConfig.GetSection("system.web/deployment");
1125                         bool isDevEnvironment = false;
1126                         if (deploymentSection != null && !deploymentSection.Retail && EnvironmentInfo.WasLaunchedFromDevelopmentEnvironment) {
1127                             appDomainAdditionalData[".devEnvironment"] = true;
1128                             isDevEnvironment = true;
1129
1130                             // DevDiv #275724 - Allow LocalDB support in partial trust scenarios
1131                             // Normally LocalDB requires full trust since it's the equivalent of unmanaged code execution. If this is
1132                             // a development environment and not a retail deployment, we can assume that the user developing the
1133                             // application is actually in charge of the host, so we can trust him with LocalDB execution.
1134                             // Technically this also means that the developer could have set <trust level="Full" /> in his application,
1135                             // but he might want to deploy his application on a Medium-trust server and thus test how the rest of his
1136                             // application works in a partial trust environment. (He would use SQL in production, whch is safe in
1137                             // partial trust.)
1138                             appDomainAdditionalData["ALLOW_LOCALDB_IN_PARTIAL_TRUST"] = true;
1139                         }
1140
1141                         TrustSection trustSection = (TrustSection)appConfig.GetSection("system.web/trust");
1142                         if (trustSection == null || String.IsNullOrEmpty(trustSection.Level)) {
1143                             throw new ConfigurationErrorsException(SR.GetString(SR.Config_section_not_present, "trust"));
1144                         }
1145
1146                         switches.UseLegacyCas = trustSection.LegacyCasModel;
1147
1148                         if (inClientBuildManager) {
1149                             permissionSet = new PermissionSet(PermissionState.Unrestricted);
1150                             setup.PartialTrustVisibleAssemblies = defaultPartialTrustVisibleAssemblies;
1151                         }
1152                         else {
1153                             if (!switches.UseLegacyCas) {
1154                                 if (trustSection.Level == "Full") {
1155                                     permissionSet = new PermissionSet(PermissionState.Unrestricted);
1156                                     setup.PartialTrustVisibleAssemblies = defaultPartialTrustVisibleAssemblies;
1157                                 }
1158                                 else {
1159                                     SecurityPolicySection securityPolicySection = (SecurityPolicySection)appConfig.GetSection("system.web/securityPolicy");
1160                                     CompilationSection compilationSection = (CompilationSection)appConfig.GetSection("system.web/compilation");
1161                                     FullTrustAssembliesSection fullTrustAssembliesSection = (FullTrustAssembliesSection)appConfig.GetSection("system.web/fullTrustAssemblies");
1162                                     policyLevel = GetPartialTrustPolicyLevel(trustSection, securityPolicySection, compilationSection, physicalPath, virtualPath, isDevEnvironment);
1163                                     permissionSet = policyLevel.GetNamedPermissionSet(trustSection.PermissionSetName);
1164                                     if (permissionSet == null) {
1165                                         throw new ConfigurationErrorsException(SR.GetString(SR.Permission_set_not_found, trustSection.PermissionSetName));
1166                                     }
1167
1168                                     // read full trust assemblies and populate the strong name list
1169                                     if (fullTrustAssembliesSection != null) {
1170                                         FullTrustAssemblyCollection fullTrustAssembliesCollection = fullTrustAssembliesSection.FullTrustAssemblies;
1171                                         if (fullTrustAssembliesCollection != null) {
1172                                             fullTrustAssemblies.AddRange(from FullTrustAssembly fta in fullTrustAssembliesCollection
1173                                                                          select CreateStrongName(fta.AssemblyName, fta.Version, fta.PublicKey));
1174                                         }
1175                                     }
1176
1177                                     // DevDiv #27645 - We need to add future versions of Microsoft.Web.Infrastructure to <fullTrustAssemblies> so that ASP.NET
1178                                     // can version out-of-band releases. We should only do this if V1 of M.W.I is listed.
1179                                     if (fullTrustAssemblies.Contains(_mwiV1StrongName)) {
1180                                         fullTrustAssemblies.AddRange(CreateFutureMicrosoftWebInfrastructureStrongNames());
1181                                     }
1182
1183                                     // Partial-trust AppDomains using a non-legacy CAS model require our special HostSecurityManager
1184                                     requireHostSecurityManager = true;
1185                                 }
1186                             }
1187                             if (trustSection.Level != "Full") {
1188                                 PartialTrustVisibleAssembliesSection partialTrustVisibleAssembliesSection = (PartialTrustVisibleAssembliesSection)appConfig.GetSection("system.web/partialTrustVisibleAssemblies");
1189                                 string[] partialTrustVisibleAssemblies = null;
1190                                 if (partialTrustVisibleAssembliesSection != null) {
1191                                     PartialTrustVisibleAssemblyCollection partialTrustVisibleAssembliesCollection = partialTrustVisibleAssembliesSection.PartialTrustVisibleAssemblies;
1192                                     if (partialTrustVisibleAssembliesCollection != null && partialTrustVisibleAssembliesCollection.Count != 0) {
1193                                         partialTrustVisibleAssemblies = new string[partialTrustVisibleAssembliesCollection.Count + defaultPartialTrustVisibleAssemblies.Length];
1194                                         for (int i = 0; i < partialTrustVisibleAssembliesCollection.Count; i++) {
1195                                             partialTrustVisibleAssemblies[i] = partialTrustVisibleAssembliesCollection[i].AssemblyName +
1196                                                 ", PublicKey=" +
1197                                                 NormalizePublicKeyBlob(partialTrustVisibleAssembliesCollection[i].PublicKey);
1198                                         }
1199                                         defaultPartialTrustVisibleAssemblies.CopyTo(partialTrustVisibleAssemblies, partialTrustVisibleAssembliesCollection.Count);
1200                                     }
1201                                 }
1202                                 if (partialTrustVisibleAssemblies == null) {
1203                                     partialTrustVisibleAssemblies = defaultPartialTrustVisibleAssemblies;
1204                                 }
1205                                 setup.PartialTrustVisibleAssemblies = partialTrustVisibleAssemblies;
1206                             }
1207                         }
1208                     }
1209                 }
1210                 catch (Exception e) {
1211                     appDomainStartupConfigurationException = e;
1212                     permissionSet = new PermissionSet(PermissionState.Unrestricted);
1213                 }
1214
1215                 // Set the AppDomainManager if needed
1216                 Type appDomainManagerType = AspNetAppDomainManager.GetAspNetAppDomainManagerType(requireHostExecutionContextManager, requireHostSecurityManager);
1217                 if (appDomainManagerType != null) {
1218                     setup.AppDomainManagerType = appDomainManagerType.FullName;
1219                     setup.AppDomainManagerAssembly = appDomainManagerType.Assembly.FullName;
1220                 }
1221
1222                 // Apply compatibility switches
1223                 switches.Apply(setup);
1224
1225                 try {
1226                     if (switches.UseLegacyCas) {
1227                         appDomain = AppDomain.CreateDomain(domainId,
1228 #if FEATURE_PAL // FEATURE_PAL: hack to avoid non-supported hosting features
1229                                                            null,
1230 #else // FEATURE_PAL
1231 GetDefaultDomainIdentity(),
1232 #endif // FEATURE_PAL
1233 setup);
1234                     }
1235                     else {
1236                         appDomain = AppDomain.CreateDomain(domainId,
1237 #if FEATURE_PAL // FEATURE_PAL: hack to avoid non-supported hosting features
1238                                                            null,
1239 #else // FEATURE_PAL
1240 GetDefaultDomainIdentity(),
1241 #endif // FEATURE_PAL
1242 setup,
1243                                                            permissionSet,
1244                                                            fullTrustAssemblies.ToArray() /* fully trusted assemblies list: empty list means only trust GAC assemblies */);
1245                     }
1246                     foreach (DictionaryEntry e in bindings)
1247                         appDomain.SetData((String)e.Key, (String)e.Value);
1248                     foreach (var entry in appDomainAdditionalData)
1249                         appDomain.SetData(entry.Key, entry.Value);
1250                 }
1251                 catch (Exception e) {
1252                     Debug.Trace("AppManager", "AppDomain.CreateDomain failed", e);
1253                     appDomainCreationException = e;
1254                 }
1255             }
1256             finally {
1257                 if (ictxConfig != null) {
1258                     ictxConfig.Undo();
1259                     ictxConfig = null;
1260                 }
1261                 if (uncTokenConfig != IntPtr.Zero) {
1262                     UnsafeNativeMethods.CloseHandle(uncTokenConfig);
1263                     uncTokenConfig = IntPtr.Zero;
1264                 }
1265             }
1266
1267             if (appDomain == null) {
1268                 throw new SystemException(SR.GetString(SR.Cannot_create_AppDomain), appDomainCreationException);
1269             }
1270
1271             // Create hosting environment in the new app domain
1272
1273             Type hostType = typeof(HostingEnvironment);
1274             String module = hostType.Module.Assembly.FullName;
1275             String typeName = hostType.FullName;
1276             ObjectHandle h = null;
1277
1278             // impersonate UNC identity, if any
1279             ImpersonationContext ictx = null;
1280             IntPtr uncToken = IntPtr.Zero;
1281
1282             //
1283             // fetching config can fail due to a ---- with the 
1284             // native config reader
1285             // if that has happened, force a flush
1286             //
1287             int maxRetries = 10;
1288             int numRetries = 0;
1289
1290             while (numRetries < maxRetries) {
1291                 try {
1292                     uncToken = appHost.GetConfigToken();
1293                     // no throw, so break
1294                     break;
1295                 }
1296                 catch (InvalidOperationException) {
1297                     numRetries++;
1298                     System.Threading.Thread.Sleep(250);
1299                 }
1300             }
1301
1302
1303             if (uncToken != IntPtr.Zero) {
1304                 try {
1305                     ictx = new ImpersonationContext(uncToken);
1306                 }
1307                 catch {
1308                 }
1309                 finally {
1310                     UnsafeNativeMethods.CloseHandle(uncToken);
1311                 }
1312             }
1313
1314             try {
1315
1316                 // Create the hosting environment in the app domain
1317 #if DBG
1318                 try {
1319                     h = Activator.CreateInstance(appDomain, module, typeName);
1320                 }
1321                 catch (Exception e) {
1322                     Debug.Trace("AppManager", "appDomain.CreateInstance failed; identity=" + System.Security.Principal.WindowsIdentity.GetCurrent().Name, e);
1323                     throw;
1324                 }
1325 #else
1326                 h = Activator.CreateInstance(appDomain, module, typeName);
1327 #endif
1328             }
1329             finally {
1330                 // revert impersonation
1331                 if (ictx != null)
1332                     ictx.Undo();
1333
1334                 if (h == null) {
1335                     AppDomain.Unload(appDomain);
1336                 }
1337             }
1338
1339             HostingEnvironment env = (h != null) ? h.Unwrap() as HostingEnvironment : null;
1340
1341             if (env == null)
1342                 throw new SystemException(SR.GetString(SR.Cannot_create_HostEnv));
1343
1344             // initialize the hosting environment
1345             IConfigMapPathFactory configMapPathFactory = appHost.GetConfigMapPathFactory();
1346             if (appDomainStartupConfigurationException == null) {
1347                 env.Initialize(this, appHost, configMapPathFactory, hostingParameters, policyLevel);
1348             }
1349             else {
1350                 env.Initialize(this, appHost, configMapPathFactory, hostingParameters, policyLevel, appDomainStartupConfigurationException);
1351             }
1352             return env;
1353         }
1354
1355         private static string NormalizePublicKeyBlob(string publicKey) {
1356             StringBuilder sb = new StringBuilder();
1357             for (int i = 0; i < publicKey.Length; i++) {
1358                 if (!Char.IsWhiteSpace(publicKey[i])) {
1359                     sb.Append(publicKey[i]);
1360                 }
1361             }
1362             publicKey = sb.ToString();
1363             return publicKey;
1364         }
1365
1366         private static StrongName CreateStrongName(string assemblyName, string version, string publicKeyString) {
1367             byte[] publicKey = null;
1368             StrongName strongName = null;
1369             publicKeyString = NormalizePublicKeyBlob(publicKeyString);
1370             int publicKeySize = publicKeyString.Length / 2;
1371             publicKey = new byte[publicKeySize];
1372             for (int i = 0; i < publicKeySize; i++) {
1373                 publicKey[i] = Byte.Parse(publicKeyString.Substring(i * 2, 2), System.Globalization.NumberStyles.HexNumber, CultureInfo.InvariantCulture);
1374             }
1375             StrongNamePublicKeyBlob keyBlob = new StrongNamePublicKeyBlob(publicKey);
1376             strongName = new StrongName(keyBlob, assemblyName, new Version(version));
1377             return strongName;
1378         }
1379
1380         // For various reasons, we can't add any entries to the <fullTrustAssemblies> list until .NET 5, which at the time of this writing is a few
1381         // years out. But since ASP.NET releases projects out-of-band from the .NET Framework as a whole (using Microsoft.Web.Infrasturcture), we
1382         // need to be sure that future versions of M.W.I have the ability to assert full trust. This code works by seeing if M.W.I v1 is in the
1383         // <fullTrustAssemblies> list, and if it is then v2 - v10 are implicitly added. If v1 is not present in the <fTA> list, then we'll not
1384         // treat v2 - v10 as implicitly added. See DevDiv #27645 for more information.
1385
1386         private static StrongName GetMicrosoftWebInfrastructureV1StrongName() {
1387             return CreateStrongName(
1388                     assemblyName: "Microsoft.Web.Infrastructure",
1389                     version: "1.0.0.0",
1390                     publicKeyString: "0024000004800000940000000602000000240000525341310004000001000100B5FC90E7027F67871E773A8FDE8938C81DD402BA65B9201D60593E96C492651E889CC13F1415EBB53FAC1131AE0BD333C5EE6021672D9718EA31A8AEBD0DA0072F25D87DBA6FC90FFD598ED4DA35E44C398C454307E8E33B8426143DAEC9F596836F97C8F74750E5975C64E2189F45DEF46B2A2B1247ADC3652BF5C308055DA9");
1391         }
1392
1393         private static IEnumerable<StrongName> CreateFutureMicrosoftWebInfrastructureStrongNames() {
1394             string asmName = _mwiV1StrongName.Name;
1395             StrongNamePublicKeyBlob publicKey = _mwiV1StrongName.PublicKey;
1396             for (int i = 2; i <= 10; i++) {
1397                 yield return new StrongName(publicKey, asmName, new Version(i, 0, 0, 0));
1398             }
1399         }
1400
1401
1402          // devdiv 1038337: execution permission cannot be acquired under partial trust with ctrl-f5.
1403          // We build the codegen path in default domain. In order to build the right path, 
1404          // caller must pass in a flag indicating whether it is under dev environment.
1405         [SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands", Justification = "We carefully control this method's caller.")]
1406         private static PolicyLevel GetPartialTrustPolicyLevel(
1407                 TrustSection trustSection, SecurityPolicySection securityPolicySection,
1408                 CompilationSection compilationSection, string physicalPath, VirtualPath virtualPath, bool isDevEnvironment) {
1409             if (securityPolicySection == null || securityPolicySection.TrustLevels[trustSection.Level] == null) {
1410                 throw new ConfigurationErrorsException(SR.GetString(SR.Unable_to_get_policy_file, trustSection.Level), String.Empty, 0);
1411             }
1412             String configFile = (String)securityPolicySection.TrustLevels[trustSection.Level].PolicyFileExpanded;
1413             if (configFile == null || !FileUtil.FileExists(configFile)) {
1414                 throw new HttpException(SR.GetString(SR.Unable_to_get_policy_file, trustSection.Level));
1415             }
1416             PolicyLevel policyLevel = null;
1417             String appDir = FileUtil.RemoveTrailingDirectoryBackSlash(physicalPath);
1418             String appDirUrl = HttpRuntime.MakeFileUrl(appDir);
1419
1420             // setup $CodeGen$ replacement
1421             string tempDirectory = null;
1422             // These variables are used for error handling
1423             string tempDirAttribName = null;
1424             string configFileName = null;
1425             int configLineNumber = 0;
1426             if (compilationSection != null && !String.IsNullOrEmpty(compilationSection.TempDirectory)) {
1427                 tempDirectory = compilationSection.TempDirectory;
1428                 compilationSection.GetTempDirectoryErrorInfo(out tempDirAttribName,
1429                     out configFileName, out configLineNumber);
1430             }
1431             if (tempDirectory != null) {
1432                 tempDirectory = tempDirectory.Trim();
1433                 if (!Path.IsPathRooted(tempDirectory)) {
1434                     // Make sure the path is not relative (VSWhidbey 260075)
1435                     tempDirectory = null;
1436                 }
1437                 else {
1438                     try {
1439                         // Canonicalize it to avoid problems with spaces (VSWhidbey 229873)
1440                         tempDirectory = new DirectoryInfo(tempDirectory).FullName;
1441                     }
1442                     catch {
1443                         tempDirectory = null;
1444                     }
1445                 }
1446                 if (tempDirectory == null) {
1447                     throw new ConfigurationErrorsException(
1448                         SR.GetString(SR.Invalid_temp_directory, tempDirAttribName),
1449                         configFileName, configLineNumber);
1450                 }
1451                 // Create the config-specified directory if needed
1452                 try {
1453                     Directory.CreateDirectory(tempDirectory);
1454                 }
1455                 catch (Exception e) {
1456                     throw new ConfigurationErrorsException(
1457                         SR.GetString(SR.Invalid_temp_directory, tempDirAttribName),
1458                         e,
1459                         configFileName, configLineNumber);
1460                 }
1461             }
1462             else {
1463                 tempDirectory = Path.Combine(RuntimeEnvironment.GetRuntimeDirectory(), HttpRuntime.codegenDirName);
1464             }
1465             // If we don't have write access to the codegen dir, use the TEMP dir instead.
1466             // This will allow non-admin users to work in hosting scenarios (e.g. Venus, aspnet_compiler)
1467             if (!System.Web.UI.Util.HasWriteAccessToDirectory(tempDirectory)) {
1468                 // Don't do this if we're in a service (!UserInteractive), as TEMP
1469                 // could point to unwanted places.
1470                 if (!Environment.UserInteractive) {
1471                     throw new HttpException(SR.GetString(SR.No_codegen_access,
1472                         System.Web.UI.Util.GetCurrentAccountName(), tempDirectory));
1473                 }
1474                 tempDirectory = Path.GetTempPath();
1475                 Debug.Assert(System.Web.UI.Util.HasWriteAccessToDirectory(tempDirectory));
1476                 tempDirectory = Path.Combine(tempDirectory, HttpRuntime.codegenDirName);
1477             }
1478             String simpleAppName = System.Web.Hosting.AppManagerAppDomainFactory.ConstructSimpleAppName(
1479                 VirtualPath.GetVirtualPathStringNoTrailingSlash(virtualPath), isDevEnvironment);
1480             String binDir = Path.Combine(tempDirectory, simpleAppName);
1481             binDir = FileUtil.RemoveTrailingDirectoryBackSlash(binDir);
1482             String binDirUrl = HttpRuntime.MakeFileUrl(binDir);
1483
1484             String originUrl = trustSection.OriginUrl;
1485             FileStream file = new FileStream(configFile, FileMode.Open, FileAccess.Read);
1486             StreamReader reader = new StreamReader(file, Encoding.UTF8);
1487             String strFileData = reader.ReadToEnd();
1488             reader.Close();
1489             strFileData = strFileData.Replace("$AppDir$", appDir);
1490             strFileData = strFileData.Replace("$AppDirUrl$", appDirUrl);
1491             strFileData = strFileData.Replace("$CodeGen$", binDirUrl);
1492             if (originUrl == null)
1493                 originUrl = String.Empty;
1494             strFileData = strFileData.Replace("$OriginHost$", originUrl);
1495             String gacLocation = null;
1496             if (strFileData.IndexOf("$Gac$", StringComparison.Ordinal) != -1) {
1497                 gacLocation = HttpRuntime.GetGacLocation();
1498                 if (gacLocation != null)
1499                     gacLocation = HttpRuntime.MakeFileUrl(gacLocation);
1500                 if (gacLocation == null)
1501                     gacLocation = String.Empty;
1502                 strFileData = strFileData.Replace("$Gac$", gacLocation);
1503             }
1504 #pragma warning disable 618 // ASP is reading their grant set out of legacy policy level files
1505             policyLevel = SecurityManager.LoadPolicyLevelFromString(strFileData, PolicyLevelType.AppDomain);
1506             if (policyLevel == null) {
1507                 throw new ConfigurationErrorsException(SR.GetString(SR.Unable_to_get_policy_file, trustSection.Level));
1508             }
1509             // Found GAC Token
1510             if (gacLocation != null) {
1511                 // walk the code groups at the app domain level and look for one that grants
1512                 // access to the GAC with an UrlMembershipCondition.
1513                 CodeGroup rootGroup = policyLevel.RootCodeGroup;
1514                 bool foundGacCondition = false;
1515                 foreach (CodeGroup childGroup in rootGroup.Children) {
1516                     if (childGroup.MembershipCondition is GacMembershipCondition) {
1517                         foundGacCondition = true;
1518                         // if we found the GAC token and also have the GacMembershipCondition
1519                         // the policy file needs to be upgraded to just include the GacMembershipCondition
1520                         Debug.Assert(!foundGacCondition);
1521                         break;
1522                     }
1523                 }
1524                 // add one as a child of the toplevel group after
1525                 // some sanity checking to make sure it's an ASP.NET policy file
1526                 // which always begins with a FirstMatchCodeGroup granting nothing
1527                 // this might not upgrade some custom policy files
1528                 if (!foundGacCondition) {
1529                     if (rootGroup is FirstMatchCodeGroup) {
1530                         FirstMatchCodeGroup firstMatch = (FirstMatchCodeGroup)rootGroup;
1531                         if (firstMatch.MembershipCondition is AllMembershipCondition &&
1532                             firstMatch.PermissionSetName == "Nothing") {
1533                             PermissionSet fullTrust = new PermissionSet(PermissionState.Unrestricted);
1534                             CodeGroup gacGroup = new UnionCodeGroup(new GacMembershipCondition(),
1535                                                                     new PolicyStatement(fullTrust));
1536                             // now, walk the current groups and insert our new group immediately before the old Gac group
1537                             // we'll need to use heuristics for this: it will be an UrlMembershipCondition group with full trust
1538                             CodeGroup newRoot = new FirstMatchCodeGroup(rootGroup.MembershipCondition, rootGroup.PolicyStatement);
1539                             foreach (CodeGroup childGroup in rootGroup.Children) {
1540                                 // is this the target old $Gac$ group?
1541                                 // insert our new GacMembershipCondition group ahead of it
1542                                 if ((childGroup is UnionCodeGroup) &&
1543                                     (childGroup.MembershipCondition is UrlMembershipCondition) &&
1544                                     childGroup.PolicyStatement.PermissionSet.IsUnrestricted()) {
1545                                     if (null != gacGroup) {
1546                                         newRoot.AddChild(gacGroup);
1547                                         gacGroup = null;
1548                                     }
1549                                 }
1550                                 // append this group to the root group
1551                                 // AddChild itself does a deep Copy to get any
1552                                 // child groups so we don't need one here
1553                                 newRoot.AddChild(childGroup);
1554                             }
1555                             policyLevel.RootCodeGroup = newRoot;
1556                         }
1557                     }
1558                 }
1559             }
1560             return policyLevel;
1561 #pragma warning restore 618
1562         }
1563
1564         private sealed class ApplicationResumeStateContainer {
1565             private static readonly WaitCallback _tpCallback = ResumeCallback;
1566
1567             private readonly HostingEnvironment _hostEnv;
1568             private readonly IntPtr _resumeState;
1569
1570             internal ApplicationResumeStateContainer(HostingEnvironment hostEnv, IntPtr resumeState) {
1571                 _hostEnv = hostEnv;
1572                 _resumeState = resumeState;
1573             }
1574
1575             // schedules resume for execution on a new thread
1576             // unsafe since we don't care about impersonation, identity, etc.
1577             internal void Resume() {
1578                 ThreadPool.UnsafeQueueUserWorkItem(_tpCallback, this);
1579             }
1580
1581             private static void ResumeCallback(object state) {
1582                 ApplicationResumeStateContainer container = (ApplicationResumeStateContainer)state;
1583                 try {
1584                     container._hostEnv.ResumeApplication(container._resumeState);
1585                 }
1586                 catch (AppDomainUnloadedException) {
1587                     // AD unloads aren't considered a failure, ----
1588                 }
1589             }
1590         }
1591
1592         [SecurityPermission(SecurityAction.LinkDemand, Unrestricted = true)]
1593         private static class AspNetAppDomainManager {
1594             internal static Type GetAspNetAppDomainManagerType(bool overrideHostExecutionContextManager, bool overrideHostSecurityManager) {
1595                 if (!overrideHostExecutionContextManager && !overrideHostSecurityManager) {
1596                     // A custom AppDomainManager isn't necessary for this AppDomain.
1597                     return null;
1598                 }
1599                 else {
1600                     // A custom AppDomainManager is necessary for this AppDomain.
1601                     // See comment on the generic type for further information.
1602                     Type openGenericType = typeof(AspNetAppDomainManagerImpl<,>);
1603                     Type closedGenericType = openGenericType.MakeGenericType(
1604                         (overrideHostExecutionContextManager) ? typeof(AspNetHostExecutionContextManager) : typeof(object),
1605                         (overrideHostSecurityManager) ? typeof(AspNetHostSecurityManager) : typeof(object)
1606                         );
1607                     return closedGenericType;
1608                 }
1609             }
1610
1611             // This AppDomainManager may have been set because we need it for Task support, because this is a partial-trust
1612             // AppDomain, or both. Normally we would store this data in the AppDomain's ambient data store (AppDomain.SetData),
1613             // but the AppDomainManager instance is initialized in the new AppDomain before the original AppDomain has a chance to
1614             // call SetData, so in this AppDomain the call to GetData is useless. However, we can use the AppDomainManager type
1615             // itself to carry the necessary information in the form of a generic type parameter. If a custom
1616             // HostExecutionContextManager or HostSecurityManager is necessary, the generic type parameters can tell us that.
1617             // A generic type parameter of "object" means that this particular sub-manager isn't necessary.
1618             private sealed class AspNetAppDomainManagerImpl<THostExecutionContextManager, THostSecurityManager> : AppDomainManager
1619                 where THostExecutionContextManager : class, new()
1620                 where THostSecurityManager : class, new() {
1621
1622                 private readonly HostExecutionContextManager _hostExecutionContextManager = CreateHostExecutionContextManager();
1623                 private readonly HostSecurityManager _hostSecurityManager = CreateHostSecurityManager();
1624
1625                 public override HostExecutionContextManager HostExecutionContextManager {
1626                     get {
1627                         return _hostExecutionContextManager ?? base.HostExecutionContextManager;
1628                     }
1629                 }
1630
1631                 public override HostSecurityManager HostSecurityManager {
1632                     get {
1633                         return _hostSecurityManager ?? base.HostSecurityManager;
1634                     }
1635                 }
1636
1637                 private static HostExecutionContextManager CreateHostExecutionContextManager() {
1638                     object hostExecutionContextManager = new THostExecutionContextManager();
1639                     Debug.Assert(hostExecutionContextManager is HostExecutionContextManager || hostExecutionContextManager.GetType() == typeof(object), "THostExecutionContextManager was an unexpected type!");
1640                     return hostExecutionContextManager as HostExecutionContextManager;
1641                 }
1642
1643                 private static HostSecurityManager CreateHostSecurityManager() {
1644                     object hostSecurityManager = new THostSecurityManager();
1645                     Debug.Assert(hostSecurityManager is HostSecurityManager || hostSecurityManager.GetType() == typeof(object), "THostSecurityManager was an unexpected type!");
1646                     return hostSecurityManager as HostSecurityManager;
1647                 }
1648             }
1649
1650             private sealed class AspNetHostSecurityManager : HostSecurityManager {
1651                 private PermissionSet Nothing = new PermissionSet(PermissionState.None);
1652                 private PermissionSet FullTrust = new PermissionSet(PermissionState.Unrestricted);
1653                 private HostSecurityPolicyResolver hostSecurityPolicyResolver = null;
1654
1655                 public override HostSecurityManagerOptions Flags {
1656                     get {
1657                         return HostSecurityManagerOptions.HostResolvePolicy;
1658                     }
1659                 }
1660
1661                 [SecurityPermission(SecurityAction.Assert, Flags = SecurityPermissionFlag.SerializationFormatter)]
1662                 public override PermissionSet ResolvePolicy(Evidence evidence) {
1663                     if (base.ResolvePolicy(evidence).IsUnrestricted()) {
1664                         return FullTrust;
1665                     }
1666
1667                     if (!String.IsNullOrEmpty(HttpRuntime.HostSecurityPolicyResolverType) && hostSecurityPolicyResolver == null) {
1668                         hostSecurityPolicyResolver = Activator.CreateInstance(
1669                             Type.GetType(HttpRuntime.HostSecurityPolicyResolverType)) as HostSecurityPolicyResolver;
1670                     }
1671
1672                     if (hostSecurityPolicyResolver != null) {
1673                         switch (hostSecurityPolicyResolver.ResolvePolicy(evidence)) {
1674                             case HostSecurityPolicyResults.FullTrust:
1675                                 return FullTrust;
1676                             case HostSecurityPolicyResults.AppDomainTrust:
1677                                 return HttpRuntime.NamedPermissionSet;
1678                             case HostSecurityPolicyResults.Nothing:
1679                                 return Nothing;
1680                             case HostSecurityPolicyResults.DefaultPolicy:
1681                                 break;
1682                         }
1683                     }
1684
1685                     if (HttpRuntime.PolicyLevel == null || HttpRuntime.PolicyLevel.Resolve(evidence).PermissionSet.IsUnrestricted())
1686                         return FullTrust;
1687                     else if (HttpRuntime.PolicyLevel.Resolve(evidence).PermissionSet.Equals(Nothing))
1688                         return Nothing;
1689                     else
1690                         return HttpRuntime.NamedPermissionSet;
1691                 }
1692             }
1693         }
1694
1695         private static void PopulateDomainBindings(String domainId, String appId, String appName,
1696                                                     String appPath, VirtualPath appVPath,
1697                                                     AppDomainSetup setup, IDictionary dict) {
1698             // assembly loading settings
1699
1700             // We put both the old and new bin dir names on the private bin path
1701             setup.PrivateBinPathProbe   = "*";  // disable loading from app base
1702             setup.ShadowCopyFiles       = "true";
1703             setup.ApplicationBase       = appPath;
1704             setup.ApplicationName       = appName;
1705             setup.ConfigurationFile     = HttpConfigurationSystem.WebConfigFileName;
1706
1707             // Disallow code download, since it's unreliable in services (ASURT 123836/127606)
1708             setup.DisallowCodeDownload  = true;
1709
1710             // internal settings
1711             dict.Add(".appDomain",     "*");
1712             dict.Add(".appId",         appId);
1713             dict.Add(".appPath",       appPath);
1714             dict.Add(".appVPath",      appVPath.VirtualPathString);
1715             dict.Add(".domainId",      domainId);
1716         }
1717
1718         private static Evidence GetDefaultDomainIdentity() {
1719             Evidence evidence = AppDomain.CurrentDomain.Evidence; // CurrentDomain.Evidence returns a clone so we can modify it if we need
1720             bool hasZone = evidence.GetHostEvidence<Zone>() != null;
1721             bool hasUrl = evidence.GetHostEvidence<Url>() != null;
1722
1723             if (!hasZone)
1724                 evidence.AddHostEvidence(new Zone(SecurityZone.MyComputer));
1725
1726             if (!hasUrl)
1727                 evidence.AddHostEvidence(new Url("ms-internal-microsoft-asp-net-webhost-20"));
1728
1729             return evidence;
1730         }
1731
1732         private static int s_domainCount = 0;
1733         private static Object s_domainCountLock = new Object();
1734
1735         private static String ConstructAppDomainId(String id) {
1736             int domainCount = 0;
1737             lock (s_domainCountLock) {
1738                 domainCount = ++s_domainCount;
1739             }
1740             return id + "-" + domainCount.ToString(NumberFormatInfo.InvariantInfo) + "-" + DateTime.UtcNow.ToFileTime().ToString();
1741         }
1742
1743         internal LockableAppDomainContext GetLockableAppDomainContext (string appId) {
1744             lock (this) {
1745                 LockableAppDomainContext ac;
1746                 if (!_appDomains.TryGetValue(appId, out ac)) {
1747                     ac = new LockableAppDomainContext();
1748                     _appDomains.Add (appId, ac);
1749                 }
1750
1751                 return ac;
1752             }
1753         }
1754
1755         // take a copy of _appDomains collection so that it can be used without locking on ApplicationManager
1756         private Dictionary<string, LockableAppDomainContext> CloneAppDomainsCollection() {
1757             lock (this) {
1758                 return new Dictionary<string, LockableAppDomainContext>(_appDomains, StringComparer.OrdinalIgnoreCase);
1759             }
1760         }
1761
1762         private static Configuration GetAppConfigCommon(IConfigMapPath configMapPath, string siteID, string appSegment) {
1763             WebConfigurationFileMap fileMap = new WebConfigurationFileMap();
1764             string dir = null;
1765             string fileName = null;
1766             string subDir = "/";
1767             // add root mapping
1768             configMapPath.GetPathConfigFilename(siteID, subDir, out dir, out fileName);
1769             if (dir != null) {
1770                 fileMap.VirtualDirectories.Add(subDir, new VirtualDirectoryMapping(Path.GetFullPath(dir), true));
1771             }
1772             // add subdir mappings
1773             string[] subDirs = appSegment.Split(new char[] { '/' }, StringSplitOptions.RemoveEmptyEntries);
1774             foreach (string s in subDirs) {
1775                 subDir = subDir + s;
1776                 configMapPath.GetPathConfigFilename(siteID, subDir, out dir, out fileName);
1777                 if (dir != null) {
1778                     fileMap.VirtualDirectories.Add(subDir, new VirtualDirectoryMapping(Path.GetFullPath(dir), true));
1779                 }
1780                 subDir = subDir + "/";
1781             }
1782             // open mapped web config for application
1783             return WebConfigurationManager.OpenMappedWebConfiguration(fileMap, appSegment, siteID);
1784         }
1785
1786         [SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands", Justification = "Only ever called by the full-trust parent AppDomain.")]
1787         private static Configuration GetAppConfigGeneric(IApplicationHost appHost, string siteID, string appSegment, VirtualPath virtualPath, string physicalPath) {
1788             WebConfigurationFileMap fileMap = new WebConfigurationFileMap();
1789             IConfigMapPathFactory configMapPathFactory2 = appHost.GetConfigMapPathFactory();
1790             IConfigMapPath configMapPath = configMapPathFactory2.Create(virtualPath.VirtualPathString, physicalPath);
1791             return GetAppConfigCommon(configMapPath, siteID, appSegment);
1792         }
1793
1794         private static Configuration GetAppConfigIISExpress(string siteID, string appSegment, string iisExpressVersion) {
1795             ExpressServerConfig serverConfig = (ExpressServerConfig)ServerConfig.GetDefaultDomainInstance(iisExpressVersion);
1796             return GetAppConfigCommon(serverConfig, siteID, appSegment);
1797         }
1798
1799         private sealed class AppDomainSwitches {
1800             public bool UseLegacyCas;
1801             public bool UseRandomizedStringHashAlgorithm;
1802
1803             public void Apply(AppDomainSetup setup) {
1804                 List<string> switches = new List<string>();
1805
1806                 if (UseLegacyCas) {
1807                     // Enables the AppDomain to use the legacy CAS model for compatibility <trust/legacyCasModel>
1808                     switches.Add("NetFx40_LegacySecurityPolicy");
1809                 }
1810
1811                 if (UseRandomizedStringHashAlgorithm) {
1812                     switches.Add("UseRandomizedStringHashAlgorithm");
1813                 }
1814
1815                 if (switches.Count > 0) {
1816                     setup.SetCompatibilitySwitches(switches);
1817                 }
1818             }
1819         }
1820
1821         // This class holds information about the environment that is hosting ASP.NET. The particular design of this class
1822         // is that the information is computed once and stored, and the methods which compute the information are private.
1823         // This prevents accidental misuse of this type via querying the environment after user code has had a chance to
1824         // run, which could potentially affect the environment itself.
1825         private static class EnvironmentInfo {
1826             public static readonly bool IsStringHashCodeRandomizationDetected = GetIsStringHashCodeRandomizationDetected();
1827             public static readonly bool WasLaunchedFromDevelopmentEnvironment = GetWasLaunchedFromDevelopmentEnvironmentValue();
1828
1829             private static bool GetIsStringHashCodeRandomizationDetected() {
1830                 // known test vector
1831                 return (StringComparer.InvariantCultureIgnoreCase.GetHashCode("The quick brown fox jumps over the lazy dog.") != 0x703e662e);
1832             }
1833
1834             // Visual Studio / WebMatrix will set DEV_ENVIRONMENT=1 when launching an ASP.NET host in a development environment.
1835             private static bool GetWasLaunchedFromDevelopmentEnvironmentValue() {
1836                 try {
1837                     string envVar = Environment.GetEnvironmentVariable("DEV_ENVIRONMENT", EnvironmentVariableTarget.Process);
1838                     return String.Equals(envVar, "1", StringComparison.Ordinal);
1839                 }
1840                 catch {
1841                     // We don't care if we can't read the environment variable; just treat it as not present.
1842                     return false;
1843                 }
1844             }
1845         }
1846
1847     }
1848 }