//---------------------------------------------------------------------------- // Copyright (c) Microsoft Corporation. All rights reserved. //---------------------------------------------------------------------------- namespace System.ServiceModel.Activation { using System.Collections.Generic; using System.Configuration; using System.Net; using System.Runtime; using System.Security; using System.Security.Authentication.ExtendedProtection; using System.Security.Permissions; using System.ServiceModel.Channels; using System.ServiceModel.Description; using System.ServiceModel.Dispatcher; class AspNetEnvironment { static readonly object thisLock = new object(); // Double-checked locking pattern requires volatile for read/write synchronization static volatile AspNetEnvironment current; static bool isEnabled; static bool? isApplicationDomainHosted; protected AspNetEnvironment() { } public static AspNetEnvironment Current { get { if (current == null) { lock (thisLock) { if (current == null) { current = new AspNetEnvironment(); } } } return current; } // AspNetEnvironment.Current is set by System.ServiceModel.Activation when it is brought into memory through // the ASP.Net hosting environment. It is the only "real" implementer of this class. protected set { Fx.Assert(!isEnabled, "should only be explicitly set once"); Fx.Assert(value != null, "should only be set to a valid environment"); current = value; isEnabled = true; } } public static bool Enabled { get { return isEnabled; } } public bool RequiresImpersonation { get { return AspNetCompatibilityEnabled; } } public virtual bool AspNetCompatibilityEnabled { get { // subclass will check AspNetCompatibility mode return false; } } public virtual string ConfigurationPath { get { return AppDomain.CurrentDomain.SetupInformation.ConfigurationFile; } } // these ideally would be replaced with public APIs public virtual bool IsConfigurationBased { get { // subclass will check ServiceActivationElement presence return false; } } public virtual string CurrentVirtualPath { get { // subclass will use calculation from HostingManager.CreateService return null; } } public virtual string XamlFileBaseLocation { get { // subclass will use calculation from HostingManager.CreateService return null; } } public virtual bool UsingIntegratedPipeline { get { return false; } } public virtual string WebSocketVersion { get { return null; } } // Indicates if the WebSocket module is loaded. When IIS hosted, it throws an exception when called before we determined if the module is loaded or not. public bool IsWebSocketModuleLoaded { get { return this.WebSocketVersion != null; } } public virtual void AddHostingBehavior(ServiceHostBase serviceHost, ServiceDescription description) { // subclass will add HostedBindingBehavior } public virtual bool IsWindowsAuthenticationConfigured() { // subclass will check Asp.Net authentication mode return false; } public virtual List GetBaseAddresses(Uri addressTemplate) { // subclass will provide multiple base address support return null; } // check if ((System.Web.Configuration.WebContext)configHostingContext).ApplicationLevel == WebApplicationLevel.AboveApplication public virtual bool IsWebConfigAboveApplication(object configHostingContext) { // there are currently only two known implementations of HostingContext, so we are // pretty much guaranteed to be hosted in ASP.Net here. However, it may not be // through our BuildProvider, so we still need to do some work in the base class. // The HostedAspNetEnvironment subclass can perform more efficiently using reflection return SystemWebHelper.IsWebConfigAboveApplication(configHostingContext); } public virtual void EnsureCompatibilityRequirements(ServiceDescription description) { // subclass will ensure AspNetCompatibilityRequirementsAttribute is in the behaviors collection } public virtual bool TryGetFullVirtualPath(out string virtualPath) { // subclass will use the virtual path from the compiled string virtualPath = null; return false; } public virtual string GetAnnotationFromHost(ServiceHostBase host) { // subclass will return "Website name\Application Virtual Path|\relative service virtual path|serviceName" return string.Empty; } public virtual void EnsureAllReferencedAssemblyLoaded() { } public virtual BaseUriWithWildcard GetBaseUri(string transportScheme, Uri listenUri) { return null; } public virtual void ValidateHttpSettings(string virtualPath, bool isMetadataListener, bool usingDefaultSpnList, ref AuthenticationSchemes supportedSchemes, ref ExtendedProtectionPolicy extendedProtectionPolicy, ref string realm) { } // returns whether or not the caller should use the hosted client certificate mapping public virtual bool ValidateHttpsSettings(string virtualPath, ref bool requireClientCertificate) { return false; } public virtual void ProcessNotMatchedEndpointAddress(Uri uri, string endpointName) { // subclass will throw as appropriate for compat mode } public virtual void ValidateCompatibilityRequirements(AspNetCompatibilityRequirementsMode compatibilityMode) { // validate that hosting settings are compatible with the requested requirements if (compatibilityMode == AspNetCompatibilityRequirementsMode.Required) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.Hosting_CompatibilityServiceNotHosted))); } } public virtual IAspNetMessageProperty GetHostingProperty(Message message) { // subclass will gen up a HostingMessageProperty return null; } public virtual IAspNetMessageProperty GetHostingProperty(Message message, bool removeFromMessage) { // subclass will return the hosting property from the message // and remove it from the message's properties. return null; } public virtual void PrepareMessageForDispatch(Message message) { // subclass will wrap ReceiveContext for Busy Count } public virtual void ApplyHostedContext(TransportChannelListener listener, BindingContext context) { // subclass will push hosted information to the transport listeners } internal virtual void AddMetadataBindingParameters(Uri listenUri, KeyedByTypeCollection serviceBehaviors, BindingParameterCollection bindingParameters) { bindingParameters.Add(new ServiceMetadataExtension.MetadataBindingParameter()); } internal virtual bool IsMetadataListener(BindingParameterCollection bindingParameters) { return bindingParameters.Find() != null; } public virtual void IncrementBusyCount() { // subclass will increment HostingEnvironment.BusyCount } public virtual void DecrementBusyCount() { // subclass will decrement HostingEnvironment.BusyCount } public virtual bool TraceIncrementBusyCountIsEnabled() { // subclass will return true if tracing for IncrementBusyCount is enabled. //kept as a separate check from TraceIncrementBusyCount to avoid creating source string if Tracing is not enabled. return false; } public virtual bool TraceDecrementBusyCountIsEnabled() { // subclass will return true if tracing for DecrementBusyCount is enabled. //kept as a separate check from TraceDecrementBusyCount to avoid creating source string if Tracing is not enabled. return false; } public virtual void TraceIncrementBusyCount(string data) { //callers are expected to check if TraceIncrementBusyCountIsEnabled() is true //before calling this method // subclass will emit trace for IncrementBusyCount // data is emitted in the Trace as the source of the call to Increment. } public virtual void TraceDecrementBusyCount(string data) { //callers are expected to check if TraceDecrementBusyCountIsEnabled() is true //before calling this method // subclass will emit trace for DecrementBusyCount // data is emitted in the Trace as the source of the call to Decrement. } public virtual object GetConfigurationSection(string sectionPath) { // subclass will interact with web.config system return ConfigurationManager.GetSection(sectionPath); } // Be sure to update UnsafeGetSection if you modify this method [Fx.Tag.SecurityNote(Critical = "Uses SecurityCritical method UnsafeGetSectionFromConfigurationManager which elevates.")] [SecurityCritical] public virtual object UnsafeGetConfigurationSection(string sectionPath) { // subclass will interact with web.config system return UnsafeGetSectionFromConfigurationManager(sectionPath); } public virtual AuthenticationSchemes GetAuthenticationSchemes(Uri baseAddress) { // subclass will grab settings from the metabase return AuthenticationSchemes.None; } public virtual bool IsSimpleApplicationHost { get { // subclass will grab settings from the ServiceHostingEnvironment return false; } } [Fx.Tag.SecurityNote(Critical = "Asserts ConfigurationPermission in order to fetch config from ConfigurationManager," + "caller must guard return value.")] [SecurityCritical] [ConfigurationPermission(SecurityAction.Assert, Unrestricted = true)] static object UnsafeGetSectionFromConfigurationManager(string sectionPath) { return ConfigurationManager.GetSection(sectionPath); } public virtual bool IsWithinApp(string absoluteVirtualPath) { return true; } internal static bool IsApplicationDomainHosted() { if (!AspNetEnvironment.isApplicationDomainHosted.HasValue) { lock (AspNetEnvironment.thisLock) { if (!AspNetEnvironment.isApplicationDomainHosted.HasValue) { bool isApplicationDomainHosted = false; if (AspNetEnvironment.Enabled) { isApplicationDomainHosted = AspNetEnvironment.IsSystemWebAssemblyLoaded(); } AspNetEnvironment.isApplicationDomainHosted = isApplicationDomainHosted; } } } return AspNetEnvironment.isApplicationDomainHosted.Value; } private static bool IsSystemWebAssemblyLoaded() { const string systemWebName = "System.Web,"; foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies()) { if (assembly.FullName.StartsWith(systemWebName, StringComparison.OrdinalIgnoreCase)) { return true; } } return false; } } }