1 //------------------------------------------------------------------------------
2 // <copyright file="ApplicationManager.cs" company="Microsoft">
3 // Copyright (c) Microsoft Corporation. All rights reserved.
5 //------------------------------------------------------------------------------
8 namespace System.Web.Hosting {
10 using System.Collections;
11 using System.Collections.Generic;
12 using System.Configuration;
13 using System.Diagnostics.CodeAnalysis;
14 using System.Globalization;
17 using System.Reflection;
18 using System.Runtime.ExceptionServices;
19 using System.Runtime.InteropServices;
20 using System.Runtime.Remoting;
21 using System.Runtime.Versioning;
22 using System.Security;
23 using System.Security.Permissions;
24 using System.Security.Policy;
26 using System.Threading;
27 using System.Threading.Tasks;
29 using System.Web.Compilation;
30 using System.Web.Configuration;
31 using System.Web.Util;
33 public enum HostSecurityPolicyResults {
40 [PermissionSet(SecurityAction.InheritanceDemand, Unrestricted = true)]
41 public class HostSecurityPolicyResolver {
42 public virtual HostSecurityPolicyResults ResolvePolicy(Evidence evidence) {
43 return HostSecurityPolicyResults.DefaultPolicy;
49 internal class LockableAppDomainContext {
50 internal HostingEnvironment HostEnv { get; set; }
51 internal string PreloadContext { get; set; }
52 internal bool RetryingPreload { get; set; }
54 internal LockableAppDomainContext() {
58 public sealed class ApplicationManager : MarshalByRefObject {
60 private const string _clrQuirkAppSettingsAppContextPrefix = "AppContext.SetSwitch:";
61 private const string _regexMatchTimeoutKey = "REGEX_DEFAULT_MATCH_TIMEOUT";
62 private static readonly StrongName _mwiV1StrongName = GetMicrosoftWebInfrastructureV1StrongName();
64 private static Object _applicationManagerStaticLock = new Object();
66 // open count (when last close goes to 0 it shuts down everything)
68 bool _shutdownInProgress = false;
70 // table of app domains (LockableAppDomainContext objects) by app id
71 // To simplify per-appdomain synchronization we will never remove LockableAppDomainContext objects from this table even when the AD is unloaded
72 // We may need to fix it if profiling shows a noticeable impact on performance
73 private Dictionary <string, LockableAppDomainContext> _appDomains = new Dictionary<string, LockableAppDomainContext>(StringComparer.OrdinalIgnoreCase);
74 // count of HostingEnvironment instances that is referenced in _appDomains collection
75 private int _accessibleHostingEnvCount;
77 // could differ from _appDomains or _accessibleHostingEnvCount count (host env is active some time after it is removed)
78 private int _activeHostingEnvCount;
80 // pending callback to respond to ping (typed as Object to do Interlocked operations)
81 private Object _pendingPingCallback;
82 // delegate OnRespondToPing
83 private WaitCallback _onRespondToPingWaitCallback;
85 // flag indicates whether any fatal exception has been recorded
86 private bool _fatalExceptionRecorded = false;
88 // single instance of app manager
89 private static ApplicationManager _theAppManager;
91 // single instance of cache manager
92 private static CacheManager _cm;
94 // store fatal exception to assist debugging
95 private static Exception _fatalException = null;
97 internal ApplicationManager() {
98 _onRespondToPingWaitCallback = new WaitCallback(this.OnRespondToPingWaitCallback);
100 // VSWhidbey 555767: Need better logging for unhandled exceptions (http://support.microsoft.com/?id=911816)
101 // We only add a handler in the default domain because it will be notified when an unhandled exception
102 // occurs in ANY domain.
103 // WOS 1983175: (weird) only the handler in the default domain is notified when there is an AV in a native module
104 // while we're in a call to MgdIndicateCompletion.
105 AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(OnUnhandledException);
108 private void InitCacheManager(long privateBytesLimit) {
110 lock (_applicationManagerStaticLock) {
111 if (_cm == null && !_shutdownInProgress) {
112 _cm = new CacheManager(this, privateBytesLimit);
118 private void DisposeCacheManager() {
120 lock (_applicationManagerStaticLock) {
129 // Each cache must update the total with the difference between it's current size and it's previous size.
130 // To reduce cross-domain costs, this also returns the updated total size.
131 internal long GetUpdatedTotalCacheSize(long sizeUpdate) {
132 CacheManager cm = _cm;
133 return (cm != null) ? cm.GetUpdatedTotalCacheSize(sizeUpdate) : 0;
136 internal long TrimCaches(int percent) {
137 long trimmedOrExpired = 0;
138 Dictionary<string, LockableAppDomainContext> apps = CloneAppDomainsCollection();
139 foreach (LockableAppDomainContext ac in apps.Values) {
141 HostingEnvironment env = ac.HostEnv;
142 if (_shutdownInProgress) {
148 trimmedOrExpired += env.TrimCache(percent);
151 return trimmedOrExpired;
154 internal bool ShutdownInProgress {
156 return _shutdownInProgress;
160 private bool FatalExceptionRecorded
163 return _fatalExceptionRecorded;
166 _fatalExceptionRecorded = value;
170 internal static void RecordFatalException(Exception e) {
171 RecordFatalException(AppDomain.CurrentDomain, e);
174 internal static void RecordFatalException(AppDomain appDomain, Exception e) {
175 // store the exception from the first caller to assist debugging
176 object originalValue = Interlocked.CompareExchange(ref _fatalException, e, null);
178 if (originalValue == null) {
179 // create event log entry
180 Misc.WriteUnhandledExceptionToEventLog(appDomain, e);
184 internal static void OnUnhandledException(Object sender, UnhandledExceptionEventArgs eventArgs) {
185 // if the CLR is not terminating, ignore the notification
186 if (!eventArgs.IsTerminating) {
190 Exception exception = eventArgs.ExceptionObject as Exception;
191 if (exception == null) {
195 AppDomain appDomain = sender as AppDomain;
196 if (appDomain == null) {
200 // If any fatal exception was recorded in applicaiton AppDomains,
201 // we wouldn't record exceptions in the default AppDomain.
202 var appManager = GetApplicationManager();
203 if (AppDomain.CurrentDomain.IsDefaultAppDomain() && appManager.FatalExceptionRecorded) {
207 appManager.FatalExceptionRecorded = true;
209 RecordFatalException(appDomain, exception);
212 public override Object InitializeLifetimeService() {
213 return null; // never expire lease
217 // public ApplicationManager methods
221 public static ApplicationManager GetApplicationManager() {
222 if (_theAppManager == null) {
223 lock (_applicationManagerStaticLock) {
224 if (_theAppManager == null) {
225 if (HostingEnvironment.IsHosted)
226 _theAppManager = HostingEnvironment.GetApplicationManager();
228 if (_theAppManager == null)
229 _theAppManager = new ApplicationManager();
234 return _theAppManager;
238 [SecurityPermission(SecurityAction.Demand, Unrestricted=true)]
240 Interlocked.Increment(ref _openCount);
244 [SecurityPermission(SecurityAction.Demand, Unrestricted = true)]
245 public void Close() {
246 if (Interlocked.Decrement(ref _openCount) > 0)
249 // need to shutdown everything
253 private string CreateSimpleAppID(VirtualPath virtualPath, string physicalPath, string siteName) {
254 // Put together some unique app id
255 string appId = String.Concat(virtualPath.VirtualPathString, physicalPath);
257 if (!String.IsNullOrEmpty(siteName)) {
258 appId = String.Concat(appId, siteName);
261 return appId.GetHashCode().ToString("x", CultureInfo.InvariantCulture);
264 [SecurityPermission(SecurityAction.Demand, Unrestricted = true)]
265 public IRegisteredObject CreateObject(IApplicationHost appHost, Type type) {
266 if (appHost == null) {
267 throw new ArgumentNullException("appHost");
270 throw new ArgumentNullException("type");
273 string appID = CreateSimpleAppID(appHost);
274 return CreateObjectInternal(appID, type, appHost, false);
277 [SecurityPermission(SecurityAction.Demand, UnmanagedCode=true)]
278 public IRegisteredObject CreateObject(String appId, Type type, string virtualPath, string physicalPath, bool failIfExists) {
279 return CreateObject(appId, type, virtualPath, physicalPath, failIfExists, false /*throwOnError*/);
282 [SecurityPermission(SecurityAction.Demand, Unrestricted = true)]
283 public IRegisteredObject CreateObject(String appId, Type type, string virtualPath, string physicalPath,
284 bool failIfExists, bool throwOnError) {
287 throw new ArgumentNullException("appId");
289 SimpleApplicationHost appHost = new SimpleApplicationHost(VirtualPath.CreateAbsolute(virtualPath), physicalPath);
291 // if throw on error flag is set, create hosting parameters accordingly
292 HostingEnvironmentParameters hostingParameters = null;
295 hostingParameters = new HostingEnvironmentParameters();
296 hostingParameters.HostingFlags = HostingEnvironmentFlags.ThrowHostingInitErrors;
300 // call the internal method
301 return CreateObjectInternal(appId, type, appHost, failIfExists, hostingParameters);
304 [SecurityPermission(SecurityAction.Demand, Unrestricted = true)]
305 internal IRegisteredObject CreateObjectInternal(String appId, Type type, IApplicationHost appHost, bool failIfExists) {
308 throw new ArgumentNullException("appId");
311 throw new ArgumentNullException("type");
314 throw new ArgumentNullException("appHost");
316 // call the internal method
317 return CreateObjectInternal(appId, type, appHost, failIfExists, null /*hostingParameters*/);
320 [PermissionSet(SecurityAction.Assert, Unrestricted = true)]
321 internal IRegisteredObject CreateObjectInternal(
324 IApplicationHost appHost,
326 HostingEnvironmentParameters hostingParameters) {
328 // check that type is as IRegisteredObject
329 if (!typeof(IRegisteredObject).IsAssignableFrom(type))
330 throw new ArgumentException(SR.GetString(SR.Not_IRegisteredObject, type.FullName), "type");
332 // get hosting environment
333 HostingEnvironment env = GetAppDomainWithHostingEnvironment(appId, appHost, hostingParameters);
335 // create the managed object in the worker app domain
336 // When marshaling Type, the AppDomain must have FileIoPermission to the assembly, which is not
337 // always the case, so we marshal the assembly qualified name instead
338 ObjectHandle h = env.CreateWellKnownObjectInstance(type.AssemblyQualifiedName, failIfExists);
339 return (h != null) ? h.Unwrap() as IRegisteredObject : null;
342 internal IRegisteredObject CreateObjectWithDefaultAppHostAndAppId(
347 out IApplicationHost appHost) {
348 return CreateObjectWithDefaultAppHostAndAppId(physicalPath,
349 VirtualPath.CreateNonRelative(virtualPath), type, out appId, out appHost);
352 internal IRegisteredObject CreateObjectWithDefaultAppHostAndAppId(
354 VirtualPath virtualPath,
357 out IApplicationHost appHost) {
359 HostingEnvironmentParameters hostingParameters = new HostingEnvironmentParameters();
360 hostingParameters.HostingFlags = HostingEnvironmentFlags.DontCallAppInitialize;
362 return CreateObjectWithDefaultAppHostAndAppId(
372 internal IRegisteredObject CreateObjectWithDefaultAppHostAndAppId(
374 VirtualPath virtualPath,
377 HostingEnvironmentParameters hostingParameters,
379 out IApplicationHost appHost) {
381 #if !FEATURE_PAL // FEATURE_PAL does not enable IIS-based hosting features
382 if (physicalPath == null) {
384 // If the physical path is null, we use an ISAPIApplicationHost based
385 // on the virtual path (or metabase id).
387 // Make sure the static HttpRuntime is created so isapi assembly can be loaded properly.
388 HttpRuntime.ForceStaticInit();
390 ISAPIApplicationHost isapiAppHost = new ISAPIApplicationHost(virtualPath.VirtualPathString, null, true, null, hostingParameters.IISExpressVersion);
392 appHost = isapiAppHost;
393 appId = isapiAppHost.AppId;
394 virtualPath = VirtualPath.Create(appHost.GetVirtualPath());
395 physicalPath = FileUtil.FixUpPhysicalDirectory(appHost.GetPhysicalPath());
398 #endif // !FEATURE_PAL
399 // If the physical path was passed in, don't use an Isapi host. Instead,
400 // use a simple app host which does simple virtual to physical mappings
402 // Put together some unique app id
403 appId = CreateSimpleAppID(virtualPath, physicalPath, null);
405 appHost = new SimpleApplicationHost(virtualPath, physicalPath);
408 string precompTargetPhysicalDir = hostingParameters.PrecompilationTargetPhysicalDirectory;
409 if (precompTargetPhysicalDir != null) {
410 // Change the appID so we use a different codegendir in precompile for deployment scenario,
411 // this ensures we don't use or pollute the regular codegen files. Also, use different
412 // ID's depending on whether the precompilation is Updatable (VSWhidbey 383239)
413 if ((hostingParameters.ClientBuildManagerParameter != null) &&
414 (hostingParameters.ClientBuildManagerParameter.PrecompilationFlags & PrecompilationFlags.Updatable) == 0)
415 appId = appId + "_precompile";
417 appId = appId + "_precompile_u";
420 return CreateObjectInternal(appId, type, appHost, failIfExists, hostingParameters);
424 [SecurityPermission(SecurityAction.Demand, Unrestricted = true)]
425 public IRegisteredObject GetObject(String appId, Type type) {
428 throw new ArgumentNullException("appId");
430 throw new ArgumentNullException("type");
432 LockableAppDomainContext ac = GetLockableAppDomainContext(appId);
434 HostingEnvironment env = ac.HostEnv;
438 // find the instance by type
439 // When marshaling Type, the AppDomain must have FileIoPermission to the assembly, which is not
440 // always the case, so we marshal the assembly qualified name instead
441 ObjectHandle h = env.FindWellKnownObject(type.AssemblyQualifiedName);
442 return (h != null) ? h.Unwrap() as IRegisteredObject : null;
446 [SecurityPermission(SecurityAction.Demand, Unrestricted = true)]
447 public AppDomain GetAppDomain(string appId) {
449 throw new ArgumentNullException("appId");
452 LockableAppDomainContext ac = GetLockableAppDomainContext(appId);
454 HostingEnvironment env = ac.HostEnv;
459 return env.HostedAppDomain;
463 public AppDomain GetAppDomain(IApplicationHost appHost) {
464 if (appHost == null) {
465 throw new ArgumentNullException("appHost");
467 string appID = CreateSimpleAppID(appHost);
468 return GetAppDomain(appID);
471 [SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands", Justification = "This isn't a dangerous method.")]
472 private string CreateSimpleAppID(IApplicationHost appHost) {
473 if (appHost == null) {
474 throw new ArgumentNullException("appHost");
476 return CreateSimpleAppID(VirtualPath.Create(appHost.GetVirtualPath()),
477 appHost.GetPhysicalPath(), appHost.GetSiteName());
481 // if a "well-known" object of the specified type already exists in the application,
482 // remove the app from the managed application table. This is
483 // used in IIS7 integrated mode when IIS7 determines that it is necessary to create
484 // a new application and shutdown the old one.
485 internal void RemoveFromTableIfRuntimeExists(String appId, Type runtimeType) {
488 throw new ArgumentNullException("appId");
489 if (runtimeType == null)
490 throw new ArgumentNullException("runtimeType");
492 LockableAppDomainContext ac = GetLockableAppDomainContext(appId);
494 // get hosting environment
495 HostingEnvironment env = ac.HostEnv;
499 // find the instance by type
500 // When marshaling Type, the AppDomain must have FileIoPermission to the assembly, which is not
501 // always the case, so we marshal the assembly qualified name instead
502 ObjectHandle h = env.FindWellKnownObject(runtimeType.AssemblyQualifiedName);
505 // ensure that it is removed from _appDomains by calling
506 // HostingEnvironmentShutdownInitiated directly.
507 HostingEnvironmentShutdownInitiated(appId, env);
512 [SecurityPermission(SecurityAction.Demand, Unrestricted = true)]
513 public void StopObject(String appId, Type type) {
516 throw new ArgumentNullException("appId");
518 throw new ArgumentNullException("type");
520 LockableAppDomainContext ac = GetLockableAppDomainContext(appId);
522 HostingEnvironment env = ac.HostEnv;
524 // When marshaling Type, the AppDomain must have FileIoPermission to the assembly, which is not
525 // always the case, so we marshal the assembly qualified name instead
526 env.StopWellKnownObject(type.AssemblyQualifiedName);
532 public bool IsIdle() {
533 Dictionary<string, LockableAppDomainContext> apps = CloneAppDomainsCollection();
535 foreach (LockableAppDomainContext ac in apps.Values) {
537 HostingEnvironment env = ac.HostEnv;
538 bool idle = (null == env) ? true : env.IsIdle();
549 [SecurityPermission(SecurityAction.Demand, Unrestricted = true)]
550 public void ShutdownApplication(String appId) {
552 throw new ArgumentNullException("appId");
554 LockableAppDomainContext ac = GetLockableAppDomainContext(appId);
556 if (ac.HostEnv != null) {
557 ac.HostEnv.InitiateShutdownInternal();
563 [SecurityPermission(SecurityAction.Demand, Unrestricted = true)]
564 public void ShutdownAll() {
565 _shutdownInProgress = true;
566 Dictionary <string, LockableAppDomainContext> oldTable = null;
568 DisposeCacheManager();
571 oldTable = _appDomains;
572 // don't keep references to hosting environments anymore
573 _appDomains = new Dictionary<string, LockableAppDomainContext>(StringComparer.OrdinalIgnoreCase);
577 foreach (KeyValuePair <string, LockableAppDomainContext> p in oldTable) {
578 LockableAppDomainContext ac = p.Value;
580 HostingEnvironment env = ac.HostEnv;
582 env.InitiateShutdownInternal();
587 for (int iter=0; _activeHostingEnvCount > 0 && iter < 3000; iter++) // Wait at most 5 minutes
592 [SecurityPermission(SecurityAction.Demand, Unrestricted = true)]
593 public ApplicationInfo[] GetRunningApplications() {
594 ArrayList appList = new ArrayList();
596 Dictionary<string, LockableAppDomainContext> apps = CloneAppDomainsCollection();
598 foreach (LockableAppDomainContext ac in apps.Values) {
600 HostingEnvironment env = ac.HostEnv;
602 appList.Add(env.GetApplicationInfo());
607 int n = appList.Count;
608 ApplicationInfo[] result = new ApplicationInfo[n];
611 appList.CopyTo(result);
617 [SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands", Justification = "This method fails due to serialization issues if not called by ASP.NET.")]
618 internal AppDomainInfo [] GetAppDomainInfos()
620 ArrayList appList = new ArrayList();
621 Dictionary<string, LockableAppDomainContext> apps = CloneAppDomainsCollection();
623 foreach (LockableAppDomainContext ac in apps.Values) {
625 HostingEnvironment hostEnv = ac.HostEnv;
626 if (hostEnv == null) {
630 IApplicationHost appHost = hostEnv.InternalApplicationHost;
631 ApplicationInfo appInfo = hostEnv.GetApplicationInfo();
634 if (appHost != null) {
636 siteId = Int32.Parse(appHost.GetSiteID(), CultureInfo.InvariantCulture);
642 AppDomainInfo appDomainInfo = new AppDomainInfo(appInfo.ID,
644 appInfo.PhysicalPath,
646 hostEnv.GetIdleValue());
648 appList.Add(appDomainInfo);
652 return (AppDomainInfo[]) appList.ToArray(typeof(AppDomainInfo));
656 // APIs for the process host to suspend / resume all running applications
659 [SuppressMessage("Microsoft.Reliability", "CA2002:DoNotLockOnObjectsWithWeakIdentity", Justification = "'this' is never a MBRO proxy object.")]
660 internal object SuspendAllApplications() {
661 LockableAppDomainContext[] allAppDomainContexts;
664 allAppDomainContexts = _appDomains.Values.ToArray();
667 ApplicationResumeStateContainer[] resumeContainers = Task.WhenAll(allAppDomainContexts.Select(CreateSuspendTask)).Result;
668 return resumeContainers;
671 private static Task<ApplicationResumeStateContainer> _dummyCompletedSuspendTask = Task.FromResult<ApplicationResumeStateContainer>(null);
672 private static Task<ApplicationResumeStateContainer> CreateSuspendTask(LockableAppDomainContext appDomainContext) {
673 // dictionary contained a null entry?
674 if (appDomainContext == null) {
675 return _dummyCompletedSuspendTask;
678 HostingEnvironment hostEnv;
679 lock (appDomainContext) {
680 hostEnv = appDomainContext.HostEnv;
683 // Quick check: is this a dummy context that had no associated application?
684 if (hostEnv == null) {
685 return _dummyCompletedSuspendTask;
688 // QUWI since we want to run each application's suspend method in parallel.
689 // Unsafe since we don't care about impersonation, identity, etc.
690 // Don't use Task.Run since it captures the EC and could execute inline.
691 TaskCompletionSource<ApplicationResumeStateContainer> tcs = new TaskCompletionSource<ApplicationResumeStateContainer>();
692 ThreadPool.UnsafeQueueUserWorkItem(_ => {
694 // We're not locking on the appDomainContext here. The reason for this is two-fold:
695 // a) We don't want to cause a potential deadlock issue whereby Suspend could kick
696 // off user code that tries calling InitiateShutdown and thus taking a lock on
698 // b) It's easier to try calling into the captured HostingEnvironment and just
699 // ---- the "no AD" exception than it is to try to synchronize the Suspend,
700 // Resume, and Stop methods. The CLR protects us from ourselves here.
702 // We need to use the captured 'hostEnv' to prevent null refs.
706 state = hostEnv.SuspendApplication();
708 catch (AppDomainUnloadedException) {
709 // AD unloads aren't considered a failure
710 tcs.TrySetResult(null);
714 tcs.TrySetResult(new ApplicationResumeStateContainer(hostEnv, state));
719 internal void ResumeAllApplications(object state) {
720 foreach (var resumeContainer in (ApplicationResumeStateContainer[])state) {
721 if (resumeContainer != null) { // could be null if the application went away
722 resumeContainer.Resume();
728 // ping implementation
731 // called from process host
732 internal void Ping(IProcessPingCallback callback) {
733 if (callback == null || _pendingPingCallback != null)
736 // remember active callback but only if none is remembered already
737 if (Interlocked.CompareExchange(ref _pendingPingCallback, callback, null) == null) {
738 // queue a work item to respond to ping
739 ThreadPool.QueueUserWorkItem(_onRespondToPingWaitCallback);
743 // threadpool callback (also called on some activity from hosting environment)
744 internal void OnRespondToPingWaitCallback(Object state) {
745 RespondToPingIfNeeded();
748 // respond to ping on callback
749 internal void RespondToPingIfNeeded() {
750 IProcessPingCallback callback = _pendingPingCallback as IProcessPingCallback;
752 // make sure we call the callback once
753 if (callback != null) {
754 if (Interlocked.CompareExchange(ref _pendingPingCallback, null, callback) == callback) {
760 // ApplicationManager is loaded into the default AppDomain
761 // ASP.NET doesn't set string hash randomization for the defaul AppDomain, so we can assume the existing CLR implementation here is unchanged
762 // Note, it won't work if <runtime/UseRandomizedStringHashAlgorithm enabled="1"> is used, because the entire process is subject to string hash randomization
763 internal int GetNonRandomizedStringComparerHashCode(string s, bool ignoreCase) {
764 StringComparer comparer = ignoreCase ? StringComparer.InvariantCultureIgnoreCase : StringComparer.InvariantCulture;
765 return comparer.GetHashCode(s);
769 // communication with hosting environments
772 internal void HostingEnvironmentActivated(long privateBytesLimit) {
773 int count = Interlocked.Increment(ref _activeHostingEnvCount);
775 // initialize CacheManager once, without blocking
777 InitCacheManager(privateBytesLimit);
781 internal void HostingEnvironmentShutdownComplete(String appId, IApplicationHost appHost) {
783 if (appHost != null) {
784 // make sure application host can be GC'd
785 MarshalByRefObject realApplicationHost = appHost as MarshalByRefObject;
786 if (realApplicationHost != null) {
787 RemotingServices.Disconnect(realApplicationHost);
792 Interlocked.Decrement(ref _activeHostingEnvCount);
796 internal void HostingEnvironmentShutdownInitiated(String appId, HostingEnvironment env) {
797 if (!_shutdownInProgress) { // don't bother during shutdown (while enumerating)
798 LockableAppDomainContext ac = GetLockableAppDomainContext (appId);
801 if (!env.HasBeenRemovedFromAppManagerTable) {
802 env.HasBeenRemovedFromAppManagerTable = true;
805 Interlocked.Decrement(ref _accessibleHostingEnvCount);
807 // Autorestart the application right away
808 if (ac.PreloadContext != null && !ac.RetryingPreload) {
809 ProcessHost.PreloadApplicationIfNotShuttingdown(appId, ac);
816 internal int AppDomainsCount {
817 get { return _accessibleHostingEnvCount; }
821 internal void ReduceAppDomainsCount(int limit) {
827 Dictionary<string, LockableAppDomainContext> apps = CloneAppDomainsCollection();
828 while (_accessibleHostingEnvCount >= limit && !_shutdownInProgress)
830 LockableAppDomainContext bestCandidateForShutdown = null;
831 int bestCandidateLruScore = 0;
833 foreach (LockableAppDomainContext ac in apps.Values) {
834 // Don't lock on LockableAppDomainContext before we check that ac.HostEnv != null.
835 // Otherwise we may end up with a deadlock between 2 app domains trying to unload each other
836 HostingEnvironment h = ac.HostEnv;
843 // Avoid ---- by checking again under lock
847 int newLruScore = h.LruScore;
849 if (bestCandidateForShutdown == null || bestCandidateForShutdown.HostEnv == null ||
850 newLruScore < bestCandidateLruScore) {
852 bestCandidateLruScore = newLruScore;
853 bestCandidateForShutdown = ac;
858 if (bestCandidateForShutdown == null)
861 lock (bestCandidateForShutdown) {
862 if (bestCandidateForShutdown.HostEnv != null) {
863 bestCandidateForShutdown.HostEnv.InitiateShutdownInternal();
870 // helper to support legacy APIs (AppHost.CreateAppHost)
873 internal ObjectHandle CreateInstanceInNewWorkerAppDomain(
876 VirtualPath virtualPath,
877 String physicalPath) {
879 Debug.Trace("AppManager", "CreateObjectInNewWorkerAppDomain, type=" + type.FullName);
881 IApplicationHost appHost = new SimpleApplicationHost(virtualPath, physicalPath);
883 HostingEnvironmentParameters hostingParameters = new HostingEnvironmentParameters();
884 hostingParameters.HostingFlags = HostingEnvironmentFlags.HideFromAppManager;
886 HostingEnvironment env = CreateAppDomainWithHostingEnvironmentAndReportErrors(appId, appHost, hostingParameters);
887 // When marshaling Type, the AppDomain must have FileIoPermission to the assembly, which is not
888 // always the case, so we marshal the assembly qualified name instead
889 return env.CreateInstance(type.AssemblyQualifiedName);
893 // helpers to facilitate app domain creation
895 private HostingEnvironment GetAppDomainWithHostingEnvironment(String appId, IApplicationHost appHost, HostingEnvironmentParameters hostingParameters) {
896 LockableAppDomainContext ac = GetLockableAppDomainContext (appId);
899 HostingEnvironment env = ac.HostEnv;
904 } catch(AppDomainUnloadedException) {
909 env = CreateAppDomainWithHostingEnvironmentAndReportErrors(appId, appHost, hostingParameters);
911 Interlocked.Increment(ref _accessibleHostingEnvCount);
919 private HostingEnvironment CreateAppDomainWithHostingEnvironmentAndReportErrors(
921 IApplicationHost appHost,
922 HostingEnvironmentParameters hostingParameters) {
924 return CreateAppDomainWithHostingEnvironment(appId, appHost, hostingParameters);
926 catch (Exception e) {
927 Misc.ReportUnhandledException(e, new string[] {SR.GetString(SR.Failed_to_initialize_AppDomain), appId});
932 [SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands", Justification = "We carefully control the callers.")]
933 [SuppressMessage("Microsoft.Usage", "CA1806:DoNotIgnoreMethodResults", MessageId = "System.Boolean.TryParse(System.String,System.Boolean@)", Justification = "Sets parameter to default(bool) on conversion failure, which is semantic we need.")]
934 private HostingEnvironment CreateAppDomainWithHostingEnvironment(
936 IApplicationHost appHost,
937 HostingEnvironmentParameters hostingParameters) {
939 String physicalPath = appHost.GetPhysicalPath();
940 if (!StringUtil.StringEndsWith(physicalPath, Path.DirectorySeparatorChar))
941 physicalPath = physicalPath + Path.DirectorySeparatorChar;
943 String domainId = ConstructAppDomainId(appId);
944 String appName = (StringUtil.GetStringHashCode(String.Concat(appId.ToLower(CultureInfo.InvariantCulture),
945 physicalPath.ToLower(CultureInfo.InvariantCulture)))).ToString("x", CultureInfo.InvariantCulture);
946 VirtualPath virtualPath = VirtualPath.Create(appHost.GetVirtualPath());
948 Debug.Trace("AppManager", "CreateAppDomainWithHostingEnvironment, path=" + physicalPath + "; appId=" + appId + "; domainId=" + domainId);
950 IDictionary bindings = new Hashtable(20);
951 AppDomainSetup setup = new AppDomainSetup();
952 AppDomainSwitches switches = new AppDomainSwitches();
953 PopulateDomainBindings(domainId, appId, appName, physicalPath, virtualPath, setup, bindings);
955 // Create the app domain
957 AppDomain appDomain = null;
958 Dictionary<string, object> appDomainAdditionalData = new Dictionary<string, object>();
959 Exception appDomainCreationException = null;
961 string siteID = appHost.GetSiteID();
962 string appSegment = virtualPath.VirtualPathStringNoTrailingSlash;
963 bool inClientBuildManager = false;
964 Configuration appConfig = null;
965 PolicyLevel policyLevel = null;
966 PermissionSet permissionSet = null;
967 List<StrongName> fullTrustAssemblies = new List<StrongName>();
968 string[] defaultPartialTrustVisibleAssemblies = new[] { "System.Web, PublicKey=002400000480000094000000060200000024000052534131000400000100010007d1fa57c4aed9f0a32e84aa0faefd0de9e8fd6aec8f87fb03766c834c99921eb23be79ad9d5dcc1dd9ad236132102900b723cf980957fc4e177108fc607774f29e8320e92ea05ece4e821c0a5efe8f1645c4c0c93c1ab99285d622caa652c1dfad63d745d6f2de5f17e5eaf0fc4963d261c8a12436518206dc093344d5ad293",
969 "System.Web.Extensions, PublicKey=0024000004800000940000000602000000240000525341310004000001000100b5fc90e7027f67871e773a8fde8938c81dd402ba65b9201d60593e96c492651e889cc13f1415ebb53fac1131ae0bd333c5ee6021672d9718ea31a8aebd0da0072f25d87dba6fc90ffd598ed4da35e44c398c454307e8e33b8426143daec9f596836f97c8f74750e5975c64e2189f45def46b2a2b1247adc3652bf5c308055da9",
970 "System.Web.Abstractions, PublicKey=0024000004800000940000000602000000240000525341310004000001000100b5fc90e7027f67871e773a8fde8938c81dd402ba65b9201d60593e96c492651e889cc13f1415ebb53fac1131ae0bd333c5ee6021672d9718ea31a8aebd0da0072f25d87dba6fc90ffd598ed4da35e44c398c454307e8e33b8426143daec9f596836f97c8f74750e5975c64e2189f45def46b2a2b1247adc3652bf5c308055da9",
971 "System.Web.Routing, PublicKey=0024000004800000940000000602000000240000525341310004000001000100b5fc90e7027f67871e773a8fde8938c81dd402ba65b9201d60593e96c492651e889cc13f1415ebb53fac1131ae0bd333c5ee6021672d9718ea31a8aebd0da0072f25d87dba6fc90ffd598ed4da35e44c398c454307e8e33b8426143daec9f596836f97c8f74750e5975c64e2189f45def46b2a2b1247adc3652bf5c308055da9",
972 "System.Web.DynamicData, PublicKey=0024000004800000940000000602000000240000525341310004000001000100b5fc90e7027f67871e773a8fde8938c81dd402ba65b9201d60593e96c492651e889cc13f1415ebb53fac1131ae0bd333c5ee6021672d9718ea31a8aebd0da0072f25d87dba6fc90ffd598ed4da35e44c398c454307e8e33b8426143daec9f596836f97c8f74750e5975c64e2189f45def46b2a2b1247adc3652bf5c308055da9",
973 "System.Web.DataVisualization, PublicKey=0024000004800000940000000602000000240000525341310004000001000100b5fc90e7027f67871e773a8fde8938c81dd402ba65b9201d60593e96c492651e889cc13f1415ebb53fac1131ae0bd333c5ee6021672d9718ea31a8aebd0da0072f25d87dba6fc90ffd598ed4da35e44c398c454307e8e33b8426143daec9f596836f97c8f74750e5975c64e2189f45def46b2a2b1247adc3652bf5c308055da9",
974 "System.Web.ApplicationServices, PublicKey=0024000004800000940000000602000000240000525341310004000001000100b5fc90e7027f67871e773a8fde8938c81dd402ba65b9201d60593e96c492651e889cc13f1415ebb53fac1131ae0bd333c5ee6021672d9718ea31a8aebd0da0072f25d87dba6fc90ffd598ed4da35e44c398c454307e8e33b8426143daec9f596836f97c8f74750e5975c64e2189f45def46b2a2b1247adc3652bf5c308055da9" };
976 Exception appDomainStartupConfigurationException = null;
977 ImpersonationContext ictxConfig = null;
978 IntPtr uncTokenConfig = IntPtr.Zero;
979 HostingEnvironmentFlags hostingFlags = HostingEnvironmentFlags.Default;
980 if (hostingParameters != null) {
981 hostingFlags = hostingParameters.HostingFlags;
982 if ((hostingFlags & HostingEnvironmentFlags.ClientBuildManager) != 0) {
983 inClientBuildManager = true;
984 // The default hosting policy in VS has changed (from MultiDomainHost to MultiDomain),
985 // so we need to specify explicitly to allow generated assemblies
986 // to be unloaded subsequently. (Dev10 bug)
987 setup.LoaderOptimization = LoaderOptimization.MultiDomainHost;
991 bool requireHostExecutionContextManager = false;
992 bool requireHostSecurityManager = false;
994 uncTokenConfig = appHost.GetConfigToken();
995 if (uncTokenConfig != IntPtr.Zero) {
996 ictxConfig = new ImpersonationContext(uncTokenConfig);
1000 // Did the custom loader fail to load?
1001 ExceptionDispatchInfo customLoaderException = ProcessHost.GetExistingCustomLoaderFailureAndClear(appId);
1002 if (customLoaderException != null) {
1003 customLoaderException.Throw();
1006 // We support randomized string hash code, but not for the default AppDomain
1007 // Don't allow string hash randomization for the defaul AppDomain (i.e. <runtime/UseRandomizedStringHashAlgorithm enabled="1">)
1008 // Application should use AppSettings instead to opt-in.
1009 if (EnvironmentInfo.IsStringHashCodeRandomizationDetected) {
1010 throw new ConfigurationErrorsException(SR.GetString(SR.Require_stable_string_hash_codes));
1013 bool skipAdditionalConfigChecks = false;
1014 if (inClientBuildManager && hostingParameters.IISExpressVersion != null) {
1015 permissionSet = new PermissionSet(PermissionState.Unrestricted);
1016 setup.PartialTrustVisibleAssemblies = defaultPartialTrustVisibleAssemblies;
1017 appConfig = GetAppConfigIISExpress(siteID, appSegment, hostingParameters.IISExpressVersion);
1018 skipAdditionalConfigChecks = true;
1021 //Hosted by IIS, we already have an IISMap.
1022 if (appHost is ISAPIApplicationHost) {
1023 string cacheKey = System.Web.Caching.CacheInternal.PrefixMapPath + siteID + virtualPath.VirtualPathString;
1024 MapPathCacheInfo cacheInfo = (MapPathCacheInfo)HttpRuntime.CacheInternal.Remove(cacheKey);
1025 appConfig = WebConfigurationManager.OpenWebConfiguration(appSegment, siteID);
1027 // For non-IIS hosting scenarios, we need to get config map from application host in a generic way.
1029 appConfig = GetAppConfigGeneric(appHost, siteID, appSegment, virtualPath, physicalPath);
1033 HttpRuntimeSection httpRuntimeSection = (HttpRuntimeSection)appConfig.GetSection("system.web/httpRuntime");
1034 if (httpRuntimeSection == null) {
1035 throw new ConfigurationErrorsException(SR.GetString(SR.Config_section_not_present, "httpRuntime"));
1038 // DevDiv #403846 - Change certain config defaults if <httpRuntime targetFramework="4.5" /> exists in config.
1039 // We store this information in the AppDomain data because certain configuration sections (like <compilation>)
1040 // are loaded before config is "baked" in the child AppDomain, and if we make <compilation> and other sections
1041 // dependent on <httpRuntime> which may not have been loaded yet, we risk introducing ----s. Putting this value
1042 // in the AppDomain data guarantees that it is available before the first call to the config system.
1043 FrameworkName targetFrameworkName = httpRuntimeSection.GetTargetFrameworkName();
1044 if (targetFrameworkName != null) {
1045 appDomainAdditionalData[System.Web.Util.BinaryCompatibility.TargetFrameworkKey] = targetFrameworkName;
1048 if (!skipAdditionalConfigChecks) {
1049 // DevDiv #71268 - Add <httpRuntime defaultRegexMatchTimeout="HH:MM:SS" /> configuration attribute
1050 if (httpRuntimeSection.DefaultRegexMatchTimeout != TimeSpan.Zero) {
1051 appDomainAdditionalData[_regexMatchTimeoutKey] = httpRuntimeSection.DefaultRegexMatchTimeout;
1054 // DevDiv #258274 - Add support for CLR quirks mode to ASP.NET
1055 if (targetFrameworkName != null) {
1056 setup.TargetFrameworkName = targetFrameworkName.ToString();
1059 // DevDiv #286354 - Having a Task-friendly SynchronizationContext requires overriding the AppDomain's HostExecutionContextManager.
1060 // DevDiv #403846 - If we can't parse the <appSettings> switch, use the <httpRuntime/targetFramework> setting to determine the default.
1061 AppSettingsSection appSettingsSection = appConfig.AppSettings;
1062 KeyValueConfigurationElement useTaskFriendlySynchronizationContextElement = appSettingsSection.Settings["aspnet:UseTaskFriendlySynchronizationContext"];
1063 if (!(useTaskFriendlySynchronizationContextElement != null && Boolean.TryParse(useTaskFriendlySynchronizationContextElement.Value, out requireHostExecutionContextManager))) {
1064 requireHostExecutionContextManager = new System.Web.Util.BinaryCompatibility(targetFrameworkName).TargetsAtLeastFramework45 ? true : false;
1067 // DevDiv #390704 - Add support for randomized string hash algorithm
1068 KeyValueConfigurationElement useRandomizedStringHashAlgorithmElement = appSettingsSection.Settings["aspnet:UseRandomizedStringHashAlgorithm"];
1069 bool useRandomizedStringHashAlgorithm = false;
1070 if (useRandomizedStringHashAlgorithmElement != null && Boolean.TryParse(useRandomizedStringHashAlgorithmElement.Value, out useRandomizedStringHashAlgorithm)) {
1071 switches.UseRandomizedStringHashAlgorithm = useRandomizedStringHashAlgorithm;
1074 // DevDiv #1041102 - Allow specifying quirks via <appSettings> switches
1075 // The keys must begin with "AppContext.SetSwitch" and have a non-zero key name length,
1076 // and the values must be parseable as Booleans.
1077 Dictionary<string, bool> clrQuirks = null;
1078 foreach (KeyValueConfigurationElement element in appSettingsSection.Settings) {
1079 if (element.Key != null && element.Key.Length > _clrQuirkAppSettingsAppContextPrefix.Length && element.Key.StartsWith(_clrQuirkAppSettingsAppContextPrefix, StringComparison.OrdinalIgnoreCase)) {
1081 if (Boolean.TryParse(element.Value, out value)) {
1082 if (clrQuirks == null) {
1083 clrQuirks = new Dictionary<string, bool>();
1086 clrQuirks[element.Key.Substring(_clrQuirkAppSettingsAppContextPrefix.Length)] = value;
1091 if (clrQuirks != null && clrQuirks.Count > 0) {
1092 if (hostingParameters == null) {
1093 hostingParameters = new HostingEnvironmentParameters();
1096 hostingParameters.ClrQuirksSwitches = clrQuirks.ToArray();
1099 // DevDiv #248126 - Allow configuration of FileChangeMonitor behavior
1100 if (httpRuntimeSection.FcnMode != FcnMode.NotSet) {
1101 if (hostingParameters == null) {
1102 hostingParameters = new HostingEnvironmentParameters();
1104 hostingParameters.FcnMode = httpRuntimeSection.FcnMode;
1107 // DevDiv #322858 - Allow FileChangesMonitor to skip reading DACLs as a perf improvement
1108 KeyValueConfigurationElement disableFcnDaclReadElement = appSettingsSection.Settings["aspnet:DisableFcnDaclRead"];
1109 if (disableFcnDaclReadElement != null) {
1110 bool skipReadingAndCachingDacls;
1111 Boolean.TryParse(disableFcnDaclReadElement.Value, out skipReadingAndCachingDacls);
1112 if (skipReadingAndCachingDacls) {
1113 if (hostingParameters == null) {
1114 hostingParameters = new HostingEnvironmentParameters();
1116 hostingParameters.FcnSkipReadAndCacheDacls = true;
1120 // If we were launched from a development environment, we might want to enable the application to do things
1121 // it otherwise wouldn't normally allow, such as enabling an administrative control panel. For security reasons,
1122 // we only do this check if <deployment retail="false" /> [the default value] is specified, since the
1123 // <deployment> element can only be set at machine-level in a hosted environment.
1124 DeploymentSection deploymentSection = (DeploymentSection)appConfig.GetSection("system.web/deployment");
1125 bool isDevEnvironment = false;
1126 if (deploymentSection != null && !deploymentSection.Retail && EnvironmentInfo.WasLaunchedFromDevelopmentEnvironment) {
1127 appDomainAdditionalData[".devEnvironment"] = true;
1128 isDevEnvironment = true;
1130 // DevDiv #275724 - Allow LocalDB support in partial trust scenarios
1131 // Normally LocalDB requires full trust since it's the equivalent of unmanaged code execution. If this is
1132 // a development environment and not a retail deployment, we can assume that the user developing the
1133 // application is actually in charge of the host, so we can trust him with LocalDB execution.
1134 // Technically this also means that the developer could have set <trust level="Full" /> in his application,
1135 // but he might want to deploy his application on a Medium-trust server and thus test how the rest of his
1136 // application works in a partial trust environment. (He would use SQL in production, whch is safe in
1138 appDomainAdditionalData["ALLOW_LOCALDB_IN_PARTIAL_TRUST"] = true;
1141 TrustSection trustSection = (TrustSection)appConfig.GetSection("system.web/trust");
1142 if (trustSection == null || String.IsNullOrEmpty(trustSection.Level)) {
1143 throw new ConfigurationErrorsException(SR.GetString(SR.Config_section_not_present, "trust"));
1146 switches.UseLegacyCas = trustSection.LegacyCasModel;
1148 if (inClientBuildManager) {
1149 permissionSet = new PermissionSet(PermissionState.Unrestricted);
1150 setup.PartialTrustVisibleAssemblies = defaultPartialTrustVisibleAssemblies;
1153 if (!switches.UseLegacyCas) {
1154 if (trustSection.Level == "Full") {
1155 permissionSet = new PermissionSet(PermissionState.Unrestricted);
1156 setup.PartialTrustVisibleAssemblies = defaultPartialTrustVisibleAssemblies;
1159 SecurityPolicySection securityPolicySection = (SecurityPolicySection)appConfig.GetSection("system.web/securityPolicy");
1160 CompilationSection compilationSection = (CompilationSection)appConfig.GetSection("system.web/compilation");
1161 FullTrustAssembliesSection fullTrustAssembliesSection = (FullTrustAssembliesSection)appConfig.GetSection("system.web/fullTrustAssemblies");
1162 policyLevel = GetPartialTrustPolicyLevel(trustSection, securityPolicySection, compilationSection, physicalPath, virtualPath, isDevEnvironment);
1163 permissionSet = policyLevel.GetNamedPermissionSet(trustSection.PermissionSetName);
1164 if (permissionSet == null) {
1165 throw new ConfigurationErrorsException(SR.GetString(SR.Permission_set_not_found, trustSection.PermissionSetName));
1168 // read full trust assemblies and populate the strong name list
1169 if (fullTrustAssembliesSection != null) {
1170 FullTrustAssemblyCollection fullTrustAssembliesCollection = fullTrustAssembliesSection.FullTrustAssemblies;
1171 if (fullTrustAssembliesCollection != null) {
1172 fullTrustAssemblies.AddRange(from FullTrustAssembly fta in fullTrustAssembliesCollection
1173 select CreateStrongName(fta.AssemblyName, fta.Version, fta.PublicKey));
1177 // DevDiv #27645 - We need to add future versions of Microsoft.Web.Infrastructure to <fullTrustAssemblies> so that ASP.NET
1178 // can version out-of-band releases. We should only do this if V1 of M.W.I is listed.
1179 if (fullTrustAssemblies.Contains(_mwiV1StrongName)) {
1180 fullTrustAssemblies.AddRange(CreateFutureMicrosoftWebInfrastructureStrongNames());
1183 // Partial-trust AppDomains using a non-legacy CAS model require our special HostSecurityManager
1184 requireHostSecurityManager = true;
1187 if (trustSection.Level != "Full") {
1188 PartialTrustVisibleAssembliesSection partialTrustVisibleAssembliesSection = (PartialTrustVisibleAssembliesSection)appConfig.GetSection("system.web/partialTrustVisibleAssemblies");
1189 string[] partialTrustVisibleAssemblies = null;
1190 if (partialTrustVisibleAssembliesSection != null) {
1191 PartialTrustVisibleAssemblyCollection partialTrustVisibleAssembliesCollection = partialTrustVisibleAssembliesSection.PartialTrustVisibleAssemblies;
1192 if (partialTrustVisibleAssembliesCollection != null && partialTrustVisibleAssembliesCollection.Count != 0) {
1193 partialTrustVisibleAssemblies = new string[partialTrustVisibleAssembliesCollection.Count + defaultPartialTrustVisibleAssemblies.Length];
1194 for (int i = 0; i < partialTrustVisibleAssembliesCollection.Count; i++) {
1195 partialTrustVisibleAssemblies[i] = partialTrustVisibleAssembliesCollection[i].AssemblyName +
1197 NormalizePublicKeyBlob(partialTrustVisibleAssembliesCollection[i].PublicKey);
1199 defaultPartialTrustVisibleAssemblies.CopyTo(partialTrustVisibleAssemblies, partialTrustVisibleAssembliesCollection.Count);
1202 if (partialTrustVisibleAssemblies == null) {
1203 partialTrustVisibleAssemblies = defaultPartialTrustVisibleAssemblies;
1205 setup.PartialTrustVisibleAssemblies = partialTrustVisibleAssemblies;
1210 catch (Exception e) {
1211 appDomainStartupConfigurationException = e;
1212 permissionSet = new PermissionSet(PermissionState.Unrestricted);
1215 // Set the AppDomainManager if needed
1216 Type appDomainManagerType = AspNetAppDomainManager.GetAspNetAppDomainManagerType(requireHostExecutionContextManager, requireHostSecurityManager);
1217 if (appDomainManagerType != null) {
1218 setup.AppDomainManagerType = appDomainManagerType.FullName;
1219 setup.AppDomainManagerAssembly = appDomainManagerType.Assembly.FullName;
1222 // Apply compatibility switches
1223 switches.Apply(setup);
1226 if (switches.UseLegacyCas) {
1227 appDomain = AppDomain.CreateDomain(domainId,
1228 #if FEATURE_PAL // FEATURE_PAL: hack to avoid non-supported hosting features
1230 #else // FEATURE_PAL
1231 GetDefaultDomainIdentity(),
1232 #endif // FEATURE_PAL
1236 appDomain = AppDomain.CreateDomain(domainId,
1237 #if FEATURE_PAL // FEATURE_PAL: hack to avoid non-supported hosting features
1239 #else // FEATURE_PAL
1240 GetDefaultDomainIdentity(),
1241 #endif // FEATURE_PAL
1244 fullTrustAssemblies.ToArray() /* fully trusted assemblies list: empty list means only trust GAC assemblies */);
1246 foreach (DictionaryEntry e in bindings)
1247 appDomain.SetData((String)e.Key, (String)e.Value);
1248 foreach (var entry in appDomainAdditionalData)
1249 appDomain.SetData(entry.Key, entry.Value);
1251 catch (Exception e) {
1252 Debug.Trace("AppManager", "AppDomain.CreateDomain failed", e);
1253 appDomainCreationException = e;
1257 if (ictxConfig != null) {
1261 if (uncTokenConfig != IntPtr.Zero) {
1262 UnsafeNativeMethods.CloseHandle(uncTokenConfig);
1263 uncTokenConfig = IntPtr.Zero;
1267 if (appDomain == null) {
1268 throw new SystemException(SR.GetString(SR.Cannot_create_AppDomain), appDomainCreationException);
1271 // Create hosting environment in the new app domain
1273 Type hostType = typeof(HostingEnvironment);
1274 String module = hostType.Module.Assembly.FullName;
1275 String typeName = hostType.FullName;
1276 ObjectHandle h = null;
1278 // impersonate UNC identity, if any
1279 ImpersonationContext ictx = null;
1280 IntPtr uncToken = IntPtr.Zero;
1283 // fetching config can fail due to a ---- with the
1284 // native config reader
1285 // if that has happened, force a flush
1287 int maxRetries = 10;
1290 while (numRetries < maxRetries) {
1292 uncToken = appHost.GetConfigToken();
1293 // no throw, so break
1296 catch (InvalidOperationException) {
1298 System.Threading.Thread.Sleep(250);
1303 if (uncToken != IntPtr.Zero) {
1305 ictx = new ImpersonationContext(uncToken);
1310 UnsafeNativeMethods.CloseHandle(uncToken);
1316 // Create the hosting environment in the app domain
1319 h = Activator.CreateInstance(appDomain, module, typeName);
1321 catch (Exception e) {
1322 Debug.Trace("AppManager", "appDomain.CreateInstance failed; identity=" + System.Security.Principal.WindowsIdentity.GetCurrent().Name, e);
1326 h = Activator.CreateInstance(appDomain, module, typeName);
1330 // revert impersonation
1335 AppDomain.Unload(appDomain);
1339 HostingEnvironment env = (h != null) ? h.Unwrap() as HostingEnvironment : null;
1342 throw new SystemException(SR.GetString(SR.Cannot_create_HostEnv));
1344 // initialize the hosting environment
1345 IConfigMapPathFactory configMapPathFactory = appHost.GetConfigMapPathFactory();
1346 if (appDomainStartupConfigurationException == null) {
1347 env.Initialize(this, appHost, configMapPathFactory, hostingParameters, policyLevel);
1350 env.Initialize(this, appHost, configMapPathFactory, hostingParameters, policyLevel, appDomainStartupConfigurationException);
1355 private static string NormalizePublicKeyBlob(string publicKey) {
1356 StringBuilder sb = new StringBuilder();
1357 for (int i = 0; i < publicKey.Length; i++) {
1358 if (!Char.IsWhiteSpace(publicKey[i])) {
1359 sb.Append(publicKey[i]);
1362 publicKey = sb.ToString();
1366 private static StrongName CreateStrongName(string assemblyName, string version, string publicKeyString) {
1367 byte[] publicKey = null;
1368 StrongName strongName = null;
1369 publicKeyString = NormalizePublicKeyBlob(publicKeyString);
1370 int publicKeySize = publicKeyString.Length / 2;
1371 publicKey = new byte[publicKeySize];
1372 for (int i = 0; i < publicKeySize; i++) {
1373 publicKey[i] = Byte.Parse(publicKeyString.Substring(i * 2, 2), System.Globalization.NumberStyles.HexNumber, CultureInfo.InvariantCulture);
1375 StrongNamePublicKeyBlob keyBlob = new StrongNamePublicKeyBlob(publicKey);
1376 strongName = new StrongName(keyBlob, assemblyName, new Version(version));
1380 // For various reasons, we can't add any entries to the <fullTrustAssemblies> list until .NET 5, which at the time of this writing is a few
1381 // years out. But since ASP.NET releases projects out-of-band from the .NET Framework as a whole (using Microsoft.Web.Infrasturcture), we
1382 // need to be sure that future versions of M.W.I have the ability to assert full trust. This code works by seeing if M.W.I v1 is in the
1383 // <fullTrustAssemblies> list, and if it is then v2 - v10 are implicitly added. If v1 is not present in the <fTA> list, then we'll not
1384 // treat v2 - v10 as implicitly added. See DevDiv #27645 for more information.
1386 private static StrongName GetMicrosoftWebInfrastructureV1StrongName() {
1387 return CreateStrongName(
1388 assemblyName: "Microsoft.Web.Infrastructure",
1390 publicKeyString: "0024000004800000940000000602000000240000525341310004000001000100B5FC90E7027F67871E773A8FDE8938C81DD402BA65B9201D60593E96C492651E889CC13F1415EBB53FAC1131AE0BD333C5EE6021672D9718EA31A8AEBD0DA0072F25D87DBA6FC90FFD598ED4DA35E44C398C454307E8E33B8426143DAEC9F596836F97C8F74750E5975C64E2189F45DEF46B2A2B1247ADC3652BF5C308055DA9");
1393 private static IEnumerable<StrongName> CreateFutureMicrosoftWebInfrastructureStrongNames() {
1394 string asmName = _mwiV1StrongName.Name;
1395 StrongNamePublicKeyBlob publicKey = _mwiV1StrongName.PublicKey;
1396 for (int i = 2; i <= 10; i++) {
1397 yield return new StrongName(publicKey, asmName, new Version(i, 0, 0, 0));
1402 // devdiv 1038337: execution permission cannot be acquired under partial trust with ctrl-f5.
1403 // We build the codegen path in default domain. In order to build the right path,
1404 // caller must pass in a flag indicating whether it is under dev environment.
1405 [SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands", Justification = "We carefully control this method's caller.")]
1406 private static PolicyLevel GetPartialTrustPolicyLevel(
1407 TrustSection trustSection, SecurityPolicySection securityPolicySection,
1408 CompilationSection compilationSection, string physicalPath, VirtualPath virtualPath, bool isDevEnvironment) {
1409 if (securityPolicySection == null || securityPolicySection.TrustLevels[trustSection.Level] == null) {
1410 throw new ConfigurationErrorsException(SR.GetString(SR.Unable_to_get_policy_file, trustSection.Level), String.Empty, 0);
1412 String configFile = (String)securityPolicySection.TrustLevels[trustSection.Level].PolicyFileExpanded;
1413 if (configFile == null || !FileUtil.FileExists(configFile)) {
1414 throw new HttpException(SR.GetString(SR.Unable_to_get_policy_file, trustSection.Level));
1416 PolicyLevel policyLevel = null;
1417 String appDir = FileUtil.RemoveTrailingDirectoryBackSlash(physicalPath);
1418 String appDirUrl = HttpRuntime.MakeFileUrl(appDir);
1420 // setup $CodeGen$ replacement
1421 string tempDirectory = null;
1422 // These variables are used for error handling
1423 string tempDirAttribName = null;
1424 string configFileName = null;
1425 int configLineNumber = 0;
1426 if (compilationSection != null && !String.IsNullOrEmpty(compilationSection.TempDirectory)) {
1427 tempDirectory = compilationSection.TempDirectory;
1428 compilationSection.GetTempDirectoryErrorInfo(out tempDirAttribName,
1429 out configFileName, out configLineNumber);
1431 if (tempDirectory != null) {
1432 tempDirectory = tempDirectory.Trim();
1433 if (!Path.IsPathRooted(tempDirectory)) {
1434 // Make sure the path is not relative (VSWhidbey 260075)
1435 tempDirectory = null;
1439 // Canonicalize it to avoid problems with spaces (VSWhidbey 229873)
1440 tempDirectory = new DirectoryInfo(tempDirectory).FullName;
1443 tempDirectory = null;
1446 if (tempDirectory == null) {
1447 throw new ConfigurationErrorsException(
1448 SR.GetString(SR.Invalid_temp_directory, tempDirAttribName),
1449 configFileName, configLineNumber);
1451 // Create the config-specified directory if needed
1453 Directory.CreateDirectory(tempDirectory);
1455 catch (Exception e) {
1456 throw new ConfigurationErrorsException(
1457 SR.GetString(SR.Invalid_temp_directory, tempDirAttribName),
1459 configFileName, configLineNumber);
1463 tempDirectory = Path.Combine(RuntimeEnvironment.GetRuntimeDirectory(), HttpRuntime.codegenDirName);
1465 // If we don't have write access to the codegen dir, use the TEMP dir instead.
1466 // This will allow non-admin users to work in hosting scenarios (e.g. Venus, aspnet_compiler)
1467 if (!System.Web.UI.Util.HasWriteAccessToDirectory(tempDirectory)) {
1468 // Don't do this if we're in a service (!UserInteractive), as TEMP
1469 // could point to unwanted places.
1470 if (!Environment.UserInteractive) {
1471 throw new HttpException(SR.GetString(SR.No_codegen_access,
1472 System.Web.UI.Util.GetCurrentAccountName(), tempDirectory));
1474 tempDirectory = Path.GetTempPath();
1475 Debug.Assert(System.Web.UI.Util.HasWriteAccessToDirectory(tempDirectory));
1476 tempDirectory = Path.Combine(tempDirectory, HttpRuntime.codegenDirName);
1478 String simpleAppName = System.Web.Hosting.AppManagerAppDomainFactory.ConstructSimpleAppName(
1479 VirtualPath.GetVirtualPathStringNoTrailingSlash(virtualPath), isDevEnvironment);
1480 String binDir = Path.Combine(tempDirectory, simpleAppName);
1481 binDir = FileUtil.RemoveTrailingDirectoryBackSlash(binDir);
1482 String binDirUrl = HttpRuntime.MakeFileUrl(binDir);
1484 String originUrl = trustSection.OriginUrl;
1485 FileStream file = new FileStream(configFile, FileMode.Open, FileAccess.Read);
1486 StreamReader reader = new StreamReader(file, Encoding.UTF8);
1487 String strFileData = reader.ReadToEnd();
1489 strFileData = strFileData.Replace("$AppDir$", appDir);
1490 strFileData = strFileData.Replace("$AppDirUrl$", appDirUrl);
1491 strFileData = strFileData.Replace("$CodeGen$", binDirUrl);
1492 if (originUrl == null)
1493 originUrl = String.Empty;
1494 strFileData = strFileData.Replace("$OriginHost$", originUrl);
1495 String gacLocation = null;
1496 if (strFileData.IndexOf("$Gac$", StringComparison.Ordinal) != -1) {
1497 gacLocation = HttpRuntime.GetGacLocation();
1498 if (gacLocation != null)
1499 gacLocation = HttpRuntime.MakeFileUrl(gacLocation);
1500 if (gacLocation == null)
1501 gacLocation = String.Empty;
1502 strFileData = strFileData.Replace("$Gac$", gacLocation);
1504 #pragma warning disable 618 // ASP is reading their grant set out of legacy policy level files
1505 policyLevel = SecurityManager.LoadPolicyLevelFromString(strFileData, PolicyLevelType.AppDomain);
1506 if (policyLevel == null) {
1507 throw new ConfigurationErrorsException(SR.GetString(SR.Unable_to_get_policy_file, trustSection.Level));
1510 if (gacLocation != null) {
1511 // walk the code groups at the app domain level and look for one that grants
1512 // access to the GAC with an UrlMembershipCondition.
1513 CodeGroup rootGroup = policyLevel.RootCodeGroup;
1514 bool foundGacCondition = false;
1515 foreach (CodeGroup childGroup in rootGroup.Children) {
1516 if (childGroup.MembershipCondition is GacMembershipCondition) {
1517 foundGacCondition = true;
1518 // if we found the GAC token and also have the GacMembershipCondition
1519 // the policy file needs to be upgraded to just include the GacMembershipCondition
1520 Debug.Assert(!foundGacCondition);
1524 // add one as a child of the toplevel group after
1525 // some sanity checking to make sure it's an ASP.NET policy file
1526 // which always begins with a FirstMatchCodeGroup granting nothing
1527 // this might not upgrade some custom policy files
1528 if (!foundGacCondition) {
1529 if (rootGroup is FirstMatchCodeGroup) {
1530 FirstMatchCodeGroup firstMatch = (FirstMatchCodeGroup)rootGroup;
1531 if (firstMatch.MembershipCondition is AllMembershipCondition &&
1532 firstMatch.PermissionSetName == "Nothing") {
1533 PermissionSet fullTrust = new PermissionSet(PermissionState.Unrestricted);
1534 CodeGroup gacGroup = new UnionCodeGroup(new GacMembershipCondition(),
1535 new PolicyStatement(fullTrust));
1536 // now, walk the current groups and insert our new group immediately before the old Gac group
1537 // we'll need to use heuristics for this: it will be an UrlMembershipCondition group with full trust
1538 CodeGroup newRoot = new FirstMatchCodeGroup(rootGroup.MembershipCondition, rootGroup.PolicyStatement);
1539 foreach (CodeGroup childGroup in rootGroup.Children) {
1540 // is this the target old $Gac$ group?
1541 // insert our new GacMembershipCondition group ahead of it
1542 if ((childGroup is UnionCodeGroup) &&
1543 (childGroup.MembershipCondition is UrlMembershipCondition) &&
1544 childGroup.PolicyStatement.PermissionSet.IsUnrestricted()) {
1545 if (null != gacGroup) {
1546 newRoot.AddChild(gacGroup);
1550 // append this group to the root group
1551 // AddChild itself does a deep Copy to get any
1552 // child groups so we don't need one here
1553 newRoot.AddChild(childGroup);
1555 policyLevel.RootCodeGroup = newRoot;
1561 #pragma warning restore 618
1564 private sealed class ApplicationResumeStateContainer {
1565 private static readonly WaitCallback _tpCallback = ResumeCallback;
1567 private readonly HostingEnvironment _hostEnv;
1568 private readonly IntPtr _resumeState;
1570 internal ApplicationResumeStateContainer(HostingEnvironment hostEnv, IntPtr resumeState) {
1572 _resumeState = resumeState;
1575 // schedules resume for execution on a new thread
1576 // unsafe since we don't care about impersonation, identity, etc.
1577 internal void Resume() {
1578 ThreadPool.UnsafeQueueUserWorkItem(_tpCallback, this);
1581 private static void ResumeCallback(object state) {
1582 ApplicationResumeStateContainer container = (ApplicationResumeStateContainer)state;
1584 container._hostEnv.ResumeApplication(container._resumeState);
1586 catch (AppDomainUnloadedException) {
1587 // AD unloads aren't considered a failure, ----
1592 [SecurityPermission(SecurityAction.LinkDemand, Unrestricted = true)]
1593 private static class AspNetAppDomainManager {
1594 internal static Type GetAspNetAppDomainManagerType(bool overrideHostExecutionContextManager, bool overrideHostSecurityManager) {
1595 if (!overrideHostExecutionContextManager && !overrideHostSecurityManager) {
1596 // A custom AppDomainManager isn't necessary for this AppDomain.
1600 // A custom AppDomainManager is necessary for this AppDomain.
1601 // See comment on the generic type for further information.
1602 Type openGenericType = typeof(AspNetAppDomainManagerImpl<,>);
1603 Type closedGenericType = openGenericType.MakeGenericType(
1604 (overrideHostExecutionContextManager) ? typeof(AspNetHostExecutionContextManager) : typeof(object),
1605 (overrideHostSecurityManager) ? typeof(AspNetHostSecurityManager) : typeof(object)
1607 return closedGenericType;
1611 // This AppDomainManager may have been set because we need it for Task support, because this is a partial-trust
1612 // AppDomain, or both. Normally we would store this data in the AppDomain's ambient data store (AppDomain.SetData),
1613 // but the AppDomainManager instance is initialized in the new AppDomain before the original AppDomain has a chance to
1614 // call SetData, so in this AppDomain the call to GetData is useless. However, we can use the AppDomainManager type
1615 // itself to carry the necessary information in the form of a generic type parameter. If a custom
1616 // HostExecutionContextManager or HostSecurityManager is necessary, the generic type parameters can tell us that.
1617 // A generic type parameter of "object" means that this particular sub-manager isn't necessary.
1618 private sealed class AspNetAppDomainManagerImpl<THostExecutionContextManager, THostSecurityManager> : AppDomainManager
1619 where THostExecutionContextManager : class, new()
1620 where THostSecurityManager : class, new() {
1622 private readonly HostExecutionContextManager _hostExecutionContextManager = CreateHostExecutionContextManager();
1623 private readonly HostSecurityManager _hostSecurityManager = CreateHostSecurityManager();
1625 public override HostExecutionContextManager HostExecutionContextManager {
1627 return _hostExecutionContextManager ?? base.HostExecutionContextManager;
1631 public override HostSecurityManager HostSecurityManager {
1633 return _hostSecurityManager ?? base.HostSecurityManager;
1637 private static HostExecutionContextManager CreateHostExecutionContextManager() {
1638 object hostExecutionContextManager = new THostExecutionContextManager();
1639 Debug.Assert(hostExecutionContextManager is HostExecutionContextManager || hostExecutionContextManager.GetType() == typeof(object), "THostExecutionContextManager was an unexpected type!");
1640 return hostExecutionContextManager as HostExecutionContextManager;
1643 private static HostSecurityManager CreateHostSecurityManager() {
1644 object hostSecurityManager = new THostSecurityManager();
1645 Debug.Assert(hostSecurityManager is HostSecurityManager || hostSecurityManager.GetType() == typeof(object), "THostSecurityManager was an unexpected type!");
1646 return hostSecurityManager as HostSecurityManager;
1650 private sealed class AspNetHostSecurityManager : HostSecurityManager {
1651 private PermissionSet Nothing = new PermissionSet(PermissionState.None);
1652 private PermissionSet FullTrust = new PermissionSet(PermissionState.Unrestricted);
1653 private HostSecurityPolicyResolver hostSecurityPolicyResolver = null;
1655 public override HostSecurityManagerOptions Flags {
1657 return HostSecurityManagerOptions.HostResolvePolicy;
1661 [SecurityPermission(SecurityAction.Assert, Flags = SecurityPermissionFlag.SerializationFormatter)]
1662 public override PermissionSet ResolvePolicy(Evidence evidence) {
1663 if (base.ResolvePolicy(evidence).IsUnrestricted()) {
1667 if (!String.IsNullOrEmpty(HttpRuntime.HostSecurityPolicyResolverType) && hostSecurityPolicyResolver == null) {
1668 hostSecurityPolicyResolver = Activator.CreateInstance(
1669 Type.GetType(HttpRuntime.HostSecurityPolicyResolverType)) as HostSecurityPolicyResolver;
1672 if (hostSecurityPolicyResolver != null) {
1673 switch (hostSecurityPolicyResolver.ResolvePolicy(evidence)) {
1674 case HostSecurityPolicyResults.FullTrust:
1676 case HostSecurityPolicyResults.AppDomainTrust:
1677 return HttpRuntime.NamedPermissionSet;
1678 case HostSecurityPolicyResults.Nothing:
1680 case HostSecurityPolicyResults.DefaultPolicy:
1685 if (HttpRuntime.PolicyLevel == null || HttpRuntime.PolicyLevel.Resolve(evidence).PermissionSet.IsUnrestricted())
1687 else if (HttpRuntime.PolicyLevel.Resolve(evidence).PermissionSet.Equals(Nothing))
1690 return HttpRuntime.NamedPermissionSet;
1695 private static void PopulateDomainBindings(String domainId, String appId, String appName,
1696 String appPath, VirtualPath appVPath,
1697 AppDomainSetup setup, IDictionary dict) {
1698 // assembly loading settings
1700 // We put both the old and new bin dir names on the private bin path
1701 setup.PrivateBinPathProbe = "*"; // disable loading from app base
1702 setup.ShadowCopyFiles = "true";
1703 setup.ApplicationBase = appPath;
1704 setup.ApplicationName = appName;
1705 setup.ConfigurationFile = HttpConfigurationSystem.WebConfigFileName;
1707 // Disallow code download, since it's unreliable in services (ASURT 123836/127606)
1708 setup.DisallowCodeDownload = true;
1710 // internal settings
1711 dict.Add(".appDomain", "*");
1712 dict.Add(".appId", appId);
1713 dict.Add(".appPath", appPath);
1714 dict.Add(".appVPath", appVPath.VirtualPathString);
1715 dict.Add(".domainId", domainId);
1718 private static Evidence GetDefaultDomainIdentity() {
1719 Evidence evidence = AppDomain.CurrentDomain.Evidence; // CurrentDomain.Evidence returns a clone so we can modify it if we need
1720 bool hasZone = evidence.GetHostEvidence<Zone>() != null;
1721 bool hasUrl = evidence.GetHostEvidence<Url>() != null;
1724 evidence.AddHostEvidence(new Zone(SecurityZone.MyComputer));
1727 evidence.AddHostEvidence(new Url("ms-internal-microsoft-asp-net-webhost-20"));
1732 private static int s_domainCount = 0;
1733 private static Object s_domainCountLock = new Object();
1735 private static String ConstructAppDomainId(String id) {
1736 int domainCount = 0;
1737 lock (s_domainCountLock) {
1738 domainCount = ++s_domainCount;
1740 return id + "-" + domainCount.ToString(NumberFormatInfo.InvariantInfo) + "-" + DateTime.UtcNow.ToFileTime().ToString();
1743 internal LockableAppDomainContext GetLockableAppDomainContext (string appId) {
1745 LockableAppDomainContext ac;
1746 if (!_appDomains.TryGetValue(appId, out ac)) {
1747 ac = new LockableAppDomainContext();
1748 _appDomains.Add (appId, ac);
1755 // take a copy of _appDomains collection so that it can be used without locking on ApplicationManager
1756 private Dictionary<string, LockableAppDomainContext> CloneAppDomainsCollection() {
1758 return new Dictionary<string, LockableAppDomainContext>(_appDomains, StringComparer.OrdinalIgnoreCase);
1762 private static Configuration GetAppConfigCommon(IConfigMapPath configMapPath, string siteID, string appSegment) {
1763 WebConfigurationFileMap fileMap = new WebConfigurationFileMap();
1765 string fileName = null;
1766 string subDir = "/";
1768 configMapPath.GetPathConfigFilename(siteID, subDir, out dir, out fileName);
1770 fileMap.VirtualDirectories.Add(subDir, new VirtualDirectoryMapping(Path.GetFullPath(dir), true));
1772 // add subdir mappings
1773 string[] subDirs = appSegment.Split(new char[] { '/' }, StringSplitOptions.RemoveEmptyEntries);
1774 foreach (string s in subDirs) {
1775 subDir = subDir + s;
1776 configMapPath.GetPathConfigFilename(siteID, subDir, out dir, out fileName);
1778 fileMap.VirtualDirectories.Add(subDir, new VirtualDirectoryMapping(Path.GetFullPath(dir), true));
1780 subDir = subDir + "/";
1782 // open mapped web config for application
1783 return WebConfigurationManager.OpenMappedWebConfiguration(fileMap, appSegment, siteID);
1786 [SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands", Justification = "Only ever called by the full-trust parent AppDomain.")]
1787 private static Configuration GetAppConfigGeneric(IApplicationHost appHost, string siteID, string appSegment, VirtualPath virtualPath, string physicalPath) {
1788 WebConfigurationFileMap fileMap = new WebConfigurationFileMap();
1789 IConfigMapPathFactory configMapPathFactory2 = appHost.GetConfigMapPathFactory();
1790 IConfigMapPath configMapPath = configMapPathFactory2.Create(virtualPath.VirtualPathString, physicalPath);
1791 return GetAppConfigCommon(configMapPath, siteID, appSegment);
1794 private static Configuration GetAppConfigIISExpress(string siteID, string appSegment, string iisExpressVersion) {
1795 ExpressServerConfig serverConfig = (ExpressServerConfig)ServerConfig.GetDefaultDomainInstance(iisExpressVersion);
1796 return GetAppConfigCommon(serverConfig, siteID, appSegment);
1799 private sealed class AppDomainSwitches {
1800 public bool UseLegacyCas;
1801 public bool UseRandomizedStringHashAlgorithm;
1803 public void Apply(AppDomainSetup setup) {
1804 List<string> switches = new List<string>();
1807 // Enables the AppDomain to use the legacy CAS model for compatibility <trust/legacyCasModel>
1808 switches.Add("NetFx40_LegacySecurityPolicy");
1811 if (UseRandomizedStringHashAlgorithm) {
1812 switches.Add("UseRandomizedStringHashAlgorithm");
1815 if (switches.Count > 0) {
1816 setup.SetCompatibilitySwitches(switches);
1821 // This class holds information about the environment that is hosting ASP.NET. The particular design of this class
1822 // is that the information is computed once and stored, and the methods which compute the information are private.
1823 // This prevents accidental misuse of this type via querying the environment after user code has had a chance to
1824 // run, which could potentially affect the environment itself.
1825 private static class EnvironmentInfo {
1826 public static readonly bool IsStringHashCodeRandomizationDetected = GetIsStringHashCodeRandomizationDetected();
1827 public static readonly bool WasLaunchedFromDevelopmentEnvironment = GetWasLaunchedFromDevelopmentEnvironmentValue();
1829 private static bool GetIsStringHashCodeRandomizationDetected() {
1830 // known test vector
1831 return (StringComparer.InvariantCultureIgnoreCase.GetHashCode("The quick brown fox jumps over the lazy dog.") != 0x703e662e);
1834 // Visual Studio / WebMatrix will set DEV_ENVIRONMENT=1 when launching an ASP.NET host in a development environment.
1835 private static bool GetWasLaunchedFromDevelopmentEnvironmentValue() {
1837 string envVar = Environment.GetEnvironmentVariable("DEV_ENVIRONMENT", EnvironmentVariableTarget.Process);
1838 return String.Equals(envVar, "1", StringComparison.Ordinal);
1841 // We don't care if we can't read the environment variable; just treat it as not present.