File: System\ServiceModel\Activation\AspNetEnvironment.cs
Project: ndp\cdf\src\WCF\ServiceModel\System.ServiceModel.csproj (System.ServiceModel)
//----------------------------------------------------------------------------
// 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<Uri> 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<IServiceBehavior> serviceBehaviors, BindingParameterCollection bindingParameters)
        {
            bindingParameters.Add(new ServiceMetadataExtension.MetadataBindingParameter());
        }
 
        internal virtual bool IsMetadataListener(BindingParameterCollection bindingParameters)
        {
            return bindingParameters.Find<ServiceMetadataExtension.MetadataBindingParameter>() != 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;
        }
    }
}