1 //------------------------------------------------------------------------------
2 // <copyright file="HostingEnvironment.cs" company="Microsoft">
3 //     Copyright (c) Microsoft Corporation.  All rights reserved.
4 // </copyright>
5 //------------------------------------------------------------------------------
6 
7 namespace System.Web.Hosting {
8     using System;
9     using System.Collections;
10     using System.Collections.Generic;
11     using System.Collections.Specialized;
12     using System.Configuration;
13     using System.Configuration.Provider;
14     using System.Diagnostics.CodeAnalysis;
15     using System.Globalization;
16     using System.IO;
17     using System.Runtime.Caching;
18     using System.Runtime.CompilerServices;
19     using System.Runtime.InteropServices;
20     using System.Runtime.Remoting;
21     using System.Runtime.Remoting.Messaging;
22     using System.Security;
23     using System.Security.Permissions;
24     using System.Security.Policy;
25     using System.Security.Principal;
26     using System.Text;
27     using System.Threading;
28     using System.Threading.Tasks;
29     using System.Web;
30     using System.Web.Caching;
31     using System.Web.Compilation;
32     using System.Web.Configuration;
33     using System.Web.Management;
34     using System.Web.Util;
35     using System.Web.WebSockets;
36     using Microsoft.Win32;
37 
38     [Flags]
39     internal enum HostingEnvironmentFlags {
40         Default = 0,
41         HideFromAppManager = 1,
42         ThrowHostingInitErrors = 2,
43         DontCallAppInitialize = 4,
44         ClientBuildManager = 8,
45         SupportsMultiTargeting = 16,
46     }
47 
48     [Serializable]
49     internal class HostingEnvironmentParameters {
50         private HostingEnvironmentFlags _hostingFlags;
51         private ClientBuildManagerParameter _clientBuildManagerParameter;
52         private string _precompTargetPhysicalDir;
53         private string _iisExpressVersion;
54 
55         public HostingEnvironmentFlags HostingFlags {
56             get { return _hostingFlags; }
57             set { _hostingFlags = value; }
58         }
59 
60         // Directory where the precompiled site is placed
61         public string PrecompilationTargetPhysicalDirectory {
62             get { return _precompTargetPhysicalDir; }
63             set {
64                 _precompTargetPhysicalDir = FileUtil.FixUpPhysicalDirectory(value);
65             }
66         }
67 
68         // Determines the behavior of the precompilation
69         public ClientBuildManagerParameter ClientBuildManagerParameter {
70             get { return _clientBuildManagerParameter; }
71             set { _clientBuildManagerParameter = value; }
72         }
73 
74         // Determines which config system to load
75         public string IISExpressVersion {
76             get { return _iisExpressVersion; }
77             set { _iisExpressVersion = value; }
78         }
79 
80         // Determines what FileChangeMonitor mode to use
81         public FcnMode FcnMode {
82             get;
83             set;
84         }
85 
86         // Should FileChangesMonitor skip reading and caching DACLs?
87         public bool FcnSkipReadAndCacheDacls {
88             get;
89             set;
90         }
91 
92         public KeyValuePair<string, bool>[] ClrQuirksSwitches {
93             get;
94             set;
95         }
96     }
97 
98     public sealed class HostingEnvironment : MarshalByRefObject {
99 
100         private static HostingEnvironment _theHostingEnvironment;
101         private EventHandler _onAppDomainUnload;
102         private ApplicationManager _appManager;
103         private HostingEnvironmentParameters _hostingParameters;
104         private IApplicationHost _appHost;
105         private bool _externalAppHost;
106         private IConfigMapPath _configMapPath;
107         private IConfigMapPath2 _configMapPath2;
108         private IntPtr _configToken;
109 
110         private IdentitySection _appIdentity;
111         private IntPtr _appIdentityToken;
112         private bool _appIdentityTokenSet;
113 
114         private String _appId;
115         private VirtualPath _appVirtualPath;
116         private String _appPhysicalPath;
117         private String _siteName;
118         private String _siteID;
119         private String _appConfigPath;
120 
121         private bool   _isBusy;
122         private int    _busyCount;
123 
124         private volatile static bool _stopListeningWasCalled; // static since it's process-wide
125         private bool _removedFromAppManager;
126         private bool _appDomainShutdownStarted;
127         private bool _shutdownInitiated;
128         private bool _shutdownInProgress;
129         private String _shutDownStack;
130 
131         private static NameValueCollection _cacheProviderSettings;
132         private int _inTrimCache;
133         private ObjectCacheHost _objectCacheHost;
134 
135         // table of well know objects keyed by type
136         private Hashtable _wellKnownObjects = new Hashtable();
137 
138         // list of registered IRegisteredObject instances, suspend listeners, and background work items
139         private Hashtable _registeredObjects = new Hashtable();
140         private SuspendManager _suspendManager = new SuspendManager();
141         private ApplicationMonitors _applicationMonitors;
142         private BackgroundWorkScheduler _backgroundWorkScheduler = null; // created on demand
143         private static readonly Task<object> _completedTask = Task.FromResult<object>(null);
144 
145         // callback to make InitiateShutdown non-blocking
146         private WaitCallback _initiateShutdownWorkItemCallback;
147 
148         // inside app domain idle shutdown logic
149         private IdleTimeoutMonitor _idleTimeoutMonitor;
150 
151         private static IProcessHostSupportFunctions _functions;
152         private static bool _hasBeenRemovedFromAppManangerTable;
153 
154         private const string TemporaryVirtualPathProviderKey = "__TemporaryVirtualPathProvider__";
155 
156         // Determines what FileChangeMonitor mode to use
157         internal static FcnMode FcnMode {
158             get {
159                 if (_theHostingEnvironment != null && _theHostingEnvironment._hostingParameters != null) {
160                     return _theHostingEnvironment._hostingParameters.FcnMode;
161                 }
162                 return FcnMode.NotSet;
163             }
164         }
165 
166         internal static bool FcnSkipReadAndCacheDacls {
167             get {
168                 if (_theHostingEnvironment != null && _theHostingEnvironment._hostingParameters != null) {
169                     return _theHostingEnvironment._hostingParameters.FcnSkipReadAndCacheDacls;
170                 }
171                 return false;
172             }
173         }
174 
InitializeLifetimeService()175         public override Object InitializeLifetimeService() {
176             return null; // never expire lease
177         }
178 
179         /// <internalonly/>
180         [SecurityPermission(SecurityAction.Demand, Unrestricted = true)]
HostingEnvironment()181         public HostingEnvironment() {
182             if (_theHostingEnvironment != null)
183                 throw new InvalidOperationException(SR.GetString(SR.Only_1_HostEnv));
184 
185             // remember singleton HostingEnvironment in a static
186             _theHostingEnvironment = this;
187 
188             // start watching for app domain unloading
189             _onAppDomainUnload = new EventHandler(OnAppDomainUnload);
190             Thread.GetDomain().DomainUnload += _onAppDomainUnload;
191 
192             // VSO 160528: We used to listen to the default AppDomain's UnhandledException only.
193             // However, non-serializable exceptions cannot be passed to the default domain. Therefore
194             // we should try to log exceptions in application AppDomains.
195             Thread.GetDomain().UnhandledException += new UnhandledExceptionEventHandler(ApplicationManager.OnUnhandledException);
196         }
197 
TrimCache(int percent)198         internal static long TrimCache(int percent)
199         {
200             if (_theHostingEnvironment != null)
201                 return _theHostingEnvironment.TrimCacheInternal(percent);
202             return 0;
203         }
204 
TrimCacheInternal(int percent)205         private long TrimCacheInternal(int percent)
206         {
207             if (Interlocked.Exchange(ref _inTrimCache, 1) != 0)
208                 return 0;
209             try {
210                 long trimmedOrExpired = 0;
211                 // do nothing if we're shutting down
212                 if (!_shutdownInitiated) {
213                     var iCache = HttpRuntime.Cache.GetInternalCache(createIfDoesNotExist: false);
214                     var oCache = HttpRuntime.Cache.GetObjectCache(createIfDoesNotExist: false);
215                     if (oCache != null) {
216                         trimmedOrExpired = oCache.Trim(percent);
217                     }
218                     if (iCache != null && !iCache.Equals(oCache)) {
219                         trimmedOrExpired += iCache.Trim(percent);
220                     }
221                     if (_objectCacheHost != null && !_shutdownInitiated) {
222                         trimmedOrExpired += _objectCacheHost.TrimCache(percent);
223                     }
224                 }
225                 return trimmedOrExpired;
226             }
227             finally {
228                 Interlocked.Exchange(ref _inTrimCache, 0);
229             }
230         }
231 
OnAppDomainUnload(Object unusedObject, EventArgs unusedEventArgs)232         private void OnAppDomainUnload(Object unusedObject, EventArgs unusedEventArgs) {
233             Debug.Trace("PipelineRuntime", "HE.OnAppDomainUnload");
234 
235             Thread.GetDomain().DomainUnload -= _onAppDomainUnload;
236 
237             // check for unexpected shutdown
238             if (!_removedFromAppManager) {
239                 RemoveThisAppDomainFromAppManagerTableOnce();
240             }
241 
242             HttpRuntime.RecoverFromUnexceptedAppDomainUnload();
243 
244             // call Stop on all registered objects with immediate = true
245             StopRegisteredObjects(true);
246 
247             // notify app manager
248             if (_appManager != null) {
249                 // disconnect the real app host and substitute it with a bogus one
250                 // to avoid exceptions later when app host is called (it normally wouldn't)
251                 IApplicationHost originalAppHost = null;
252 
253                 if (_externalAppHost) {
254                     originalAppHost = _appHost;
255                     _appHost = new SimpleApplicationHost(_appVirtualPath, _appPhysicalPath);
256                     _externalAppHost = false;
257                 }
258 
259                 IDisposable configSystem = _configMapPath2 as IDisposable;
260                 if (configSystem != null) {
261                     configSystem.Dispose();
262                 }
263 
264                 _appManager.HostingEnvironmentShutdownComplete(_appId, originalAppHost);
265             }
266 
267             // free the config access token
268             if (_configToken != IntPtr.Zero) {
269                 UnsafeNativeMethods.CloseHandle(_configToken);
270                 _configToken = IntPtr.Zero;
271             }
272         }
273 
274         //
275         // Initialization
276         //
277 
278         // called from app manager right after app domain (and hosting env) is created
Initialize(ApplicationManager appManager, IApplicationHost appHost, IConfigMapPathFactory configMapPathFactory, HostingEnvironmentParameters hostingParameters, PolicyLevel policyLevel)279         internal void Initialize(ApplicationManager appManager, IApplicationHost appHost, IConfigMapPathFactory configMapPathFactory, HostingEnvironmentParameters hostingParameters, PolicyLevel policyLevel) {
280             Initialize(appManager, appHost, configMapPathFactory, hostingParameters, policyLevel, null);
281         }
282 
283         [PermissionSet(SecurityAction.Assert, Unrestricted = true)]
284         [SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands", Justification = "We carefully control this method's callers.")]
Initialize(ApplicationManager appManager, IApplicationHost appHost, IConfigMapPathFactory configMapPathFactory, HostingEnvironmentParameters hostingParameters, PolicyLevel policyLevel, Exception appDomainCreationException)285         internal void Initialize(ApplicationManager appManager, IApplicationHost appHost, IConfigMapPathFactory configMapPathFactory,
286             HostingEnvironmentParameters hostingParameters, PolicyLevel policyLevel,
287             Exception appDomainCreationException) {
288 
289             _hostingParameters = hostingParameters;
290 
291             HostingEnvironmentFlags hostingFlags = HostingEnvironmentFlags.Default;
292             if (_hostingParameters != null) {
293                 hostingFlags = _hostingParameters.HostingFlags;
294                 if (_hostingParameters.IISExpressVersion != null) {
295                     ServerConfig.IISExpressVersion = _hostingParameters.IISExpressVersion;
296                 }
297             }
298 
299             // Keep track of the app manager, unless HideFromAppManager flag was passed
300             if ((hostingFlags & HostingEnvironmentFlags.HideFromAppManager) == 0)
301                 _appManager = appManager;
302 
303             if ((hostingFlags & HostingEnvironmentFlags.ClientBuildManager) != 0) {
304                 BuildManagerHost.InClientBuildManager = true;
305             }
306 
307             if ((hostingFlags & HostingEnvironmentFlags.SupportsMultiTargeting) != 0) {
308                 BuildManagerHost.SupportsMultiTargeting = true;
309             }
310 
311             // Set CLR quirks switches before the config system is initialized since config might depend on them
312             if (_hostingParameters != null && _hostingParameters.ClrQuirksSwitches != null && _hostingParameters.ClrQuirksSwitches.Length > 0) {
313                 SetClrQuirksSwitches(_hostingParameters.ClrQuirksSwitches);
314             }
315 
316             //
317             // init config system using private config if applicable
318             //
319             if (appHost is ISAPIApplicationHost && !ServerConfig.UseMetabase) {
320                 string rootWebConfigPath = ((ISAPIApplicationHost)appHost).ResolveRootWebConfigPath();
321                 if (!String.IsNullOrEmpty(rootWebConfigPath)) {
322                     Debug.Assert(File.Exists(rootWebConfigPath), "File.Exists(rootWebConfigPath)");
323                     HttpConfigurationSystem.RootWebConfigurationFilePath = rootWebConfigPath;
324                 }
325 
326                 // we need to explicit create a COM proxy in this app domain
327                 // so we don't go back to the default domain or have lifetime issues
328                 // remember support functions
329                 IProcessHostSupportFunctions proxyFunctions = ((ISAPIApplicationHost)appHost).SupportFunctions;
330                 if (null != proxyFunctions) {
331                     _functions = Misc.CreateLocalSupportFunctions(proxyFunctions);
332                 }
333             }
334 
335             _appId = HttpRuntime.AppDomainAppId;
336             _appVirtualPath = HttpRuntime.AppDomainAppVirtualPathObject;
337             _appPhysicalPath = HttpRuntime.AppDomainAppPathInternal;
338             _appHost = appHost;
339 
340             _configMapPath = configMapPathFactory.Create(_appVirtualPath.VirtualPathString, _appPhysicalPath);
341             HttpConfigurationSystem.EnsureInit(_configMapPath, true, false);
342 
343             // attempt to cache and use IConfigMapPath2 provider
344             // which supports VirtualPath's to save on conversions
345             _configMapPath2 = _configMapPath as IConfigMapPath2;
346 
347 
348             _initiateShutdownWorkItemCallback = new WaitCallback(this.InitiateShutdownWorkItemCallback);
349 
350             // notify app manager
351             if (_appManager != null) {
352                 _appManager.HostingEnvironmentActivated();
353             }
354 
355             // make sure there is always app host
356             if (_appHost == null) {
357                 _appHost = new SimpleApplicationHost(_appVirtualPath, _appPhysicalPath);
358             }
359             else {
360                 _externalAppHost = true;
361             }
362 
363             // remember the token to access config
364             _configToken = _appHost.GetConfigToken();
365 
366             // Start with a MapPath based virtual path provider
367             _mapPathBasedVirtualPathProvider = new MapPathBasedVirtualPathProvider();
368             _virtualPathProvider = _mapPathBasedVirtualPathProvider;
369 
370             // initiaze HTTP-independent features
371             HttpRuntime.InitializeHostingFeatures(hostingFlags, policyLevel, appDomainCreationException);
372 
373             // VSWhidbey 393259. Do not monitor idle timeout for CBM since Venus
374             // will always restart a new appdomain if old one is shutdown.
375             if (!BuildManagerHost.InClientBuildManager) {
376                 // start monitoring for idle inside app domain
377                 StartMonitoringForIdleTimeout();
378             }
379 
380             // notify app manager if the app domain limit is violated
381             EnforceAppDomainLimit();
382 
383             // get application identity (for explicit impersonation mode)
384             GetApplicationIdentity();
385 
386             _applicationMonitors = new ApplicationMonitors();
387 
388             // call AppInitialize, unless the flag says not to do it (e.g. CBM scenario).
389             // Also, don't call it if HostingInit failed (VSWhidbey 210495)
390             if(!HttpRuntime.HostingInitFailed) {
391                 try {
392                     BuildManager.ExecutePreAppStart();
393                     if ((hostingFlags & HostingEnvironmentFlags.DontCallAppInitialize) == 0) {
394                         BuildManager.CallAppInitializeMethod();
395                     }
396                 }
397                 catch (Exception e) {
398                     // could throw compilation errors in 'code' - report them with first http request
399                     HttpRuntime.InitializationException = e;
400 
401                     if ((hostingFlags & HostingEnvironmentFlags.ThrowHostingInitErrors) != 0) {
402                         throw;
403                     }
404                 }
405             }
406         }
407 
InitializeObjectCacheHostPrivate()408         private void InitializeObjectCacheHostPrivate() {
409             // set ObjectCacheHost if the Host is not already set
410             if (ObjectCache.Host == null) {
411                 ObjectCacheHost objectCacheHost = new ObjectCacheHost();
412                 ObjectCache.Host = objectCacheHost;
413                 _objectCacheHost = objectCacheHost;
414             }
415         }
416 
InitializeObjectCacheHost()417         internal static void InitializeObjectCacheHost() {
418             if (_theHostingEnvironment != null) {
419                 _theHostingEnvironment.InitializeObjectCacheHostPrivate();
420             }
421         }
422 
StartMonitoringForIdleTimeout()423         private void StartMonitoringForIdleTimeout() {
424             HostingEnvironmentSection hostEnvConfig = RuntimeConfig.GetAppLKGConfig().HostingEnvironment;
425 
426             TimeSpan idleTimeout = (hostEnvConfig != null) ? hostEnvConfig.IdleTimeout : HostingEnvironmentSection.DefaultIdleTimeout;
427 
428             // always create IdleTimeoutMonitor (even if config value is TimeSpan.MaxValue (infinite)
429             // IdleTimeoutMonitor is also needed to keep the last event for app domain set trimming
430             // and the timer is used to trim the application instances
431             _idleTimeoutMonitor = new IdleTimeoutMonitor(idleTimeout);
432         }
433 
434         // enforce app domain limit
EnforceAppDomainLimit()435         private void EnforceAppDomainLimit() {
436             if (_appManager == null)  /// detached app domain
437                 return;
438 
439             int limit = 0;
440 
441             try {
442                 ProcessModelSection pmConfig = RuntimeConfig.GetMachineConfig().ProcessModel;
443                 limit = pmConfig.MaxAppDomains;
444             }
445             catch {
446             }
447 
448             if (limit > 0 && _appManager.AppDomainsCount >= limit) {
449                 // current app domain doesn't count yet (not in the table)
450                 // that's why '>=' above
451                 _appManager.ReduceAppDomainsCount(limit);
452             }
453         }
454 
GetApplicationIdentity()455         private void GetApplicationIdentity() {
456             // if the explicit impersonation is set, use it instead of UNC identity
457             try {
458                 IdentitySection c = RuntimeConfig.GetAppConfig().Identity;
459                 if (c.Impersonate && c.ImpersonateToken != IntPtr.Zero) {
460                     _appIdentity = c;
461                     _appIdentityToken = c.ImpersonateToken;
462                 }
463                 else {
464                     _appIdentityToken = _configToken;
465                 }
466                 _appIdentityTokenSet = true;
467             }
468             catch {
469             }
470         }
471 
SetClrQuirksSwitches(KeyValuePair<string, bool>[] switches)472         private static void SetClrQuirksSwitches(KeyValuePair<string, bool>[] switches) {
473             // First, see if the static API AppContext.SetSwitch even exists.
474             // Type.GetType will return null if the type doesn't exist; it will throw on catastrophic failure.
475 
476             Type appContextType = Type.GetType("System.AppContext, " + AssemblyRef.Mscorlib);
477             if (appContextType == null) {
478                 return; // wrong version of mscorlib - do nothing
479             }
480 
481             Action<string, bool> setter = (Action<string, bool>)Delegate.CreateDelegate(
482                 typeof(Action<string, bool>),
483                 appContextType,
484                 "SetSwitch",
485                 ignoreCase: false,
486                 throwOnBindFailure: false);
487             if (setter == null) {
488                 return; // wrong version of mscorlib - do nothing
489             }
490 
491             // Finally, set each switch individually.
492 
493             foreach (var sw in switches) {
494                 setter(sw.Key, sw.Value);
495             }
496         }
497 
498 
499         // If an exception was thrown during initialization, return it.
500         public static Exception InitializationException {
501             get {
502                 return HttpRuntime.InitializationException;
503             }
504         }
505 
506         // called from app manager (from management APIs)
GetApplicationInfo()507         internal ApplicationInfo GetApplicationInfo() {
508             return new ApplicationInfo(_appId, _appVirtualPath, _appPhysicalPath);
509         }
510 
511         //
512         // Shutdown logic
513         //
514         [PermissionSet(SecurityAction.Assert, Unrestricted = true)]
StopRegisteredObjects(bool immediate)515         private void StopRegisteredObjects(bool immediate) {
516             if (_registeredObjects.Count > 0) {
517                 ArrayList list = new ArrayList();
518 
519                 lock (this) {
520                     foreach (DictionaryEntry e in _registeredObjects) {
521                         Object x = e.Key;
522 
523                         // well-known objects first
524                         if (IsWellKnownObject(x)) {
525                             list.Insert(0, x);
526                         }
527                         else {
528                             list.Add(x);
529                         }
530                     }
531                 }
532 
533                 foreach (IRegisteredObject obj in list) {
534                     try {
535                         obj.Stop(immediate);
536                     }
537                     catch {
538                     }
539                 }
540             }
541         }
542 
InitiateShutdownWorkItemCallback(Object state )543         private void InitiateShutdownWorkItemCallback(Object state /*not used*/) {
544             Debug.Trace("HostingEnvironmentShutdown", "Shutting down: appId=" + _appId);
545 
546             // no registered objects -- shutdown
547             if (_registeredObjects.Count == 0) {
548                 Debug.Trace("HostingEnvironmentShutdown", "No registered objects");
549                 ShutdownThisAppDomainOnce();
550                 return;
551             }
552 
553             // call Stop on all registered objects with immediate = false
554             StopRegisteredObjects(false);
555 
556             // no registered objects -- shutdown now
557             if (_registeredObjects.Count == 0) {
558                 Debug.Trace("HostingEnvironmentShutdown", "All registered objects gone after Stop(false)");
559                 ShutdownThisAppDomainOnce();
560                 return;
561             }
562 
563             // if not everything shutdown synchronously give it some time.
564             int shutdownTimeoutSeconds = HostingEnvironmentSection.DefaultShutdownTimeout;
565             HostingEnvironmentSection hostEnvConfig = RuntimeConfig.GetAppLKGConfig().HostingEnvironment;
566             if (hostEnvConfig != null) {
567                 shutdownTimeoutSeconds = (int) hostEnvConfig.ShutdownTimeout.TotalSeconds;
568             }
569             Debug.Trace("HostingEnvironmentShutdown", "Waiting for " + shutdownTimeoutSeconds + " sec...");
570 
571             DateTime waitUntil = DateTime.UtcNow.AddSeconds(shutdownTimeoutSeconds);
572             while (_registeredObjects.Count > 0 && DateTime.UtcNow < waitUntil) {
573                 Thread.Sleep(100);
574             }
575 
576             Debug.Trace("HostingEnvironmentShutdown", "Shutdown timeout (" + shutdownTimeoutSeconds + " sec) expired");
577 
578             // call Stop on all registered objects with immediate = true
579             StopRegisteredObjects(true);
580 
581             // no registered objects -- shutdown now
582             if (_registeredObjects.Count == 0) {
583                 Debug.Trace("HostingEnvironmentShutdown", "All registered objects gone after Stop(true)");
584                 ShutdownThisAppDomainOnce();
585                 return;
586             }
587 
588             // shutdown regardless
589             Debug.Trace("HostingEnvironmentShutdown", "Forced shutdown: " + _registeredObjects.Count + " registered objects left");
590             _registeredObjects = new Hashtable();
591             ShutdownThisAppDomainOnce();
592         }
593 
594         // app domain shutdown logic
InitiateShutdownInternal()595         internal void InitiateShutdownInternal() {
596 #if DBG
597             try {
598 #endif
599             Debug.Trace("AppManager", "HostingEnvironment.InitiateShutdownInternal appId=" + _appId);
600 
601             bool proceed = false;
602 
603             if (!_shutdownInitiated) {
604                 lock (this) {
605                     if (!_shutdownInitiated) {
606                         _shutdownInProgress = true;
607                         proceed = true;
608                         _shutdownInitiated = true;
609                     }
610                 }
611             }
612 
613             if (!proceed) {
614                 return;
615             }
616 
617             HttpRuntime.SetShutdownReason(ApplicationShutdownReason.HostingEnvironment, "HostingEnvironment initiated shutdown");
618 
619             // Avoid calling Environment.StackTrace if we are in the ClientBuildManager (Dev10 bug 824659)
620             if (!BuildManagerHost.InClientBuildManager) {
621                 new EnvironmentPermission(PermissionState.Unrestricted).Assert();
622                 try {
623                     _shutDownStack = Environment.StackTrace;
624                 }
625                 finally {
626                     CodeAccessPermission.RevertAssert();
627                 }
628             }
629 
630             // waitChangeNotification need not be honored in ClientBuildManager (Dev11 bug 264894)
631             if (!BuildManagerHost.InClientBuildManager) {
632                 // this should only be called once, before the cache is disposed, and
633                 // the config records are released.
634                 HttpRuntime.CoalesceNotifications();
635             }
636 
637             RemoveThisAppDomainFromAppManagerTableOnce();
638 
639             // stop all registered objects without blocking
640             ThreadPool.QueueUserWorkItem(this._initiateShutdownWorkItemCallback);
641 #if DBG
642             } catch (Exception ex) {
643                 HandleExceptionFromInitiateShutdownInternal(ex);
644                 throw;
645             }
646 #endif
647         }
648 
649 #if DBG
650         // InitiateShutdownInternal should never throw an exception, but we have seen cases where
651         // CLR bugs can cause it to fail without running to completion. This could cause an ASP.NET
652         // AppDomain never to unload. If we detect that an exception is thrown, we should DebugBreak
653         // so that the fundamentals team can investigate. Taking the Exception object as a parameter
654         // makes it easy to locate when looking at a stack dump.
655         [MethodImpl(MethodImplOptions.NoOptimization | MethodImplOptions.NoInlining)]
HandleExceptionFromInitiateShutdownInternal(Exception ex)656         private static void HandleExceptionFromInitiateShutdownInternal(Exception ex) {
657             Debug.Break();
658         }
659 #endif
660 
661         internal bool HasBeenRemovedFromAppManagerTable {
662             get {
663                 return _hasBeenRemovedFromAppManangerTable;
664             }
665             set {
666                 _hasBeenRemovedFromAppManangerTable = value;
667             }
668         }
669 
RemoveThisAppDomainFromAppManagerTableOnce()670         private void RemoveThisAppDomainFromAppManagerTableOnce() {
671             bool proceed = false;
672             if (!_removedFromAppManager) {
673                 lock (this) {
674                     if (!_removedFromAppManager) {
675                         proceed = true;
676                         _removedFromAppManager = true;
677                     }
678                 }
679             }
680 
681             if (!proceed)
682                 return;
683 
684             if (_appManager != null) {
685                 Debug.Trace("AppManager", "Removing HostingEnvironment from AppManager table, appId=" + _appId);
686                 _appManager.HostingEnvironmentShutdownInitiated(_appId, this);
687             }
688 #if DBG
689             Debug.Trace("FileChangesMonitorIgnoreSubdirChange",
690                         "*** REMOVE APPMANAGER TABLE" + DateTime.Now.ToString("hh:mm:ss.fff", CultureInfo.InvariantCulture)
691                         + ": _appId=" + _appId);
692 #endif
693         }
694 
ShutdownThisAppDomainOnce()695         private void ShutdownThisAppDomainOnce() {
696             bool proceed = false;
697 
698             if (!_appDomainShutdownStarted) {
699                 lock (this) {
700                     if (!_appDomainShutdownStarted) {
701                         proceed = true;
702                         _appDomainShutdownStarted = true;
703                     }
704                 }
705             }
706 
707             if (!proceed)
708                 return;
709 
710             Debug.Trace("AppManager", "HostingEnvironment - shutting down AppDomain, appId=" + _appId);
711 
712             // stop the timer used for idle timeout
713             if (_idleTimeoutMonitor != null) {
714                 _idleTimeoutMonitor.Stop();
715                 _idleTimeoutMonitor = null;
716             }
717 
718             while (_inTrimCache == 1) {
719                 Thread.Sleep(100);
720             }
721 
722             // close all outstanding WebSocket connections and begin winding down code that consumes them
723             AspNetWebSocketManager.Current.AbortAllAndWait();
724 
725             //
726             HttpRuntime.SetUserForcedShutdown();
727 
728             //WOS 1400290: CantUnloadAppDomainException in ISAPI mode, wait until HostingEnvironment.ShutdownThisAppDomainOnce completes
729             _shutdownInProgress = false;
730 
731             HttpRuntime.ShutdownAppDomainWithStackTrace(ApplicationShutdownReason.HostingEnvironment,
732                                                         SR.GetString(SR.Hosting_Env_Restart),
733                                                         _shutDownStack);
734         }
735 
736         //
737         // internal methods called by app manager
738         //
739 
740         // helper for app manager to implement AppHost.CreateAppHost
741         [PermissionSet(SecurityAction.Assert, Unrestricted = true)]
CreateInstance(String assemblyQualifiedName)742         internal ObjectHandle CreateInstance(String assemblyQualifiedName) {
743             Type type = Type.GetType(assemblyQualifiedName, true);
744             return new ObjectHandle(Activator.CreateInstance(type));
745         }
746 
747         // start well known object
748         [PermissionSet(SecurityAction.Assert, Unrestricted = true)]
CreateWellKnownObjectInstance(String assemblyQualifiedName, bool failIfExists)749         internal ObjectHandle CreateWellKnownObjectInstance(String assemblyQualifiedName, bool failIfExists) {
750             Type type = Type.GetType(assemblyQualifiedName, true);
751             IRegisteredObject obj = null;
752             String key = type.FullName;
753             bool exists = false;
754 
755             lock (this) {
756                 obj = _wellKnownObjects[key] as IRegisteredObject;
757 
758                 if (obj == null) {
759                     obj = (IRegisteredObject)Activator.CreateInstance(type);
760                     _wellKnownObjects[key] = obj;
761                 }
762                 else {
763                     exists = true;
764                 }
765             }
766 
767             if (exists && failIfExists) {
768                 throw new InvalidOperationException(SR.GetString(SR.Wellknown_object_already_exists, key));
769             }
770 
771             return new ObjectHandle(obj);
772         }
773 
774         // check if well known object
IsWellKnownObject(Object obj)775         private bool IsWellKnownObject(Object obj) {
776             bool found = false;
777             String key = obj.GetType().FullName;
778 
779             lock (this) {
780                 if (_wellKnownObjects[key] == obj) {
781                     found = true;
782                 }
783             }
784 
785             return found;
786         }
787 
788         // find well known object by type
FindWellKnownObject(String assemblyQualifiedName)789         internal ObjectHandle FindWellKnownObject(String assemblyQualifiedName) {
790             Type type = Type.GetType(assemblyQualifiedName, true);
791             IRegisteredObject obj = null;
792             String key = type.FullName;
793 
794             lock (this) {
795                 obj = _wellKnownObjects[key] as IRegisteredObject;
796             }
797 
798             return (obj != null) ? new ObjectHandle(obj) : null;
799         }
800 
801         // stop well known object by type
802         [PermissionSet(SecurityAction.Assert, Unrestricted = true)]
StopWellKnownObject(String assemblyQualifiedName)803         internal void StopWellKnownObject(String assemblyQualifiedName) {
804             Type type = Type.GetType(assemblyQualifiedName, true);
805             IRegisteredObject obj = null;
806             String key = type.FullName;
807 
808             lock (this) {
809                 obj = _wellKnownObjects[key] as IRegisteredObject;
810                 if (obj != null) {
811                     _wellKnownObjects.Remove(key);
812                     obj.Stop(false);
813                 }
814             }
815         }
816 
IsIdle()817         internal bool IsIdle() {
818             bool isBusy = _isBusy;
819             _isBusy = false;
820             return (!isBusy && _busyCount == 0);
821         }
822 
GetIdleValue()823         internal bool GetIdleValue() {
824             return (!_isBusy && _busyCount == 0);
825         }
826 
IncrementBusyCountInternal()827         internal void IncrementBusyCountInternal() {
828             _isBusy = true;
829             Interlocked.Increment(ref _busyCount);
830         }
831 
DecrementBusyCountInternal()832         internal void DecrementBusyCountInternal() {
833             _isBusy = true;
834             Interlocked.Decrement(ref _busyCount);
835 
836             // Notify idle timeout monitor
837             IdleTimeoutMonitor itm = _idleTimeoutMonitor;
838             if (itm != null) {
839                 itm.LastEvent = DateTime.UtcNow;
840             }
841         }
IsUnloaded()842         internal void IsUnloaded()
843         {
844             return;
845         }
846 
MessageReceivedInternal()847         private void MessageReceivedInternal() {
848             _isBusy = true;
849 
850             IdleTimeoutMonitor itm = _idleTimeoutMonitor;
851             if (itm != null) {
852                 itm.LastEvent = DateTime.UtcNow;
853             }
854         }
855 
856         // the busier the app domain the higher the score
857         internal int LruScore {
858             get {
859                 if (_busyCount > 0)
860                     return _busyCount;
861 
862                 IdleTimeoutMonitor itm = _idleTimeoutMonitor;
863 
864                 if (itm == null)
865                     return 0;
866 
867                 // return negative number of seconds since last activity
868                 return -(int)(DateTime.UtcNow - itm.LastEvent).TotalSeconds;
869             }
870         }
871 
GetApplicationManager()872         internal static ApplicationManager GetApplicationManager() {
873             if (_theHostingEnvironment == null)
874                 return null;
875 
876             return _theHostingEnvironment._appManager;
877         }
878 
879         //
880         // private helpers
881         //
882 
883         // register protocol handler with hosting environment
RegisterRunningObjectInternal(IRegisteredObject obj)884         private void RegisterRunningObjectInternal(IRegisteredObject obj) {
885             lock (this) {
886                 _registeredObjects[obj] = obj;
887 
888                 ISuspendibleRegisteredObject suspendibleObject = obj as ISuspendibleRegisteredObject;
889                 if (suspendibleObject != null) {
890                     _suspendManager.RegisterObject(suspendibleObject);
891                 }
892             }
893         }
894 
895         // unregister protocol handler from hosting environment
UnregisterRunningObjectInternal(IRegisteredObject obj)896         private void UnregisterRunningObjectInternal(IRegisteredObject obj) {
897             bool lastOne = false;
898 
899             lock (this) {
900                 // if it is a well known object, remove it from that table as well
901                 String key = obj.GetType().FullName;
902                 if (_wellKnownObjects[key] == obj) {
903                     _wellKnownObjects.Remove(key);
904                 }
905 
906                 // remove from running objects list
907                 _registeredObjects.Remove(obj);
908 
909                 ISuspendibleRegisteredObject suspendibleObject = obj as ISuspendibleRegisteredObject;
910                 if (suspendibleObject != null) {
911                     _suspendManager.UnregisterObject(suspendibleObject);
912                 }
913 
914                 if (_registeredObjects.Count == 0)
915                     lastOne = true;
916             }
917 
918             if (!lastOne)
919                 return;
920 
921             // shutdown app domain after last protocol handler is gone
922 
923             InitiateShutdownInternal();
924         }
925 
926         // site name
927         [SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands", Justification = "This method is not dangerous.")]
GetSiteName()928         private String GetSiteName() {
929             if (_siteName == null) {
930                 lock (this) {
931                     if (_siteName == null) {
932                         String s = null;
933 
934                         if (_appHost != null) {
935                             //
936                             InternalSecurityPermissions.Unrestricted.Assert();
937                             try {
938                                 s = _appHost.GetSiteName();
939                             }
940                             finally {
941                                 CodeAccessPermission.RevertAssert();
942                             }
943                         }
944 
945                         if (s == null)
946                             s = WebConfigurationHost.DefaultSiteName;
947 
948                         _siteName = s;
949                     }
950                 }
951             }
952 
953             return _siteName;
954         }
955 
956         // site ID
957         [SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands", Justification = "This method is not dangerous.")]
GetSiteID()958         private String GetSiteID() {
959             if (_siteID == null) {
960                 lock (this) {
961                     if (_siteID == null) {
962                         String s = null;
963 
964                         if (_appHost != null) {
965                             //
966                             InternalSecurityPermissions.Unrestricted.Assert();
967                             try {
968                                 s = _appHost.GetSiteID();
969                             }
970                             finally {
971                                 CodeAccessPermission.RevertAssert();
972                             }
973                         }
974 
975                         if (s == null)
976                             s = WebConfigurationHost.DefaultSiteID;
977 
978                         _siteID = s.ToLower(CultureInfo.InvariantCulture);
979                     }
980                 }
981             }
982 
983             return _siteID;
984         }
985 
986         // Return the configPath for the app, e.g. "machine/webroot/1/myapp"
GetAppConfigPath()987         private String GetAppConfigPath() {
988             if (_appConfigPath == null) {
989                 _appConfigPath = WebConfigurationHost.GetConfigPathFromSiteIDAndVPath(SiteID, ApplicationVirtualPathObject);
990             }
991 
992             return _appConfigPath;
993         }
994 
995         // Return the call context slot name to use for a virtual path
GetFixedMappingSlotName(VirtualPath virtualPath)996         private static string GetFixedMappingSlotName(VirtualPath virtualPath) {
997             return "MapPath_" + virtualPath.VirtualPathString.ToLowerInvariant().GetHashCode().ToString(CultureInfo.InvariantCulture);
998         }
999 
1000         /*
1001          * Map a virtual path to a physical path.  i.e. the physicalPath will be returned
1002          * when MapPath is called on the virtual path, bypassing the IApplicationHost
1003          */
GetVirtualPathToFileMapping(VirtualPath virtualPath)1004         private static string GetVirtualPathToFileMapping(VirtualPath virtualPath) {
1005             return CallContext.GetData(GetFixedMappingSlotName(virtualPath)) as string;
1006         }
1007 
1008         /*
1009          * Map a virtual path to a physical path.  i.e. the physicalPath will be returned
1010          * when MapPath is called on the virtual path, bypassing the IApplicationHost
1011          */
AddVirtualPathToFileMapping( VirtualPath virtualPath, string physicalPath)1012         internal static object AddVirtualPathToFileMapping(
1013             VirtualPath virtualPath, string physicalPath) {
1014 
1015             // Save the mapping in the call context, using a key derived from the
1016             // virtual path.  The mapping is only valid for the duration of the request.
1017             CallContext.SetData(GetFixedMappingSlotName(virtualPath), physicalPath);
1018 
1019             // Return a mapping object to keep track of the virtual path, and of the current
1020             // virtualPathProvider.
1021             VirtualPathToFileMappingState state = new VirtualPathToFileMappingState();
1022             state.VirtualPath = virtualPath;
1023             state.VirtualPathProvider = _theHostingEnvironment._virtualPathProvider;
1024 
1025             // Always use the MapPathBasedVirtualPathProvider, otherwise the mapping mechanism
1026             // doesn't work (VSWhidbey 420702)
1027             // Set/Get the VPP on the call context so as not to affect other concurrent requests  (Dev10 852255)
1028             CallContext.SetData(TemporaryVirtualPathProviderKey, _theHostingEnvironment._mapPathBasedVirtualPathProvider);
1029 
1030             return state;
1031         }
1032 
ClearVirtualPathToFileMapping(object state)1033         internal static void ClearVirtualPathToFileMapping(object state) {
1034 
1035             VirtualPathToFileMappingState mapping = (VirtualPathToFileMappingState)state;
1036 
1037             // Clear the mapping from the call context
1038             CallContext.SetData(GetFixedMappingSlotName(mapping.VirtualPath), null);
1039 
1040             // Restore the previous VirtualPathProvider
1041             // Set/Get the VPP on the call context so as not to affect other concurrent requests  (Dev10 852255)
1042             CallContext.SetData(TemporaryVirtualPathProviderKey, null);
1043         }
1044 
MapPathActual(VirtualPath virtualPath, bool permitNull)1045         private string MapPathActual(VirtualPath virtualPath, bool permitNull)
1046         {
1047             string result = null;
1048 
1049             Debug.Assert(virtualPath != null);
1050 
1051             virtualPath.FailIfRelativePath();
1052 
1053             VirtualPath reqpath = virtualPath;
1054 
1055             if (String.CompareOrdinal(reqpath.VirtualPathString, _appVirtualPath.VirtualPathString) == 0) {
1056                 // for application path don't need to call app host
1057                 Debug.Trace("MapPath", reqpath  +" is the app path");
1058                 result = _appPhysicalPath;
1059             }
1060             else {
1061                 using (new ProcessImpersonationContext()) {
1062                     // If there is a mapping for this virtual path in the call context, use it
1063                     result = GetVirtualPathToFileMapping(reqpath);
1064 
1065                     if (result == null) {
1066                         // call host's mappath
1067                         if (_configMapPath == null) {
1068                             Debug.Trace("MapPath", "Missing _configMapPath");
1069                             throw new InvalidOperationException(SR.GetString(SR.Cannot_map_path, reqpath));
1070                         }
1071                         Debug.Trace("MapPath", "call ConfigMapPath (" + reqpath + ")");
1072 
1073                         // see if the IConfigMapPath provider implements the interface
1074                         // with VirtualPath
1075                         try {
1076                             if (null != _configMapPath2) {
1077                                 result = _configMapPath2.MapPath(GetSiteID(), reqpath);
1078                             }
1079                             else {
1080                                 result = _configMapPath.MapPath(GetSiteID(), reqpath.VirtualPathString);
1081                             }
1082                             if (HttpRuntime.IsMapPathRelaxed)
1083                                 result = HttpRuntime.GetRelaxedMapPathResult(result);
1084                         } catch {
1085                             if (HttpRuntime.IsMapPathRelaxed)
1086                                 result = HttpRuntime.GetRelaxedMapPathResult(null);
1087                             else
1088                                 throw;
1089                         }
1090                     }
1091                 }
1092             }
1093 
1094             if (String.IsNullOrEmpty(result)) {
1095                 Debug.Trace("MapPath", "null Result");
1096                 if (!permitNull) {
1097                     if (HttpRuntime.IsMapPathRelaxed)
1098                         result = HttpRuntime.GetRelaxedMapPathResult(null);
1099                     else
1100                         throw new InvalidOperationException(SR.GetString(SR.Cannot_map_path, reqpath));
1101                 }
1102             }
1103             else {
1104                 // ensure extra '\\' in the physical path if the virtual path had extra '/'
1105                 // and the other way -- no extra '\\' in physical if virtual didn't have it.
1106                 if (virtualPath.HasTrailingSlash) {
1107                     if (!UrlPath.PathEndsWithExtraSlash(result) && !UrlPath.PathIsDriveRoot(result))
1108                         result = result + "\\";
1109                 }
1110                 else {
1111                     if (UrlPath.PathEndsWithExtraSlash(result) && !UrlPath.PathIsDriveRoot(result))
1112                         result = result.Substring(0, result.Length - 1);
1113                 }
1114 
1115                 Debug.Trace("MapPath", "    result=" + result);
1116             }
1117 
1118             return result;
1119         }
1120 
1121         //
1122         // public static methods
1123         //
1124 
1125 
1126         // register protocol handler with hosting environment
1127         [SecurityPermission(SecurityAction.Demand, Unrestricted = true)]
RegisterObject(IRegisteredObject obj)1128         public static void RegisterObject(IRegisteredObject obj) {
1129             if (_theHostingEnvironment != null)
1130                 _theHostingEnvironment.RegisterRunningObjectInternal(obj);
1131         }
1132 
1133 
1134         // unregister protocol handler from hosting environment
1135         [SecurityPermission(SecurityAction.Demand, Unrestricted = true)]
UnregisterObject(IRegisteredObject obj)1136         public static void UnregisterObject(IRegisteredObject obj) {
1137             if (_theHostingEnvironment != null)
1138                 _theHostingEnvironment.UnregisterRunningObjectInternal(obj);
1139         }
1140 
1141         // Schedules a task which can run in the background, independent of any request.
1142         // This differs from a normal ThreadPool work item in that ASP.NET can keep track
1143         // of how many work items registered through this API are currently running, and
1144         // the ASP.NET runtime will try not to delay AppDomain shutdown until these work
1145         // items have finished executing.
1146         //
1147         // Usage notes:
1148         // - This API cannot be called outside of an ASP.NET-managed AppDomain.
1149         // - The caller's ExecutionContext is not flowed to the work item.
1150         // - Scheduled work items are not guaranteed to ever execute, e.g., when AppDomain
1151         //   shutdown has already started by the time this API was called.
1152         // - The provided CancellationToken will be signaled when the application is
1153         //   shutting down. The work item should make every effort to honor this token.
1154         //   If a work item does not honor this token and continues executing it will
1155         //   eventually be considered rogue, and the ASP.NET runtime will rudely unload
1156         //   the AppDomain without waiting for the work item to finish.
1157         //
1158         // This overload of QueueBackgroundWorkItem takes a void-returning callback; the
1159         // work item will be considered finished when the callback returns.
1160         [SecurityPermission(SecurityAction.LinkDemand, Unrestricted = true)]
QueueBackgroundWorkItem(Action<CancellationToken> workItem)1161         public static void QueueBackgroundWorkItem(Action<CancellationToken> workItem) {
1162             if (workItem == null) {
1163                 throw new ArgumentNullException("workItem");
1164             }
1165 
1166             QueueBackgroundWorkItem(ct => { workItem(ct); return _completedTask; });
1167         }
1168 
1169         // See documentation on the other overload for a general API overview.
1170         //
1171         // This overload of QueueBackgroundWorkItem takes a Task-returning callback; the
1172         // work item will be considered finished when the returned Task transitions to a
1173         // terminal state.
1174         [SecurityPermission(SecurityAction.LinkDemand, Unrestricted = true)]
QueueBackgroundWorkItem(Func<CancellationToken, Task> workItem)1175         public static void QueueBackgroundWorkItem(Func<CancellationToken, Task> workItem) {
1176             if (workItem == null) {
1177                 throw new ArgumentNullException("workItem");
1178             }
1179             if (_theHostingEnvironment == null) {
1180                 throw new InvalidOperationException(); // can only be called within an ASP.NET AppDomain
1181             }
1182 
1183             _theHostingEnvironment.QueueBackgroundWorkItemInternal(workItem);
1184         }
1185 
QueueBackgroundWorkItemInternal(Func<CancellationToken, Task> workItem)1186         private void QueueBackgroundWorkItemInternal(Func<CancellationToken, Task> workItem) {
1187             Debug.Assert(workItem != null);
1188 
1189             BackgroundWorkScheduler scheduler = Volatile.Read(ref _backgroundWorkScheduler);
1190 
1191             // If the scheduler doesn't exist, lazily create it, but only allow one instance to ever be published to the backing field
1192             if (scheduler == null) {
1193                 BackgroundWorkScheduler newlyCreatedScheduler = new BackgroundWorkScheduler(UnregisterObject, Misc.WriteUnhandledExceptionToEventLog);
1194                 scheduler = Interlocked.CompareExchange(ref _backgroundWorkScheduler, newlyCreatedScheduler, null) ?? newlyCreatedScheduler;
1195                 if (scheduler == newlyCreatedScheduler) {
1196                     RegisterObject(scheduler); // Only call RegisterObject if we just created the "winning" one
1197                 }
1198             }
1199 
1200             scheduler.ScheduleWorkItem(workItem);
1201         }
1202 
1203         // This event is a simple way to hook IStopListeningRegisteredObject.StopListening
1204         // without needing to call RegisterObject. The same restrictions which apply to
1205         // that method apply to this event.
1206         public static event EventHandler StopListening;
1207 
1208         //
1209         // public static methods for the user code to call
1210         //
1211 
1212 
IncrementBusyCount()1213         public static void IncrementBusyCount() {
1214             if (_theHostingEnvironment != null)
1215                 _theHostingEnvironment.IncrementBusyCountInternal();
1216         }
1217 
1218 
DecrementBusyCount()1219         public static void DecrementBusyCount() {
1220             if (_theHostingEnvironment != null)
1221                 _theHostingEnvironment.DecrementBusyCountInternal();
1222         }
1223 
1224 
MessageReceived()1225         public static void MessageReceived() {
1226             if (_theHostingEnvironment != null)
1227                 _theHostingEnvironment.MessageReceivedInternal();
1228         }
1229 
1230         public static bool InClientBuildManager {
1231             get {
1232                 return BuildManagerHost.InClientBuildManager;
1233             }
1234         }
1235 
1236         public static bool IsHosted {
1237             get {
1238                 return (_theHostingEnvironment != null);
1239             }
1240         }
1241 
1242         internal static bool IsUnderIISProcess {
1243             get {
1244                 String process = VersionInfo.ExeName;
1245 
1246                 return process == "aspnet_wp" ||
1247                        process == "w3wp" ||
1248                        process == "inetinfo";
1249             }
1250         }
1251 
1252         internal static bool IsUnderIIS6Process {
1253             get {
1254                 return VersionInfo.ExeName == "w3wp";
1255             }
1256         }
1257 
1258         public static IApplicationHost ApplicationHost {
1259             //DevDivBugs 109864: ASP.NET: path discovery issue - In low trust, it is possible to get the physical path of any virtual path on the machine
1260             [SecurityPermission(SecurityAction.Demand, Unrestricted = true)]
1261             get {
1262                 if (_theHostingEnvironment == null)
1263                     return null;
1264 
1265                 return _theHostingEnvironment._appHost;
1266             }
1267         }
1268 
1269        internal static IApplicationHost ApplicationHostInternal {
1270             get {
1271                 if (_theHostingEnvironment == null)
1272                     return null;
1273 
1274                 return _theHostingEnvironment._appHost;
1275             }
1276         }
1277 
1278         internal IApplicationHost InternalApplicationHost {
1279             get {
1280                 return _appHost;
1281             }
1282         }
1283 
1284         /// <devdoc>
1285         ///    <para>A group of repleacable monitor objects used by ASP.Net subsystems to maintain
1286         ///       application health.</para>
1287         /// </devdoc>
1288         public static ApplicationMonitors ApplicationMonitors {
1289             get {
1290                 if (_theHostingEnvironment == null)
1291                     return null;
1292 
1293                 return _theHostingEnvironment._applicationMonitors;
1294             }
1295         }
1296 
1297         internal static int BusyCount {
1298             get {
1299                 if (_theHostingEnvironment == null)
1300                     return 0;
1301 
1302                 return _theHostingEnvironment._busyCount;
1303             }
1304         }
1305 
1306         internal static bool ShutdownInitiated {
1307             get {
1308                 if (_theHostingEnvironment == null)
1309                     return false;
1310 
1311                 return _theHostingEnvironment._shutdownInitiated;
1312             }
1313         }
1314 
1315 
1316         internal static bool ShutdownInProgress {
1317             get {
1318                 if (_theHostingEnvironment == null)
1319                     return false;
1320 
1321                 return _theHostingEnvironment._shutdownInProgress;
1322             }
1323         }
1324 
1325 
1326         /// <devdoc>
1327         ///    <para>The application ID (metabase path in IIS hosting).</para>
1328         /// </devdoc>
1329         public static String ApplicationID {
1330             get {
1331                 if (_theHostingEnvironment == null)
1332                     return null;
1333 
1334                 InternalSecurityPermissions.AspNetHostingPermissionLevelHigh.Demand();
1335                 return _theHostingEnvironment._appId;
1336             }
1337         }
1338 
1339         internal static String ApplicationIDNoDemand {
1340             get {
1341                 if (_theHostingEnvironment == null) {
1342                     return null;
1343                 }
1344 
1345                 return _theHostingEnvironment._appId;
1346             }
1347         }
1348 
1349 
1350         /// <devdoc>
1351         ///    <para>Physical path to the application root.</para>
1352         /// </devdoc>
1353         public static String ApplicationPhysicalPath {
1354             get {
1355                 if (_theHostingEnvironment == null)
1356                     return null;
1357 
1358                 InternalSecurityPermissions.AppPathDiscovery.Demand();
1359                 return _theHostingEnvironment._appPhysicalPath;
1360             }
1361         }
1362 
1363 
1364         /// <devdoc>
1365         ///    <para>Virtual path to the application root.</para>
1366         /// </devdoc>
1367         public static String ApplicationVirtualPath {
1368             get {
1369                 return VirtualPath.GetVirtualPathStringNoTrailingSlash(ApplicationVirtualPathObject);
1370             }
1371         }
1372 
1373         internal static VirtualPath ApplicationVirtualPathObject {
1374             get {
1375                 if (_theHostingEnvironment == null)
1376                     return null;
1377 
1378                 return _theHostingEnvironment._appVirtualPath;
1379             }
1380         }
1381 
1382 
1383         /// <devdoc>
1384         ///    <para>Site name.</para>
1385         /// </devdoc>
1386         public static String SiteName {
1387             get {
1388                 if (_theHostingEnvironment == null)
1389                     return null;
1390 
1391                 InternalSecurityPermissions.AspNetHostingPermissionLevelMedium.Demand();
1392                 return _theHostingEnvironment.GetSiteName();
1393             }
1394         }
1395 
1396         internal static String SiteNameNoDemand {
1397             get {
1398                 if (_theHostingEnvironment == null)
1399                     return null;
1400 
1401                 return _theHostingEnvironment.GetSiteName();
1402             }
1403         }
1404 
1405         internal static String SiteID {
1406             get {
1407                 if (_theHostingEnvironment == null)
1408                     return null;
1409 
1410                 return _theHostingEnvironment.GetSiteID();
1411             }
1412         }
1413 
1414         internal static IConfigMapPath ConfigMapPath {
1415             get {
1416                 if (_theHostingEnvironment == null)
1417                     return null;
1418 
1419                 return _theHostingEnvironment._configMapPath;
1420             }
1421         }
1422 
1423         internal static String AppConfigPath {
1424             get {
1425                 if (_theHostingEnvironment == null) {
1426                     return null;
1427                 }
1428 
1429                 return _theHostingEnvironment.GetAppConfigPath();
1430             }
1431         }
1432 
1433         // See comments in ApplicationManager.CreateAppDomainWithHostingEnvironment. This is the public API to access the
1434         // information we determined in that method. Defaults to 'false' if our AppDomain data isn't present.
1435         public static bool IsDevelopmentEnvironment {
1436             get {
1437                 return (AppDomain.CurrentDomain.GetData(".devEnvironment") as bool?) == true;
1438             }
1439         }
1440 
1441 
1442         /// <devdoc>
1443         ///    <para>
1444         ///       Gets a reference to the System.Web.Cache.Cache object for the current request.
1445         ///    </para>
1446         /// </devdoc>
1447         public static Cache Cache {
1448             get { return HttpRuntime.Cache; }
1449         }
1450 
1451         internal static NameValueCollection CacheStoreProviderSettings {
1452             get {
1453                 if (_cacheProviderSettings == null) {
1454                     if (AppDomain.CurrentDomain.IsDefaultAppDomain()) {
1455                         Configuration webConfig = WebConfigurationManager.OpenWebConfiguration(null /* root web.config */);
1456                         CacheSection cacheConfig = (CacheSection)webConfig.GetSection("system.web/caching/cache");
1457                         if (cacheConfig != null && cacheConfig.DefaultProvider != null && !String.IsNullOrWhiteSpace(cacheConfig.DefaultProvider)) {
1458                             ProviderSettingsCollection cacheProviders = cacheConfig.Providers;
1459                             if (cacheProviders == null || cacheProviders.Count < 1) {
1460                                 throw new ProviderException(SR.GetString(SR.Def_provider_not_found));
1461                             }
1462 
1463                             ProviderSettings cacheProviderSettings = cacheProviders[cacheConfig.DefaultProvider];
1464                             if (cacheProviderSettings == null) {
1465                                 throw new ProviderException(SR.GetString(SR.Def_provider_not_found));
1466                             }
1467 
1468                             NameValueCollection settings = cacheProviderSettings.Parameters;
1469                             settings["name"] = cacheProviderSettings.Name;
1470                             settings["type"] = cacheProviderSettings.Type;
1471                             _cacheProviderSettings = settings;
1472                         }
1473                     }
1474                     else {
1475                         _cacheProviderSettings = AppDomain.CurrentDomain.GetData(".defaultObjectCacheProvider") as NameValueCollection;
1476                     }
1477                 }
1478 
1479                 // Return a copy, so the consumer can't mess with our copy of the settings
1480                 if (_cacheProviderSettings != null)
1481                     return new NameValueCollection(_cacheProviderSettings);
1482 
1483                 return null;
1484             }
1485         }
1486 
1487         // count of all app domain from app manager
1488         internal static int AppDomainsCount {
1489             get {
1490                 ApplicationManager appManager = GetApplicationManager();
1491                 return (appManager != null) ? appManager.AppDomainsCount : 0;
1492             }
1493         }
1494 
1495         internal static HostingEnvironmentParameters HostingParameters {
1496             get {
1497                 if (_theHostingEnvironment == null)
1498                     return null;
1499 
1500                 return _theHostingEnvironment._hostingParameters;
1501             }
1502         }
1503 
1504         // Return an integer that is unique for each appdomain.  This can be used
1505         // to create things like once-per-appdomain temp files without having different
1506         // processes/appdomains step on each other
1507         private static int s_appDomainUniqueInteger;
1508         internal static int AppDomainUniqueInteger {
1509             get {
1510                 if (s_appDomainUniqueInteger == 0) {
1511                     s_appDomainUniqueInteger = Guid.NewGuid().GetHashCode();
1512                 }
1513 
1514                 return s_appDomainUniqueInteger;
1515             }
1516         }
1517 
1518         public static ApplicationShutdownReason ShutdownReason {
1519             get { return HttpRuntime.ShutdownReason; }
1520         }
1521 
1522         // Was CGlobalModule::OnGlobalStopListening called?
1523         internal static bool StopListeningWasCalled {
1524             get {
1525                 return _stopListeningWasCalled;
1526             }
1527         }
1528 
1529         [SuppressMessage("Microsoft.Reliability", "CA2004:RemoveCallsToGCKeepAlive", Justification = "See comment in function.")]
SetupStopListeningHandler()1530         internal static void SetupStopListeningHandler() {
1531             StopListeningWaitHandle waitHandle = new StopListeningWaitHandle();
1532 
1533             RegisteredWaitHandle registeredWaitHandle = null;
1534             registeredWaitHandle = ThreadPool.UnsafeRegisterWaitForSingleObject(waitHandle, (_, __) => {
1535                 // Referencing the field from within the callback should be sufficient to keep the GC
1536                 // from reclaiming the RegisteredWaitHandle; the race condition is fine.
1537                 GC.KeepAlive(registeredWaitHandle);
1538                 OnGlobalStopListening();
1539             }, null, Timeout.Infinite, executeOnlyOnce: true);
1540         }
1541 
OnGlobalStopListening()1542         private static void OnGlobalStopListening() {
1543             _stopListeningWasCalled = true;
1544 
1545             EventHandler eventHandler = StopListening;
1546             if (eventHandler != null) {
1547                 eventHandler(null /* static means no sender */, EventArgs.Empty);
1548             }
1549 
1550             if (_theHostingEnvironment != null) {
1551                 _theHostingEnvironment.FireStopListeningHandlers();
1552             }
1553         }
1554 
1555         [SuppressMessage("Microsoft.Reliability", "CA2002:DoNotLockOnObjectsWithWeakIdentity", Justification = "'this' always has strong identity.")]
FireStopListeningHandlers()1556         private void FireStopListeningHandlers() {
1557             List<IStopListeningRegisteredObject> listeners = new List<IStopListeningRegisteredObject>();
1558             lock (this) {
1559                 foreach (DictionaryEntry e in _registeredObjects) {
1560                     IStopListeningRegisteredObject listener = e.Key as IStopListeningRegisteredObject;
1561                     if (listener != null) {
1562                         listeners.Add(listener);
1563                     }
1564                 }
1565             }
1566 
1567             foreach (var listener in listeners) {
1568                 listener.StopListening();
1569             }
1570         }
1571 
1572         /// <devdoc>
1573         ///    <para>Initiate app domain unloading for the current app.</para>
1574         /// </devdoc>
1575         [SecurityPermission(SecurityAction.Demand, Unrestricted = true)]
InitiateShutdown()1576         public static void InitiateShutdown() {
1577             if (_theHostingEnvironment != null)
1578                 _theHostingEnvironment.InitiateShutdownInternal();
1579         }
1580 
InitiateShutdownWithoutDemand()1581         internal static void InitiateShutdownWithoutDemand() {
1582             if (_theHostingEnvironment != null)
1583                 _theHostingEnvironment.InitiateShutdownInternal();
1584         }
1585 
1586         //
1587         // Internal methods for the ApplicationManager to suspend / resume this application.
1588         // Using GCHandle instead of ObjectHandle means we don't need to worry about lease lifetimes.
1589         //
1590 
SuspendApplication()1591         internal IntPtr SuspendApplication() {
1592             var state = _suspendManager.Suspend();
1593             return GCUtil.RootObject(state);
1594         }
1595 
ResumeApplication(IntPtr state)1596         internal void ResumeApplication(IntPtr state) {
1597             var unwrappedState = GCUtil.UnrootObject(state);
1598             _suspendManager.Resume(unwrappedState);
1599         }
1600 
1601         /// <devdoc>
1602         ///    <para>Maps a virtual path to a physical path.</para>
1603         /// </devdoc>
MapPath(string virtualPath)1604         public static string MapPath(string virtualPath) {
1605             return MapPath(VirtualPath.Create(virtualPath));
1606         }
1607 
MapPath(VirtualPath virtualPath)1608         internal static string MapPath(VirtualPath virtualPath) {
1609             if (_theHostingEnvironment == null)
1610                 return null;
1611 
1612             String path = MapPathInternal(virtualPath);
1613 
1614             if (path != null)
1615                 InternalSecurityPermissions.PathDiscovery(path).Demand();
1616 
1617             return path;
1618         }
1619 
MapPathInternal(string virtualPath)1620         internal static String MapPathInternal(string virtualPath) {
1621             return MapPathInternal(VirtualPath.Create(virtualPath));
1622         }
1623 
MapPathInternal(VirtualPath virtualPath)1624         internal static String MapPathInternal(VirtualPath virtualPath) {
1625             if (_theHostingEnvironment == null) {
1626                 return null;
1627             }
1628 
1629             return _theHostingEnvironment.MapPathActual(virtualPath, false);
1630         }
1631 
MapPathInternal(string virtualPath, bool permitNull)1632         internal static String MapPathInternal(string virtualPath, bool permitNull) {
1633             return MapPathInternal(VirtualPath.Create(virtualPath), permitNull);
1634         }
1635 
MapPathInternal(VirtualPath virtualPath, bool permitNull)1636         internal static String MapPathInternal(VirtualPath virtualPath, bool permitNull) {
1637             if (_theHostingEnvironment == null) {
1638                 return null;
1639             }
1640 
1641             return _theHostingEnvironment.MapPathActual(virtualPath, permitNull);
1642         }
1643 
MapPathInternal(string virtualPath, string baseVirtualDir, bool allowCrossAppMapping)1644         internal static string MapPathInternal(string virtualPath, string baseVirtualDir, bool allowCrossAppMapping) {
1645             return MapPathInternal(VirtualPath.Create(virtualPath),
1646                 VirtualPath.CreateNonRelative(baseVirtualDir), allowCrossAppMapping);
1647         }
1648 
MapPathInternal(VirtualPath virtualPath, VirtualPath baseVirtualDir, bool allowCrossAppMapping)1649         internal static string MapPathInternal(VirtualPath virtualPath, VirtualPath baseVirtualDir, bool allowCrossAppMapping) {
1650             Debug.Assert(baseVirtualDir != null, "baseVirtualDir != null");
1651 
1652             // Combine it with the base and reduce
1653             virtualPath = baseVirtualDir.Combine(virtualPath);
1654 
1655             if (!allowCrossAppMapping && !virtualPath.IsWithinAppRoot)
1656                 throw new ArgumentException(SR.GetString(SR.Cross_app_not_allowed, virtualPath));
1657 
1658             return MapPathInternal(virtualPath);
1659         }
1660 
GetPathLevel(String path)1661         internal static WebApplicationLevel GetPathLevel(String path) {
1662             WebApplicationLevel pathLevel = WebApplicationLevel.AboveApplication;
1663 
1664             if (_theHostingEnvironment != null && !String.IsNullOrEmpty(path)) {
1665                 String appPath = ApplicationVirtualPath;
1666 
1667                 if (appPath == "/") {
1668                     if (path == "/") {
1669                         pathLevel = WebApplicationLevel.AtApplication;
1670                     }
1671                     else if (path[0] == '/') {
1672                         pathLevel = WebApplicationLevel.BelowApplication;
1673                     }
1674                 }
1675                 else {
1676                     if (StringUtil.EqualsIgnoreCase(appPath, path)) {
1677                         pathLevel = WebApplicationLevel.AtApplication;
1678                     }
1679                     else if (path.Length > appPath.Length && path[appPath.Length] == '/' &&
1680                         StringUtil.StringStartsWithIgnoreCase(path, appPath)) {
1681 
1682                         pathLevel = WebApplicationLevel.BelowApplication;
1683                     }
1684                 }
1685             }
1686 
1687             return pathLevel;
1688         }
1689 
1690 
1691         //
1692         // Impersonation helpers
1693         //
1694         // user token for the app (hosting / unc)
1695         internal static IntPtr ApplicationIdentityToken {
1696             get {
1697                 if (_theHostingEnvironment == null) {
1698                     return IntPtr.Zero;
1699                 }
1700                 else {
1701                     if (_theHostingEnvironment._appIdentityTokenSet)
1702                         return _theHostingEnvironment._appIdentityToken;
1703                     else
1704                         return _theHostingEnvironment._configToken;
1705                 }
1706             }
1707         }
1708 
1709 
1710         // check if application impersonation != process impersonation
1711         internal static bool HasHostingIdentity {
1712             get {
1713                 return (ApplicationIdentityToken != IntPtr.Zero);
1714             }
1715         }
1716 
1717         // impersonate application identity
1718         [SecurityPermission(SecurityAction.Demand, ControlPrincipal = true)]
Impersonate()1719         public static IDisposable Impersonate() {
1720             return new ApplicationImpersonationContext();
1721         }
1722 
1723         // impersonate the given user identity
1724         [SecurityPermission(SecurityAction.Demand, Unrestricted = true)]
Impersonate(IntPtr token)1725         public static IDisposable Impersonate(IntPtr token) {
1726             if (token == IntPtr.Zero) {
1727                 return new ProcessImpersonationContext();
1728             }
1729             else {
1730                 return new ImpersonationContext(token);
1731             }
1732         }
1733 
1734         // impersonate as configured for a given path
1735         [SecurityPermission(SecurityAction.Demand, Unrestricted = true)]
Impersonate(IntPtr userToken, String virtualPath)1736         public static IDisposable Impersonate(IntPtr userToken, String virtualPath) {
1737             virtualPath = UrlPath.MakeVirtualPathAppAbsoluteReduceAndCheck(virtualPath);
1738 
1739             if (_theHostingEnvironment == null) {
1740                 return Impersonate(userToken);
1741             }
1742 
1743             IdentitySection c = RuntimeConfig.GetConfig(virtualPath).Identity;
1744             if (c.Impersonate) {
1745                 if (c.ImpersonateToken != IntPtr.Zero) {
1746                     return new ImpersonationContext(c.ImpersonateToken);
1747                 }
1748                 else {
1749                     return new ImpersonationContext(userToken);
1750                 }
1751             }
1752             else {
1753                 return new ApplicationImpersonationContext();
1754             }
1755         }
1756 
1757         //
1758         //  Culture helpers
1759         //
1760 
SetCultures()1761         public static IDisposable SetCultures() {
1762             return SetCultures(RuntimeConfig.GetAppLKGConfig().Globalization);
1763         }
1764 
SetCultures(string virtualPath)1765         public static IDisposable SetCultures(string virtualPath) {
1766             virtualPath = UrlPath.MakeVirtualPathAppAbsoluteReduceAndCheck(virtualPath);
1767             return SetCultures(RuntimeConfig.GetConfig(virtualPath).Globalization);
1768         }
1769 
SetCultures(GlobalizationSection gs)1770         private static IDisposable SetCultures(GlobalizationSection gs) {
1771             CultureContext c = new CultureContext();
1772 
1773             if (gs != null) {
1774                 CultureInfo culture = null;
1775                 CultureInfo uiCulture = null;
1776 
1777                 if (gs.Culture != null && gs.Culture.Length > 0) {
1778                     try {
1779                         culture = HttpServerUtility.CreateReadOnlyCultureInfo(gs.Culture);
1780                     }
1781                     catch {
1782                     }
1783                 }
1784 
1785                 if (gs.UICulture != null && gs.UICulture.Length > 0) {
1786                     try {
1787                         uiCulture = HttpServerUtility.CreateReadOnlyCultureInfo(gs.UICulture);
1788                     }
1789                     catch {
1790                     }
1791                 }
1792 
1793                 c.SetCultures(culture, uiCulture);
1794             }
1795 
1796             return c;
1797         }
1798 
1799 
1800         class CultureContext : IDisposable {
1801             CultureInfo _savedCulture;
1802             CultureInfo _savedUICulture;
1803 
CultureContext()1804             internal CultureContext() {
1805             }
1806 
IDisposable.Dispose()1807             void IDisposable.Dispose() {
1808                 RestoreCultures();
1809             }
1810 
SetCultures(CultureInfo culture, CultureInfo uiCulture)1811             internal void SetCultures(CultureInfo culture, CultureInfo uiCulture) {
1812                 CultureInfo currentCulture = Thread.CurrentThread.CurrentCulture;
1813                 CultureInfo currentUICulture = Thread.CurrentThread.CurrentUICulture;
1814 
1815                 if (culture != null && culture != currentCulture) {
1816                     Thread.CurrentThread.CurrentCulture = culture;
1817                     _savedCulture = currentCulture;
1818                 }
1819 
1820                 if (uiCulture != null && uiCulture != currentCulture) {
1821                     Thread.CurrentThread.CurrentUICulture = uiCulture;
1822                     _savedUICulture = currentUICulture;
1823                 }
1824             }
1825 
RestoreCultures()1826             internal void RestoreCultures() {
1827                 if (_savedCulture != null && _savedCulture != Thread.CurrentThread.CurrentCulture) {
1828                     Thread.CurrentThread.CurrentCulture = _savedCulture;
1829                     _savedCulture = null;
1830                 }
1831 
1832                 if (_savedUICulture != null && _savedUICulture != Thread.CurrentThread.CurrentUICulture) {
1833                     Thread.CurrentThread.CurrentUICulture = _savedUICulture;
1834                     _savedUICulture = null;
1835                 }
1836             }
1837         }
1838 
1839         //
1840         // VirtualPathProvider related code
1841         //
1842 
1843         private VirtualPathProvider _virtualPathProvider;
1844         private VirtualPathProvider _mapPathBasedVirtualPathProvider;
1845 
1846 
1847         public static VirtualPathProvider VirtualPathProvider {
1848             get {
1849                 if (_theHostingEnvironment == null)
1850                     return null;
1851 
1852                 // Set/Get the VPP on the call context so as not to affect other concurrent requests  (Dev10 852255)
1853                 var tempVPP = CallContext.GetData(TemporaryVirtualPathProviderKey);
1854                 if (tempVPP != null) {
1855                     return tempVPP as VirtualPathProvider;
1856                 }
1857 
1858                 return _theHostingEnvironment._virtualPathProvider;
1859             }
1860         }
1861 
1862         internal static bool UsingMapPathBasedVirtualPathProvider {
1863             get {
1864                 if (_theHostingEnvironment == null)
1865                     return true;
1866 
1867                 return (_theHostingEnvironment._virtualPathProvider ==
1868                     _theHostingEnvironment._mapPathBasedVirtualPathProvider);
1869             }
1870         }
1871 
1872         // [AspNetHostingPermission(SecurityAction.Demand, Level=AspNetHostingPermissionLevel.High)]
1873         // Removed the above LinkDemand for AspNetHostingPermissionLevel.High. If we decide to add VPP
1874         // support for config in the future, we should have a separate API with a demand for registering
1875         // VPPs supporting configuration.
RegisterVirtualPathProvider(VirtualPathProvider virtualPathProvider)1876         public static void RegisterVirtualPathProvider(VirtualPathProvider virtualPathProvider) {
1877 
1878             if (_theHostingEnvironment == null)
1879                 throw new InvalidOperationException();
1880 
1881             // Ignore the VirtualPathProvider on precompiled sites (VSWhidbey 368169,404844)
1882             if (BuildManager.IsPrecompiledApp)
1883                 return;
1884 
1885             RegisterVirtualPathProviderInternal(virtualPathProvider);
1886         }
1887 
RegisterVirtualPathProviderInternal(VirtualPathProvider virtualPathProvider)1888         internal static void RegisterVirtualPathProviderInternal(VirtualPathProvider virtualPathProvider) {
1889             VirtualPathProvider previous = _theHostingEnvironment._virtualPathProvider;
1890             _theHostingEnvironment._virtualPathProvider = virtualPathProvider;
1891 
1892             // Give it the previous provider so it can delegate if needed
1893             virtualPathProvider.Initialize(previous);
1894         }
1895 
1896         // Helper class used to keep track of state when using
1897         // AddVirtualPathToFileMapping & ClearVirtualPathToFileMapping
1898         internal class VirtualPathToFileMappingState {
1899             internal VirtualPath VirtualPath;
1900             internal VirtualPathProvider VirtualPathProvider;
1901         }
1902 
1903         internal static IProcessHostSupportFunctions SupportFunctions {
1904             get {
1905                 return _functions;
1906             }
1907             set {
1908                 _functions = value;
1909             }
1910         }
1911 
1912         [SuppressMessage("Microsoft.Naming", "CA1705:LongAcronymsShouldBePascalCased",
1913                          Justification="matches casing of config attribute")]
1914         public static int MaxConcurrentRequestsPerCPU {
1915             get {
1916                 if (!HttpRuntime.UseIntegratedPipeline) {
1917                     throw new PlatformNotSupportedException(SR.GetString(SR.Requires_Iis_Integrated_Mode));
1918                 }
1919                 return UnsafeIISMethods.MgdGetMaxConcurrentRequestsPerCPU();
1920             }
1921             [SecurityPermission(SecurityAction.Demand, Unrestricted = true)]
1922             set {
1923                 if (!HttpRuntime.UseIntegratedPipeline) {
1924                     throw new PlatformNotSupportedException(SR.GetString(SR.Requires_Iis_Integrated_Mode));
1925                 }
1926                 int hr = UnsafeIISMethods.MgdSetMaxConcurrentRequestsPerCPU(value);
1927                 switch (hr) {
1928                     case HResults.S_FALSE:
1929                         // Because "maxConcurrentRequestsPerCPU" is currently zero, we cannot set the value, since that would
1930                         // enable the feature, which can only be done via configuration.
1931                         throw new InvalidOperationException(SR.GetString(SR.Queue_limit_is_zero, "maxConcurrentRequestsPerCPU"));
1932                     case HResults.E_INVALIDARG:
1933                         // The value must be greater than zero.  A value of zero would disable the feature, but this can only be done via configuration.
1934                         throw new ArgumentException(SR.GetString(SR.Invalid_queue_limit));
1935                 }
1936             }
1937         }
1938 
1939         [SuppressMessage("Microsoft.Naming", "CA1705:LongAcronymsShouldBePascalCased",
1940                          Justification="matches casing of config attribute")]
1941         public static int MaxConcurrentThreadsPerCPU {
1942             get {
1943                 if (!HttpRuntime.UseIntegratedPipeline) {
1944                     throw new PlatformNotSupportedException(SR.GetString(SR.Requires_Iis_Integrated_Mode));
1945                 }
1946                 return UnsafeIISMethods.MgdGetMaxConcurrentThreadsPerCPU();
1947             }
1948             [SecurityPermission(SecurityAction.Demand, Unrestricted = true)]
1949             set {
1950                 if (!HttpRuntime.UseIntegratedPipeline) {
1951                     throw new PlatformNotSupportedException(SR.GetString(SR.Requires_Iis_Integrated_Mode));
1952                 }
1953                 int hr = UnsafeIISMethods.MgdSetMaxConcurrentThreadsPerCPU(value);
1954                 switch (hr) {
1955                     case HResults.S_FALSE:
1956                         // Because "maxConcurrentThreadsPerCPU" is currently zero, we cannot set the value, since that would
1957                         // enable the feature, which can only be done via configuration.
1958                         throw new InvalidOperationException(SR.GetString(SR.Queue_limit_is_zero, "maxConcurrentThreadsPerCPU"));
1959                     case HResults.E_INVALIDARG:
1960                         // The value must be greater than zero.  A value of zero would disable the feature, but this can only be done via configuration.
1961                         throw new ArgumentException(SR.GetString(SR.Invalid_queue_limit));
1962                 }
1963             }
1964         }
1965 
1966         /// <summary>
1967         /// Returns the ASP.NET hosted domain.
1968         /// </summary>
1969         internal AppDomain HostedAppDomain {
1970             get {
1971                 return AppDomain.CurrentDomain;
1972             }
1973         }
1974 
1975     }
1976 }
1977 
1978