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