1 //------------------------------------------------------------------------------
2 // <copyright file="HostingEnvironment.cs" company="Microsoft">
3 // Copyright (c) Microsoft Corporation. All rights reserved.
5 //------------------------------------------------------------------------------
7 namespace System.Web.Hosting {
9 using System.Collections;
10 using System.Configuration;
11 using System.Diagnostics.CodeAnalysis;
12 using System.Globalization;
14 using System.Runtime.Caching;
15 using System.Runtime.CompilerServices;
16 using System.Runtime.InteropServices;
17 using System.Runtime.Remoting;
18 using System.Runtime.Remoting.Messaging;
19 using System.Security;
20 using System.Security.Permissions;
21 using System.Security.Policy;
22 using System.Security.Principal;
24 using System.Threading;
25 using System.Threading.Tasks;
27 using System.Web.Caching;
28 using System.Web.Compilation;
29 using System.Web.Configuration;
30 using System.Web.Management;
31 using System.Web.Util;
32 using System.Web.WebSockets;
33 using Microsoft.Win32;
34 using System.Collections.Generic;
37 internal enum HostingEnvironmentFlags {
39 HideFromAppManager = 1,
40 ThrowHostingInitErrors = 2,
41 DontCallAppInitialize = 4,
42 ClientBuildManager = 8,
43 SupportsMultiTargeting = 16,
47 internal class HostingEnvironmentParameters {
48 private HostingEnvironmentFlags _hostingFlags;
49 private ClientBuildManagerParameter _clientBuildManagerParameter;
50 private string _precompTargetPhysicalDir;
51 private string _iisExpressVersion;
53 public HostingEnvironmentFlags HostingFlags {
54 get { return _hostingFlags; }
55 set { _hostingFlags = value; }
58 // Directory where the precompiled site is placed
59 public string PrecompilationTargetPhysicalDirectory {
60 get { return _precompTargetPhysicalDir; }
62 _precompTargetPhysicalDir = FileUtil.FixUpPhysicalDirectory(value);
66 // Determines the behavior of the precompilation
67 public ClientBuildManagerParameter ClientBuildManagerParameter {
68 get { return _clientBuildManagerParameter; }
69 set { _clientBuildManagerParameter = value; }
72 // Determines which config system to load
73 public string IISExpressVersion {
74 get { return _iisExpressVersion; }
75 set { _iisExpressVersion = value; }
78 // Determines what FileChangeMonitor mode to use
79 public FcnMode FcnMode {
84 // Should FileChangesMonitor skip reading and caching DACLs?
85 public bool FcnSkipReadAndCacheDacls {
90 public KeyValuePair<string, bool>[] ClrQuirksSwitches {
96 public sealed class HostingEnvironment : MarshalByRefObject {
98 private static HostingEnvironment _theHostingEnvironment;
99 private EventHandler _onAppDomainUnload;
100 private ApplicationManager _appManager;
101 private HostingEnvironmentParameters _hostingParameters;
102 private IApplicationHost _appHost;
103 private bool _externalAppHost;
104 private IConfigMapPath _configMapPath;
105 private IConfigMapPath2 _configMapPath2;
106 private IntPtr _configToken;
108 private IdentitySection _appIdentity;
109 private IntPtr _appIdentityToken;
110 private bool _appIdentityTokenSet;
112 private String _appId;
113 private VirtualPath _appVirtualPath;
114 private String _appPhysicalPath;
115 private String _siteName;
116 private String _siteID;
117 private String _appConfigPath;
119 private bool _isBusy;
120 private int _busyCount;
122 private volatile static bool _stopListeningWasCalled; // static since it's process-wide
123 private bool _removedFromAppManager;
124 private bool _appDomainShutdownStarted;
125 private bool _shutdownInitiated;
126 private bool _shutdownInProgress;
127 private String _shutDownStack;
129 private int _inTrimCache;
130 private ObjectCacheHost _objectCacheHost;
132 // table of well know objects keyed by type
133 private Hashtable _wellKnownObjects = new Hashtable();
135 // list of registered IRegisteredObject instances, suspend listeners, and background work items
136 private Hashtable _registeredObjects = new Hashtable();
137 private SuspendManager _suspendManager = new SuspendManager();
138 private BackgroundWorkScheduler _backgroundWorkScheduler = null; // created on demand
139 private static readonly Task<object> _completedTask = Task.FromResult<object>(null);
141 // callback to make InitiateShutdown non-blocking
142 private WaitCallback _initiateShutdownWorkItemCallback;
144 // inside app domain idle shutdown logic
145 private IdleTimeoutMonitor _idleTimeoutMonitor;
147 private static IProcessHostSupportFunctions _functions;
148 private static bool _hasBeenRemovedFromAppManangerTable;
150 private const string TemporaryVirtualPathProviderKey = "__TemporaryVirtualPathProvider__";
152 // Determines what FileChangeMonitor mode to use
153 internal static FcnMode FcnMode {
155 if (_theHostingEnvironment != null && _theHostingEnvironment._hostingParameters != null) {
156 return _theHostingEnvironment._hostingParameters.FcnMode;
158 return FcnMode.NotSet;
162 internal static bool FcnSkipReadAndCacheDacls {
164 if (_theHostingEnvironment != null && _theHostingEnvironment._hostingParameters != null) {
165 return _theHostingEnvironment._hostingParameters.FcnSkipReadAndCacheDacls;
171 public override Object InitializeLifetimeService() {
172 return null; // never expire lease
176 [SecurityPermission(SecurityAction.Demand, Unrestricted = true)]
177 public HostingEnvironment() {
178 if (_theHostingEnvironment != null)
179 throw new InvalidOperationException(SR.GetString(SR.Only_1_HostEnv));
181 // remember singleton HostingEnvironment in a static
182 _theHostingEnvironment = this;
184 // start watching for app domain unloading
185 _onAppDomainUnload = new EventHandler(OnAppDomainUnload);
186 Thread.GetDomain().DomainUnload += _onAppDomainUnload;
188 // VSO 160528: We used to listen to the default AppDomain's UnhandledException only.
189 // However, non-serializable exceptions cannot be passed to the default domain. Therefore
190 // we should try to log exceptions in application AppDomains.
191 Thread.GetDomain().UnhandledException += new UnhandledExceptionEventHandler(ApplicationManager.OnUnhandledException);
194 internal long TrimCache(int percent) {
195 if (Interlocked.Exchange(ref _inTrimCache, 1) != 0)
198 long trimmedOrExpired = 0;
199 // do nothing if we're shutting down
200 if (!_shutdownInitiated) {
201 trimmedOrExpired = HttpRuntime.CacheInternal.TrimCache(percent);
202 if (_objectCacheHost != null && !_shutdownInitiated) {
203 trimmedOrExpired += _objectCacheHost.TrimCache(percent);
206 return trimmedOrExpired;
209 Interlocked.Exchange(ref _inTrimCache, 0);
213 private void OnAppDomainUnload(Object unusedObject, EventArgs unusedEventArgs) {
214 Debug.Trace("PipelineRuntime", "HE.OnAppDomainUnload");
216 Thread.GetDomain().DomainUnload -= _onAppDomainUnload;
218 // check for unexpected shutdown
219 if (!_removedFromAppManager) {
220 RemoveThisAppDomainFromAppManagerTableOnce();
223 HttpRuntime.RecoverFromUnexceptedAppDomainUnload();
225 // call Stop on all registered objects with immediate = true
226 StopRegisteredObjects(true);
228 // notify app manager
229 if (_appManager != null) {
230 // disconnect the real app host and substitute it with a bogus one
231 // to avoid exceptions later when app host is called (it normally wouldn't)
232 IApplicationHost originalAppHost = null;
234 if (_externalAppHost) {
235 originalAppHost = _appHost;
236 _appHost = new SimpleApplicationHost(_appVirtualPath, _appPhysicalPath);
237 _externalAppHost = false;
240 IDisposable configSystem = _configMapPath2 as IDisposable;
241 if (configSystem != null) {
242 configSystem.Dispose();
245 _appManager.HostingEnvironmentShutdownComplete(_appId, originalAppHost);
248 // free the config access token
249 if (_configToken != IntPtr.Zero) {
250 UnsafeNativeMethods.CloseHandle(_configToken);
251 _configToken = IntPtr.Zero;
259 // called from app manager right after app domain (and hosting env) is created
260 internal void Initialize(ApplicationManager appManager, IApplicationHost appHost, IConfigMapPathFactory configMapPathFactory, HostingEnvironmentParameters hostingParameters, PolicyLevel policyLevel) {
261 Initialize(appManager, appHost, configMapPathFactory, hostingParameters, policyLevel, null);
264 [PermissionSet(SecurityAction.Assert, Unrestricted = true)]
265 [SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands", Justification = "We carefully control this method's callers.")]
266 internal void Initialize(ApplicationManager appManager, IApplicationHost appHost, IConfigMapPathFactory configMapPathFactory,
267 HostingEnvironmentParameters hostingParameters, PolicyLevel policyLevel,
268 Exception appDomainCreationException) {
270 _hostingParameters = hostingParameters;
272 HostingEnvironmentFlags hostingFlags = HostingEnvironmentFlags.Default;
273 if (_hostingParameters != null) {
274 hostingFlags = _hostingParameters.HostingFlags;
275 if (_hostingParameters.IISExpressVersion != null) {
276 ServerConfig.IISExpressVersion = _hostingParameters.IISExpressVersion;
280 // Keep track of the app manager, unless HideFromAppManager flag was passed
281 if ((hostingFlags & HostingEnvironmentFlags.HideFromAppManager) == 0)
282 _appManager = appManager;
284 if ((hostingFlags & HostingEnvironmentFlags.ClientBuildManager) != 0) {
285 BuildManagerHost.InClientBuildManager = true;
288 if ((hostingFlags & HostingEnvironmentFlags.SupportsMultiTargeting) != 0) {
289 BuildManagerHost.SupportsMultiTargeting = true;
292 // Set CLR quirks switches before the config system is initialized since config might depend on them
293 if (_hostingParameters != null && _hostingParameters.ClrQuirksSwitches != null && _hostingParameters.ClrQuirksSwitches.Length > 0) {
294 SetClrQuirksSwitches(_hostingParameters.ClrQuirksSwitches);
298 // init config system using private config if applicable
300 if (appHost is ISAPIApplicationHost && !ServerConfig.UseMetabase) {
301 string rootWebConfigPath = ((ISAPIApplicationHost)appHost).ResolveRootWebConfigPath();
302 if (!String.IsNullOrEmpty(rootWebConfigPath)) {
303 Debug.Assert(File.Exists(rootWebConfigPath), "File.Exists(rootWebConfigPath)");
304 HttpConfigurationSystem.RootWebConfigurationFilePath = rootWebConfigPath;
307 // we need to explicit create a COM proxy in this app domain
308 // so we don't go back to the default domain or have lifetime issues
309 // remember support functions
310 IProcessHostSupportFunctions proxyFunctions = ((ISAPIApplicationHost)appHost).SupportFunctions;
311 if (null != proxyFunctions) {
312 _functions = Misc.CreateLocalSupportFunctions(proxyFunctions);
316 _appId = HttpRuntime.AppDomainAppId;
317 _appVirtualPath = HttpRuntime.AppDomainAppVirtualPathObject;
318 _appPhysicalPath = HttpRuntime.AppDomainAppPathInternal;
321 _configMapPath = configMapPathFactory.Create(_appVirtualPath.VirtualPathString, _appPhysicalPath);
322 HttpConfigurationSystem.EnsureInit(_configMapPath, true, false);
324 // attempt to cache and use IConfigMapPath2 provider
325 // which supports VirtualPath's to save on conversions
326 _configMapPath2 = _configMapPath as IConfigMapPath2;
329 _initiateShutdownWorkItemCallback = new WaitCallback(this.InitiateShutdownWorkItemCallback);
331 // notify app manager
332 if (_appManager != null) {
333 _appManager.HostingEnvironmentActivated(CacheMemorySizePressure.EffectiveProcessMemoryLimit);
336 // make sure there is always app host
337 if (_appHost == null) {
338 _appHost = new SimpleApplicationHost(_appVirtualPath, _appPhysicalPath);
341 _externalAppHost = true;
344 // remember the token to access config
345 _configToken = _appHost.GetConfigToken();
347 // Start with a MapPath based virtual path provider
348 _mapPathBasedVirtualPathProvider = new MapPathBasedVirtualPathProvider();
349 _virtualPathProvider = _mapPathBasedVirtualPathProvider;
351 // initiaze HTTP-independent features
352 HttpRuntime.InitializeHostingFeatures(hostingFlags, policyLevel, appDomainCreationException);
354 // VSWhidbey 393259. Do not monitor idle timeout for CBM since Venus
355 // will always restart a new appdomain if old one is shutdown.
356 if (!BuildManagerHost.InClientBuildManager) {
357 // start monitoring for idle inside app domain
358 StartMonitoringForIdleTimeout();
361 // notify app manager if the app domain limit is violated
362 EnforceAppDomainLimit();
364 // get application identity (for explicit impersonation mode)
365 GetApplicationIdentity();
367 // call AppInitialize, unless the flag says not to do it (e.g. CBM scenario).
368 // Also, don't call it if HostingInit failed (VSWhidbey 210495)
369 if(!HttpRuntime.HostingInitFailed) {
371 BuildManager.ExecutePreAppStart();
372 if ((hostingFlags & HostingEnvironmentFlags.DontCallAppInitialize) == 0) {
373 BuildManager.CallAppInitializeMethod();
376 catch (Exception e) {
377 // could throw compilation errors in 'code' - report them with first http request
378 HttpRuntime.InitializationException = e;
380 if ((hostingFlags & HostingEnvironmentFlags.ThrowHostingInitErrors) != 0) {
387 private void InitializeObjectCacheHostPrivate() {
388 // set ObjectCacheHost if the Host is not already set
389 if (ObjectCache.Host == null) {
390 ObjectCacheHost objectCacheHost = new ObjectCacheHost();
391 ObjectCache.Host = objectCacheHost;
392 _objectCacheHost = objectCacheHost;
396 internal static void InitializeObjectCacheHost() {
397 if (_theHostingEnvironment != null) {
398 _theHostingEnvironment.InitializeObjectCacheHostPrivate();
402 private void StartMonitoringForIdleTimeout() {
403 HostingEnvironmentSection hostEnvConfig = RuntimeConfig.GetAppLKGConfig().HostingEnvironment;
405 TimeSpan idleTimeout = (hostEnvConfig != null) ? hostEnvConfig.IdleTimeout : HostingEnvironmentSection.DefaultIdleTimeout;
407 // always create IdleTimeoutMonitor (even if config value is TimeSpan.MaxValue (infinite)
408 // IdleTimeoutMonitor is also needed to keep the last event for app domain set trimming
409 // and the timer is used to trim the application instances
410 _idleTimeoutMonitor = new IdleTimeoutMonitor(idleTimeout);
413 // enforce app domain limit
414 private void EnforceAppDomainLimit() {
415 if (_appManager == null) /// detached app domain
421 ProcessModelSection pmConfig = RuntimeConfig.GetMachineConfig().ProcessModel;
422 limit = pmConfig.MaxAppDomains;
427 if (limit > 0 && _appManager.AppDomainsCount >= limit) {
428 // current app domain doesn't count yet (not in the table)
429 // that's why '>=' above
430 _appManager.ReduceAppDomainsCount(limit);
434 private void GetApplicationIdentity() {
435 // if the explicit impersonation is set, use it instead of UNC identity
437 IdentitySection c = RuntimeConfig.GetAppConfig().Identity;
438 if (c.Impersonate && c.ImpersonateToken != IntPtr.Zero) {
440 _appIdentityToken = c.ImpersonateToken;
443 _appIdentityToken = _configToken;
445 _appIdentityTokenSet = true;
451 private static void SetClrQuirksSwitches(KeyValuePair<string, bool>[] switches) {
452 // First, see if the static API AppContext.SetSwitch even exists.
453 // Type.GetType will return null if the type doesn't exist; it will throw on catastrophic failure.
455 Type appContextType = Type.GetType("System.AppContext, " + AssemblyRef.Mscorlib);
456 if (appContextType == null) {
457 return; // wrong version of mscorlib - do nothing
460 Action<string, bool> setter = (Action<string, bool>)Delegate.CreateDelegate(
461 typeof(Action<string, bool>),
465 throwOnBindFailure: false);
466 if (setter == null) {
467 return; // wrong version of mscorlib - do nothing
470 // Finally, set each switch individually.
472 foreach (var sw in switches) {
473 setter(sw.Key, sw.Value);
478 // If an exception was thrown during initialization, return it.
479 public static Exception InitializationException {
481 return HttpRuntime.InitializationException;
485 // called from app manager (from management APIs)
486 internal ApplicationInfo GetApplicationInfo() {
487 return new ApplicationInfo(_appId, _appVirtualPath, _appPhysicalPath);
493 [PermissionSet(SecurityAction.Assert, Unrestricted = true)]
494 private void StopRegisteredObjects(bool immediate) {
495 if (_registeredObjects.Count > 0) {
496 ArrayList list = new ArrayList();
499 foreach (DictionaryEntry e in _registeredObjects) {
502 // well-known objects first
503 if (IsWellKnownObject(x)) {
512 foreach (IRegisteredObject obj in list) {
522 private void InitiateShutdownWorkItemCallback(Object state /*not used*/) {
523 Debug.Trace("HostingEnvironmentShutdown", "Shutting down: appId=" + _appId);
525 // no registered objects -- shutdown
526 if (_registeredObjects.Count == 0) {
527 Debug.Trace("HostingEnvironmentShutdown", "No registered objects");
528 ShutdownThisAppDomainOnce();
532 // call Stop on all registered objects with immediate = false
533 StopRegisteredObjects(false);
535 // no registered objects -- shutdown now
536 if (_registeredObjects.Count == 0) {
537 Debug.Trace("HostingEnvironmentShutdown", "All registered objects gone after Stop(false)");
538 ShutdownThisAppDomainOnce();
542 // if not everything shutdown synchronously give it some time.
543 int shutdownTimeoutSeconds = HostingEnvironmentSection.DefaultShutdownTimeout;
544 HostingEnvironmentSection hostEnvConfig = RuntimeConfig.GetAppLKGConfig().HostingEnvironment;
545 if (hostEnvConfig != null) {
546 shutdownTimeoutSeconds = (int) hostEnvConfig.ShutdownTimeout.TotalSeconds;
548 Debug.Trace("HostingEnvironmentShutdown", "Waiting for " + shutdownTimeoutSeconds + " sec...");
550 DateTime waitUntil = DateTime.UtcNow.AddSeconds(shutdownTimeoutSeconds);
551 while (_registeredObjects.Count > 0 && DateTime.UtcNow < waitUntil) {
555 Debug.Trace("HostingEnvironmentShutdown", "Shutdown timeout (" + shutdownTimeoutSeconds + " sec) expired");
557 // call Stop on all registered objects with immediate = true
558 StopRegisteredObjects(true);
560 // no registered objects -- shutdown now
561 if (_registeredObjects.Count == 0) {
562 Debug.Trace("HostingEnvironmentShutdown", "All registered objects gone after Stop(true)");
563 ShutdownThisAppDomainOnce();
567 // shutdown regardless
568 Debug.Trace("HostingEnvironmentShutdown", "Forced shutdown: " + _registeredObjects.Count + " registered objects left");
569 _registeredObjects = new Hashtable();
570 ShutdownThisAppDomainOnce();
573 // app domain shutdown logic
574 internal void InitiateShutdownInternal() {
578 Debug.Trace("AppManager", "HostingEnvironment.InitiateShutdownInternal appId=" + _appId);
580 bool proceed = false;
582 if (!_shutdownInitiated) {
584 if (!_shutdownInitiated) {
585 _shutdownInProgress = true;
587 _shutdownInitiated = true;
596 HttpRuntime.SetShutdownReason(ApplicationShutdownReason.HostingEnvironment, "HostingEnvironment initiated shutdown");
598 // Avoid calling Environment.StackTrace if we are in the ClientBuildManager (Dev10 bug 824659)
599 if (!BuildManagerHost.InClientBuildManager) {
600 new EnvironmentPermission(PermissionState.Unrestricted).Assert();
602 _shutDownStack = Environment.StackTrace;
605 CodeAccessPermission.RevertAssert();
609 // waitChangeNotification need not be honored in ClientBuildManager (Dev11 bug 264894)
610 if (!BuildManagerHost.InClientBuildManager) {
611 // this should only be called once, before the cache is disposed, and
612 // the config records are released.
613 HttpRuntime.CoalesceNotifications();
616 RemoveThisAppDomainFromAppManagerTableOnce();
618 // stop all registered objects without blocking
619 ThreadPool.QueueUserWorkItem(this._initiateShutdownWorkItemCallback);
621 } catch (Exception ex) {
622 HandleExceptionFromInitiateShutdownInternal(ex);
629 // InitiateShutdownInternal should never throw an exception, but we have seen cases where
630 // CLR bugs can cause it to fail without running to completion. This could cause an ASP.NET
631 // AppDomain never to unload. If we detect that an exception is thrown, we should DebugBreak
632 // so that the fundamentals team can investigate. Taking the Exception object as a parameter
633 // makes it easy to locate when looking at a stack dump.
634 [MethodImpl(MethodImplOptions.NoOptimization | MethodImplOptions.NoInlining)]
635 private static void HandleExceptionFromInitiateShutdownInternal(Exception ex) {
640 internal bool HasBeenRemovedFromAppManagerTable {
642 return _hasBeenRemovedFromAppManangerTable;
645 _hasBeenRemovedFromAppManangerTable = value;
649 private void RemoveThisAppDomainFromAppManagerTableOnce() {
650 bool proceed = false;
651 if (!_removedFromAppManager) {
653 if (!_removedFromAppManager) {
655 _removedFromAppManager = true;
663 if (_appManager != null) {
664 Debug.Trace("AppManager", "Removing HostingEnvironment from AppManager table, appId=" + _appId);
665 _appManager.HostingEnvironmentShutdownInitiated(_appId, this);
668 Debug.Trace("FileChangesMonitorIgnoreSubdirChange",
669 "*** REMOVE APPMANAGER TABLE" + DateTime.Now.ToString("hh:mm:ss.fff", CultureInfo.InvariantCulture)
670 + ": _appId=" + _appId);
674 private void ShutdownThisAppDomainOnce() {
675 bool proceed = false;
677 if (!_appDomainShutdownStarted) {
679 if (!_appDomainShutdownStarted) {
681 _appDomainShutdownStarted = true;
689 Debug.Trace("AppManager", "HostingEnvironment - shutting down AppDomain, appId=" + _appId);
691 // stop the timer used for idle timeout
692 if (_idleTimeoutMonitor != null) {
693 _idleTimeoutMonitor.Stop();
694 _idleTimeoutMonitor = null;
697 while (_inTrimCache == 1) {
701 // close all outstanding WebSocket connections and begin winding down code that consumes them
702 AspNetWebSocketManager.Current.AbortAllAndWait();
705 HttpRuntime.SetUserForcedShutdown();
707 //WOS 1400290: CantUnloadAppDomainException in ISAPI mode, wait until HostingEnvironment.ShutdownThisAppDomainOnce completes
708 _shutdownInProgress = false;
710 HttpRuntime.ShutdownAppDomainWithStackTrace(ApplicationShutdownReason.HostingEnvironment,
711 SR.GetString(SR.Hosting_Env_Restart),
716 // internal methods called by app manager
719 // helper for app manager to implement AppHost.CreateAppHost
720 [PermissionSet(SecurityAction.Assert, Unrestricted = true)]
721 internal ObjectHandle CreateInstance(String assemblyQualifiedName) {
722 Type type = Type.GetType(assemblyQualifiedName, true);
723 return new ObjectHandle(Activator.CreateInstance(type));
726 // start well known object
727 [PermissionSet(SecurityAction.Assert, Unrestricted = true)]
728 internal ObjectHandle CreateWellKnownObjectInstance(String assemblyQualifiedName, bool failIfExists) {
729 Type type = Type.GetType(assemblyQualifiedName, true);
730 IRegisteredObject obj = null;
731 String key = type.FullName;
735 obj = _wellKnownObjects[key] as IRegisteredObject;
738 obj = (IRegisteredObject)Activator.CreateInstance(type);
739 _wellKnownObjects[key] = obj;
746 if (exists && failIfExists) {
747 throw new InvalidOperationException(SR.GetString(SR.Wellknown_object_already_exists, key));
750 return new ObjectHandle(obj);
753 // check if well known object
754 private bool IsWellKnownObject(Object obj) {
756 String key = obj.GetType().FullName;
759 if (_wellKnownObjects[key] == obj) {
767 // find well known object by type
768 internal ObjectHandle FindWellKnownObject(String assemblyQualifiedName) {
769 Type type = Type.GetType(assemblyQualifiedName, true);
770 IRegisteredObject obj = null;
771 String key = type.FullName;
774 obj = _wellKnownObjects[key] as IRegisteredObject;
777 return (obj != null) ? new ObjectHandle(obj) : null;
780 // stop well known object by type
781 [PermissionSet(SecurityAction.Assert, Unrestricted = true)]
782 internal void StopWellKnownObject(String assemblyQualifiedName) {
783 Type type = Type.GetType(assemblyQualifiedName, true);
784 IRegisteredObject obj = null;
785 String key = type.FullName;
788 obj = _wellKnownObjects[key] as IRegisteredObject;
790 _wellKnownObjects.Remove(key);
796 internal bool IsIdle() {
797 bool isBusy = _isBusy;
799 return (!isBusy && _busyCount == 0);
802 internal bool GetIdleValue() {
803 return (!_isBusy && _busyCount == 0);
806 internal void IncrementBusyCountInternal() {
808 Interlocked.Increment(ref _busyCount);
811 internal void DecrementBusyCountInternal() {
813 Interlocked.Decrement(ref _busyCount);
815 // Notify idle timeout monitor
816 IdleTimeoutMonitor itm = _idleTimeoutMonitor;
818 itm.LastEvent = DateTime.UtcNow;
821 internal void IsUnloaded()
826 private void MessageReceivedInternal() {
829 IdleTimeoutMonitor itm = _idleTimeoutMonitor;
831 itm.LastEvent = DateTime.UtcNow;
835 // the busier the app domain the higher the score
836 internal int LruScore {
841 IdleTimeoutMonitor itm = _idleTimeoutMonitor;
846 // return negative number of seconds since last activity
847 return -(int)(DateTime.UtcNow - itm.LastEvent).TotalSeconds;
851 internal static ApplicationManager GetApplicationManager() {
852 if (_theHostingEnvironment == null)
855 return _theHostingEnvironment._appManager;
862 // register protocol handler with hosting environment
863 private void RegisterRunningObjectInternal(IRegisteredObject obj) {
865 _registeredObjects[obj] = obj;
867 ISuspendibleRegisteredObject suspendibleObject = obj as ISuspendibleRegisteredObject;
868 if (suspendibleObject != null) {
869 _suspendManager.RegisterObject(suspendibleObject);
874 // unregister protocol handler from hosting environment
875 private void UnregisterRunningObjectInternal(IRegisteredObject obj) {
876 bool lastOne = false;
879 // if it is a well known object, remove it from that table as well
880 String key = obj.GetType().FullName;
881 if (_wellKnownObjects[key] == obj) {
882 _wellKnownObjects.Remove(key);
885 // remove from running objects list
886 _registeredObjects.Remove(obj);
888 ISuspendibleRegisteredObject suspendibleObject = obj as ISuspendibleRegisteredObject;
889 if (suspendibleObject != null) {
890 _suspendManager.UnregisterObject(suspendibleObject);
893 if (_registeredObjects.Count == 0)
900 // shutdown app domain after last protocol handler is gone
902 InitiateShutdownInternal();
906 [SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands", Justification = "This method is not dangerous.")]
907 private String GetSiteName() {
908 if (_siteName == null) {
910 if (_siteName == null) {
913 if (_appHost != null) {
915 InternalSecurityPermissions.Unrestricted.Assert();
917 s = _appHost.GetSiteName();
920 CodeAccessPermission.RevertAssert();
925 s = WebConfigurationHost.DefaultSiteName;
936 [SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands", Justification = "This method is not dangerous.")]
937 private String GetSiteID() {
938 if (_siteID == null) {
940 if (_siteID == null) {
943 if (_appHost != null) {
945 InternalSecurityPermissions.Unrestricted.Assert();
947 s = _appHost.GetSiteID();
950 CodeAccessPermission.RevertAssert();
955 s = WebConfigurationHost.DefaultSiteID;
957 _siteID = s.ToLower(CultureInfo.InvariantCulture);
965 // Return the configPath for the app, e.g. "machine/webroot/1/myapp"
966 private String GetAppConfigPath() {
967 if (_appConfigPath == null) {
968 _appConfigPath = WebConfigurationHost.GetConfigPathFromSiteIDAndVPath(SiteID, ApplicationVirtualPathObject);
971 return _appConfigPath;
974 // Return the call context slot name to use for a virtual path
975 private static string GetFixedMappingSlotName(VirtualPath virtualPath) {
976 return "MapPath_" + virtualPath.VirtualPathString.ToLowerInvariant().GetHashCode().ToString(CultureInfo.InvariantCulture);
980 * Map a virtual path to a physical path. i.e. the physicalPath will be returned
981 * when MapPath is called on the virtual path, bypassing the IApplicationHost
983 private static string GetVirtualPathToFileMapping(VirtualPath virtualPath) {
984 return CallContext.GetData(GetFixedMappingSlotName(virtualPath)) as string;
988 * Map a virtual path to a physical path. i.e. the physicalPath will be returned
989 * when MapPath is called on the virtual path, bypassing the IApplicationHost
991 internal static object AddVirtualPathToFileMapping(
992 VirtualPath virtualPath, string physicalPath) {
994 // Save the mapping in the call context, using a key derived from the
995 // virtual path. The mapping is only valid for the duration of the request.
996 CallContext.SetData(GetFixedMappingSlotName(virtualPath), physicalPath);
998 // Return a mapping object to keep track of the virtual path, and of the current
999 // virtualPathProvider.
1000 VirtualPathToFileMappingState state = new VirtualPathToFileMappingState();
1001 state.VirtualPath = virtualPath;
1002 state.VirtualPathProvider = _theHostingEnvironment._virtualPathProvider;
1004 // Always use the MapPathBasedVirtualPathProvider, otherwise the mapping mechanism
1005 // doesn't work (VSWhidbey 420702)
1006 // Set/Get the VPP on the call context so as not to affect other concurrent requests (Dev10 852255)
1007 CallContext.SetData(TemporaryVirtualPathProviderKey, _theHostingEnvironment._mapPathBasedVirtualPathProvider);
1012 internal static void ClearVirtualPathToFileMapping(object state) {
1014 VirtualPathToFileMappingState mapping = (VirtualPathToFileMappingState)state;
1016 // Clear the mapping from the call context
1017 CallContext.SetData(GetFixedMappingSlotName(mapping.VirtualPath), null);
1019 // Restore the previous VirtualPathProvider
1020 // Set/Get the VPP on the call context so as not to affect other concurrent requests (Dev10 852255)
1021 CallContext.SetData(TemporaryVirtualPathProviderKey, null);
1024 private string MapPathActual(VirtualPath virtualPath, bool permitNull)
1026 string result = null;
1028 Debug.Assert(virtualPath != null);
1030 virtualPath.FailIfRelativePath();
1032 VirtualPath reqpath = virtualPath;
1034 if (String.CompareOrdinal(reqpath.VirtualPathString, _appVirtualPath.VirtualPathString) == 0) {
1035 // for application path don't need to call app host
1036 Debug.Trace("MapPath", reqpath +" is the app path");
1037 result = _appPhysicalPath;
1040 using (new ProcessImpersonationContext()) {
1041 // If there is a mapping for this virtual path in the call context, use it
1042 result = GetVirtualPathToFileMapping(reqpath);
1044 if (result == null) {
1045 // call host's mappath
1046 if (_configMapPath == null) {
1047 Debug.Trace("MapPath", "Missing _configMapPath");
1048 throw new InvalidOperationException(SR.GetString(SR.Cannot_map_path, reqpath));
1050 Debug.Trace("MapPath", "call ConfigMapPath (" + reqpath + ")");
1052 // see if the IConfigMapPath provider implements the interface
1055 if (null != _configMapPath2) {
1056 result = _configMapPath2.MapPath(GetSiteID(), reqpath);
1059 result = _configMapPath.MapPath(GetSiteID(), reqpath.VirtualPathString);
1061 if (HttpRuntime.IsMapPathRelaxed)
1062 result = HttpRuntime.GetRelaxedMapPathResult(result);
1064 if (HttpRuntime.IsMapPathRelaxed)
1065 result = HttpRuntime.GetRelaxedMapPathResult(null);
1073 if (String.IsNullOrEmpty(result)) {
1074 Debug.Trace("MapPath", "null Result");
1076 if (HttpRuntime.IsMapPathRelaxed)
1077 result = HttpRuntime.GetRelaxedMapPathResult(null);
1079 throw new InvalidOperationException(SR.GetString(SR.Cannot_map_path, reqpath));
1083 // ensure extra '\\' in the physical path if the virtual path had extra '/'
1084 // and the other way -- no extra '\\' in physical if virtual didn't have it.
1085 if (virtualPath.HasTrailingSlash) {
1086 if (!UrlPath.PathEndsWithExtraSlash(result) && !UrlPath.PathIsDriveRoot(result))
1087 result = result + "\\";
1090 if (UrlPath.PathEndsWithExtraSlash(result) && !UrlPath.PathIsDriveRoot(result))
1091 result = result.Substring(0, result.Length - 1);
1094 Debug.Trace("MapPath", " result=" + result);
1101 // public static methods
1105 // register protocol handler with hosting environment
1106 [SecurityPermission(SecurityAction.Demand, Unrestricted = true)]
1107 public static void RegisterObject(IRegisteredObject obj) {
1108 if (_theHostingEnvironment != null)
1109 _theHostingEnvironment.RegisterRunningObjectInternal(obj);
1113 // unregister protocol handler from hosting environment
1114 [SecurityPermission(SecurityAction.Demand, Unrestricted = true)]
1115 public static void UnregisterObject(IRegisteredObject obj) {
1116 if (_theHostingEnvironment != null)
1117 _theHostingEnvironment.UnregisterRunningObjectInternal(obj);
1120 // Schedules a task which can run in the background, independent of any request.
1121 // This differs from a normal ThreadPool work item in that ASP.NET can keep track
1122 // of how many work items registered through this API are currently running, and
1123 // the ASP.NET runtime will try not to delay AppDomain shutdown until these work
1124 // items have finished executing.
1127 // - This API cannot be called outside of an ASP.NET-managed AppDomain.
1128 // - The caller's ExecutionContext is not flowed to the work item.
1129 // - Scheduled work items are not guaranteed to ever execute, e.g., when AppDomain
1130 // shutdown has already started by the time this API was called.
1131 // - The provided CancellationToken will be signaled when the application is
1132 // shutting down. The work item should make every effort to honor this token.
1133 // If a work item does not honor this token and continues executing it will
1134 // eventually be considered rogue, and the ASP.NET runtime will rudely unload
1135 // the AppDomain without waiting for the work item to finish.
1137 // This overload of QueueBackgroundWorkItem takes a void-returning callback; the
1138 // work item will be considered finished when the callback returns.
1139 [SecurityPermission(SecurityAction.LinkDemand, Unrestricted = true)]
1140 public static void QueueBackgroundWorkItem(Action<CancellationToken> workItem) {
1141 if (workItem == null) {
1142 throw new ArgumentNullException("workItem");
1145 QueueBackgroundWorkItem(ct => { workItem(ct); return _completedTask; });
1148 // See documentation on the other overload for a general API overview.
1150 // This overload of QueueBackgroundWorkItem takes a Task-returning callback; the
1151 // work item will be considered finished when the returned Task transitions to a
1153 [SecurityPermission(SecurityAction.LinkDemand, Unrestricted = true)]
1154 public static void QueueBackgroundWorkItem(Func<CancellationToken, Task> workItem) {
1155 if (workItem == null) {
1156 throw new ArgumentNullException("workItem");
1158 if (_theHostingEnvironment == null) {
1159 throw new InvalidOperationException(); // can only be called within an ASP.NET AppDomain
1162 _theHostingEnvironment.QueueBackgroundWorkItemInternal(workItem);
1165 private void QueueBackgroundWorkItemInternal(Func<CancellationToken, Task> workItem) {
1166 Debug.Assert(workItem != null);
1168 BackgroundWorkScheduler scheduler = Volatile.Read(ref _backgroundWorkScheduler);
1170 // If the scheduler doesn't exist, lazily create it, but only allow one instance to ever be published to the backing field
1171 if (scheduler == null) {
1172 BackgroundWorkScheduler newlyCreatedScheduler = new BackgroundWorkScheduler(UnregisterObject, Misc.WriteUnhandledExceptionToEventLog);
1173 scheduler = Interlocked.CompareExchange(ref _backgroundWorkScheduler, newlyCreatedScheduler, null) ?? newlyCreatedScheduler;
1174 if (scheduler == newlyCreatedScheduler) {
1175 RegisterObject(scheduler); // Only call RegisterObject if we just created the "winning" one
1179 scheduler.ScheduleWorkItem(workItem);
1182 // This event is a simple way to hook IStopListeningRegisteredObject.StopListening
1183 // without needing to call RegisterObject. The same restrictions which apply to
1184 // that method apply to this event.
1185 public static event EventHandler StopListening;
1188 // public static methods for the user code to call
1192 public static void IncrementBusyCount() {
1193 if (_theHostingEnvironment != null)
1194 _theHostingEnvironment.IncrementBusyCountInternal();
1198 public static void DecrementBusyCount() {
1199 if (_theHostingEnvironment != null)
1200 _theHostingEnvironment.DecrementBusyCountInternal();
1204 public static void MessageReceived() {
1205 if (_theHostingEnvironment != null)
1206 _theHostingEnvironment.MessageReceivedInternal();
1209 public static bool InClientBuildManager {
1211 return BuildManagerHost.InClientBuildManager;
1215 public static bool IsHosted {
1217 return (_theHostingEnvironment != null);
1221 internal static bool IsUnderIISProcess {
1223 String process = VersionInfo.ExeName;
1225 return process == "aspnet_wp" ||
1226 process == "w3wp" ||
1227 process == "inetinfo";
1231 internal static bool IsUnderIIS6Process {
1233 return VersionInfo.ExeName == "w3wp";
1237 public static IApplicationHost ApplicationHost {
1238 //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
1239 [SecurityPermission(SecurityAction.Demand, Unrestricted = true)]
1241 if (_theHostingEnvironment == null)
1244 return _theHostingEnvironment._appHost;
1248 internal static IApplicationHost ApplicationHostInternal {
1250 if (_theHostingEnvironment == null)
1253 return _theHostingEnvironment._appHost;
1257 internal IApplicationHost InternalApplicationHost {
1263 internal static int BusyCount {
1265 if (_theHostingEnvironment == null)
1268 return _theHostingEnvironment._busyCount;
1272 internal static bool ShutdownInitiated {
1274 if (_theHostingEnvironment == null)
1277 return _theHostingEnvironment._shutdownInitiated;
1282 internal static bool ShutdownInProgress {
1284 if (_theHostingEnvironment == null)
1287 return _theHostingEnvironment._shutdownInProgress;
1293 /// <para>The application ID (metabase path in IIS hosting).</para>
1295 public static String ApplicationID {
1297 if (_theHostingEnvironment == null)
1300 InternalSecurityPermissions.AspNetHostingPermissionLevelHigh.Demand();
1301 return _theHostingEnvironment._appId;
1305 internal static String ApplicationIDNoDemand {
1307 if (_theHostingEnvironment == null) {
1311 return _theHostingEnvironment._appId;
1317 /// <para>Physical path to the application root.</para>
1319 public static String ApplicationPhysicalPath {
1321 if (_theHostingEnvironment == null)
1324 InternalSecurityPermissions.AppPathDiscovery.Demand();
1325 return _theHostingEnvironment._appPhysicalPath;
1331 /// <para>Virtual path to the application root.</para>
1333 public static String ApplicationVirtualPath {
1335 return VirtualPath.GetVirtualPathStringNoTrailingSlash(ApplicationVirtualPathObject);
1339 internal static VirtualPath ApplicationVirtualPathObject {
1341 if (_theHostingEnvironment == null)
1344 return _theHostingEnvironment._appVirtualPath;
1350 /// <para>Site name.</para>
1352 public static String SiteName {
1354 if (_theHostingEnvironment == null)
1357 InternalSecurityPermissions.AspNetHostingPermissionLevelMedium.Demand();
1358 return _theHostingEnvironment.GetSiteName();
1362 internal static String SiteNameNoDemand {
1364 if (_theHostingEnvironment == null)
1367 return _theHostingEnvironment.GetSiteName();
1371 internal static String SiteID {
1373 if (_theHostingEnvironment == null)
1376 return _theHostingEnvironment.GetSiteID();
1380 internal static IConfigMapPath ConfigMapPath {
1382 if (_theHostingEnvironment == null)
1385 return _theHostingEnvironment._configMapPath;
1389 internal static String AppConfigPath {
1391 if (_theHostingEnvironment == null) {
1395 return _theHostingEnvironment.GetAppConfigPath();
1399 // See comments in ApplicationManager.CreateAppDomainWithHostingEnvironment. This is the public API to access the
1400 // information we determined in that method. Defaults to 'false' if our AppDomain data isn't present.
1401 public static bool IsDevelopmentEnvironment {
1403 return (AppDomain.CurrentDomain.GetData(".devEnvironment") as bool?) == true;
1410 /// Gets a reference to the System.Web.Cache.Cache object for the current request.
1413 public static Cache Cache {
1414 get { return HttpRuntime.Cache; }
1417 // count of all app domain from app manager
1418 internal static int AppDomainsCount {
1420 ApplicationManager appManager = GetApplicationManager();
1421 return (appManager != null) ? appManager.AppDomainsCount : 0;
1425 internal static HostingEnvironmentParameters HostingParameters {
1427 if (_theHostingEnvironment == null)
1430 return _theHostingEnvironment._hostingParameters;
1434 // Return an integer that is unique for each appdomain. This can be used
1435 // to create things like once-per-appdomain temp files without having different
1436 // processes/appdomains step on each other
1437 private static int s_appDomainUniqueInteger;
1438 internal static int AppDomainUniqueInteger {
1440 if (s_appDomainUniqueInteger == 0) {
1441 s_appDomainUniqueInteger = Guid.NewGuid().GetHashCode();
1444 return s_appDomainUniqueInteger;
1448 public static ApplicationShutdownReason ShutdownReason {
1449 get { return HttpRuntime.ShutdownReason; }
1452 // Was CGlobalModule::OnGlobalStopListening called?
1453 internal static bool StopListeningWasCalled {
1455 return _stopListeningWasCalled;
1459 [SuppressMessage("Microsoft.Reliability", "CA2004:RemoveCallsToGCKeepAlive", Justification = "See comment in function.")]
1460 internal static void SetupStopListeningHandler() {
1461 StopListeningWaitHandle waitHandle = new StopListeningWaitHandle();
1463 RegisteredWaitHandle registeredWaitHandle = null;
1464 registeredWaitHandle = ThreadPool.UnsafeRegisterWaitForSingleObject(waitHandle, (_, __) => {
1465 // Referencing the field from within the callback should be sufficient to keep the GC
1466 // from reclaiming the RegisteredWaitHandle; the race condition is fine.
1467 GC.KeepAlive(registeredWaitHandle);
1468 OnGlobalStopListening();
1469 }, null, Timeout.Infinite, executeOnlyOnce: true);
1472 private static void OnGlobalStopListening() {
1473 _stopListeningWasCalled = true;
1475 EventHandler eventHandler = StopListening;
1476 if (eventHandler != null) {
1477 eventHandler(null /* static means no sender */, EventArgs.Empty);
1480 if (_theHostingEnvironment != null) {
1481 _theHostingEnvironment.FireStopListeningHandlers();
1485 [SuppressMessage("Microsoft.Reliability", "CA2002:DoNotLockOnObjectsWithWeakIdentity", Justification = "'this' always has strong identity.")]
1486 private void FireStopListeningHandlers() {
1487 List<IStopListeningRegisteredObject> listeners = new List<IStopListeningRegisteredObject>();
1489 foreach (DictionaryEntry e in _registeredObjects) {
1490 IStopListeningRegisteredObject listener = e.Key as IStopListeningRegisteredObject;
1491 if (listener != null) {
1492 listeners.Add(listener);
1497 foreach (var listener in listeners) {
1498 listener.StopListening();
1503 /// <para>Initiate app domain unloading for the current app.</para>
1505 [SecurityPermission(SecurityAction.Demand, Unrestricted = true)]
1506 public static void InitiateShutdown() {
1507 if (_theHostingEnvironment != null)
1508 _theHostingEnvironment.InitiateShutdownInternal();
1511 internal static void InitiateShutdownWithoutDemand() {
1512 if (_theHostingEnvironment != null)
1513 _theHostingEnvironment.InitiateShutdownInternal();
1517 // Internal methods for the ApplicationManager to suspend / resume this application.
1518 // Using GCHandle instead of ObjectHandle means we don't need to worry about lease lifetimes.
1521 internal IntPtr SuspendApplication() {
1522 var state = _suspendManager.Suspend();
1523 return GCUtil.RootObject(state);
1526 internal void ResumeApplication(IntPtr state) {
1527 var unwrappedState = GCUtil.UnrootObject(state);
1528 _suspendManager.Resume(unwrappedState);
1532 /// <para>Maps a virtual path to a physical path.</para>
1534 public static string MapPath(string virtualPath) {
1535 return MapPath(VirtualPath.Create(virtualPath));
1538 internal static string MapPath(VirtualPath virtualPath) {
1539 if (_theHostingEnvironment == null)
1542 String path = MapPathInternal(virtualPath);
1545 InternalSecurityPermissions.PathDiscovery(path).Demand();
1550 internal static String MapPathInternal(string virtualPath) {
1551 return MapPathInternal(VirtualPath.Create(virtualPath));
1554 internal static String MapPathInternal(VirtualPath virtualPath) {
1555 if (_theHostingEnvironment == null) {
1559 return _theHostingEnvironment.MapPathActual(virtualPath, false);
1562 internal static String MapPathInternal(string virtualPath, bool permitNull) {
1563 return MapPathInternal(VirtualPath.Create(virtualPath), permitNull);
1566 internal static String MapPathInternal(VirtualPath virtualPath, bool permitNull) {
1567 if (_theHostingEnvironment == null) {
1571 return _theHostingEnvironment.MapPathActual(virtualPath, permitNull);
1574 internal static string MapPathInternal(string virtualPath, string baseVirtualDir, bool allowCrossAppMapping) {
1575 return MapPathInternal(VirtualPath.Create(virtualPath),
1576 VirtualPath.CreateNonRelative(baseVirtualDir), allowCrossAppMapping);
1579 internal static string MapPathInternal(VirtualPath virtualPath, VirtualPath baseVirtualDir, bool allowCrossAppMapping) {
1580 Debug.Assert(baseVirtualDir != null, "baseVirtualDir != null");
1582 // Combine it with the base and reduce
1583 virtualPath = baseVirtualDir.Combine(virtualPath);
1585 if (!allowCrossAppMapping && !virtualPath.IsWithinAppRoot)
1586 throw new ArgumentException(SR.GetString(SR.Cross_app_not_allowed, virtualPath));
1588 return MapPathInternal(virtualPath);
1591 internal static WebApplicationLevel GetPathLevel(String path) {
1592 WebApplicationLevel pathLevel = WebApplicationLevel.AboveApplication;
1594 if (_theHostingEnvironment != null && !String.IsNullOrEmpty(path)) {
1595 String appPath = ApplicationVirtualPath;
1597 if (appPath == "/") {
1599 pathLevel = WebApplicationLevel.AtApplication;
1601 else if (path[0] == '/') {
1602 pathLevel = WebApplicationLevel.BelowApplication;
1606 if (StringUtil.EqualsIgnoreCase(appPath, path)) {
1607 pathLevel = WebApplicationLevel.AtApplication;
1609 else if (path.Length > appPath.Length && path[appPath.Length] == '/' &&
1610 StringUtil.StringStartsWithIgnoreCase(path, appPath)) {
1612 pathLevel = WebApplicationLevel.BelowApplication;
1622 // Impersonation helpers
1624 // user token for the app (hosting / unc)
1625 internal static IntPtr ApplicationIdentityToken {
1627 if (_theHostingEnvironment == null) {
1631 if (_theHostingEnvironment._appIdentityTokenSet)
1632 return _theHostingEnvironment._appIdentityToken;
1634 return _theHostingEnvironment._configToken;
1640 // check if application impersonation != process impersonation
1641 internal static bool HasHostingIdentity {
1643 return (ApplicationIdentityToken != IntPtr.Zero);
1647 // impersonate application identity
1648 [SecurityPermission(SecurityAction.Demand, ControlPrincipal = true)]
1649 public static IDisposable Impersonate() {
1650 return new ApplicationImpersonationContext();
1653 // impersonate the given user identity
1654 [SecurityPermission(SecurityAction.Demand, Unrestricted = true)]
1655 public static IDisposable Impersonate(IntPtr token) {
1656 if (token == IntPtr.Zero) {
1657 return new ProcessImpersonationContext();
1660 return new ImpersonationContext(token);
1664 // impersonate as configured for a given path
1665 [SecurityPermission(SecurityAction.Demand, Unrestricted = true)]
1666 public static IDisposable Impersonate(IntPtr userToken, String virtualPath) {
1667 virtualPath = UrlPath.MakeVirtualPathAppAbsoluteReduceAndCheck(virtualPath);
1669 if (_theHostingEnvironment == null) {
1670 return Impersonate(userToken);
1673 IdentitySection c = RuntimeConfig.GetConfig(virtualPath).Identity;
1674 if (c.Impersonate) {
1675 if (c.ImpersonateToken != IntPtr.Zero) {
1676 return new ImpersonationContext(c.ImpersonateToken);
1679 return new ImpersonationContext(userToken);
1683 return new ApplicationImpersonationContext();
1691 public static IDisposable SetCultures() {
1692 return SetCultures(RuntimeConfig.GetAppLKGConfig().Globalization);
1695 public static IDisposable SetCultures(string virtualPath) {
1696 virtualPath = UrlPath.MakeVirtualPathAppAbsoluteReduceAndCheck(virtualPath);
1697 return SetCultures(RuntimeConfig.GetConfig(virtualPath).Globalization);
1700 private static IDisposable SetCultures(GlobalizationSection gs) {
1701 CultureContext c = new CultureContext();
1704 CultureInfo culture = null;
1705 CultureInfo uiCulture = null;
1707 if (gs.Culture != null && gs.Culture.Length > 0) {
1709 culture = HttpServerUtility.CreateReadOnlyCultureInfo(gs.Culture);
1715 if (gs.UICulture != null && gs.UICulture.Length > 0) {
1717 uiCulture = HttpServerUtility.CreateReadOnlyCultureInfo(gs.UICulture);
1723 c.SetCultures(culture, uiCulture);
1730 class CultureContext : IDisposable {
1731 CultureInfo _savedCulture;
1732 CultureInfo _savedUICulture;
1734 internal CultureContext() {
1737 void IDisposable.Dispose() {
1741 internal void SetCultures(CultureInfo culture, CultureInfo uiCulture) {
1742 CultureInfo currentCulture = Thread.CurrentThread.CurrentCulture;
1743 CultureInfo currentUICulture = Thread.CurrentThread.CurrentUICulture;
1745 if (culture != null && culture != currentCulture) {
1746 Thread.CurrentThread.CurrentCulture = culture;
1747 _savedCulture = currentCulture;
1750 if (uiCulture != null && uiCulture != currentCulture) {
1751 Thread.CurrentThread.CurrentUICulture = uiCulture;
1752 _savedUICulture = currentUICulture;
1756 internal void RestoreCultures() {
1757 if (_savedCulture != null && _savedCulture != Thread.CurrentThread.CurrentCulture) {
1758 Thread.CurrentThread.CurrentCulture = _savedCulture;
1759 _savedCulture = null;
1762 if (_savedUICulture != null && _savedUICulture != Thread.CurrentThread.CurrentUICulture) {
1763 Thread.CurrentThread.CurrentUICulture = _savedUICulture;
1764 _savedUICulture = null;
1770 // VirtualPathProvider related code
1773 private VirtualPathProvider _virtualPathProvider;
1774 private VirtualPathProvider _mapPathBasedVirtualPathProvider;
1777 public static VirtualPathProvider VirtualPathProvider {
1779 if (_theHostingEnvironment == null)
1782 // Set/Get the VPP on the call context so as not to affect other concurrent requests (Dev10 852255)
1783 var tempVPP = CallContext.GetData(TemporaryVirtualPathProviderKey);
1784 if (tempVPP != null) {
1785 return tempVPP as VirtualPathProvider;
1788 return _theHostingEnvironment._virtualPathProvider;
1792 internal static bool UsingMapPathBasedVirtualPathProvider {
1794 if (_theHostingEnvironment == null)
1797 return (_theHostingEnvironment._virtualPathProvider ==
1798 _theHostingEnvironment._mapPathBasedVirtualPathProvider);
1802 // [AspNetHostingPermission(SecurityAction.Demand, Level=AspNetHostingPermissionLevel.High)]
1803 // Removed the above LinkDemand for AspNetHostingPermissionLevel.High. If we decide to add VPP
1804 // support for config in the future, we should have a separate API with a demand for registering
1805 // VPPs supporting configuration.
1806 public static void RegisterVirtualPathProvider(VirtualPathProvider virtualPathProvider) {
1808 if (_theHostingEnvironment == null)
1809 throw new InvalidOperationException();
1811 // Ignore the VirtualPathProvider on precompiled sites (VSWhidbey 368169,404844)
1812 if (BuildManager.IsPrecompiledApp)
1815 RegisterVirtualPathProviderInternal(virtualPathProvider);
1818 internal static void RegisterVirtualPathProviderInternal(VirtualPathProvider virtualPathProvider) {
1819 VirtualPathProvider previous = _theHostingEnvironment._virtualPathProvider;
1820 _theHostingEnvironment._virtualPathProvider = virtualPathProvider;
1822 // Give it the previous provider so it can delegate if needed
1823 virtualPathProvider.Initialize(previous);
1826 // Helper class used to keep track of state when using
1827 // AddVirtualPathToFileMapping & ClearVirtualPathToFileMapping
1828 internal class VirtualPathToFileMappingState {
1829 internal VirtualPath VirtualPath;
1830 internal VirtualPathProvider VirtualPathProvider;
1833 internal static IProcessHostSupportFunctions SupportFunctions {
1842 [SuppressMessage("Microsoft.Naming", "CA1705:LongAcronymsShouldBePascalCased",
1843 Justification="matches casing of config attribute")]
1844 public static int MaxConcurrentRequestsPerCPU {
1846 if (!HttpRuntime.UseIntegratedPipeline) {
1847 throw new PlatformNotSupportedException(SR.GetString(SR.Requires_Iis_Integrated_Mode));
1849 return UnsafeIISMethods.MgdGetMaxConcurrentRequestsPerCPU();
1851 [SecurityPermission(SecurityAction.Demand, Unrestricted = true)]
1853 if (!HttpRuntime.UseIntegratedPipeline) {
1854 throw new PlatformNotSupportedException(SR.GetString(SR.Requires_Iis_Integrated_Mode));
1856 int hr = UnsafeIISMethods.MgdSetMaxConcurrentRequestsPerCPU(value);
1858 case HResults.S_FALSE:
1859 // Because "maxConcurrentRequestsPerCPU" is currently zero, we cannot set the value, since that would
1860 // enable the feature, which can only be done via configuration.
1861 throw new InvalidOperationException(SR.GetString(SR.Queue_limit_is_zero, "maxConcurrentRequestsPerCPU"));
1862 case HResults.E_INVALIDARG:
1863 // The value must be greater than zero. A value of zero would disable the feature, but this can only be done via configuration.
1864 throw new ArgumentException(SR.GetString(SR.Invalid_queue_limit));
1869 [SuppressMessage("Microsoft.Naming", "CA1705:LongAcronymsShouldBePascalCased",
1870 Justification="matches casing of config attribute")]
1871 public static int MaxConcurrentThreadsPerCPU {
1873 if (!HttpRuntime.UseIntegratedPipeline) {
1874 throw new PlatformNotSupportedException(SR.GetString(SR.Requires_Iis_Integrated_Mode));
1876 return UnsafeIISMethods.MgdGetMaxConcurrentThreadsPerCPU();
1878 [SecurityPermission(SecurityAction.Demand, Unrestricted = true)]
1880 if (!HttpRuntime.UseIntegratedPipeline) {
1881 throw new PlatformNotSupportedException(SR.GetString(SR.Requires_Iis_Integrated_Mode));
1883 int hr = UnsafeIISMethods.MgdSetMaxConcurrentThreadsPerCPU(value);
1885 case HResults.S_FALSE:
1886 // Because "maxConcurrentThreadsPerCPU" is currently zero, we cannot set the value, since that would
1887 // enable the feature, which can only be done via configuration.
1888 throw new InvalidOperationException(SR.GetString(SR.Queue_limit_is_zero, "maxConcurrentThreadsPerCPU"));
1889 case HResults.E_INVALIDARG:
1890 // The value must be greater than zero. A value of zero would disable the feature, but this can only be done via configuration.
1891 throw new ArgumentException(SR.GetString(SR.Invalid_queue_limit));
1897 /// Returns the ASP.NET hosted domain.
1899 internal AppDomain HostedAppDomain {
1901 return AppDomain.CurrentDomain;