Code:
/ 4.0 / 4.0 / untmp / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / cdf / src / WCF / System.ServiceModel.Activation / System / ServiceModel / ServiceHostingEnvironment.cs / 1438166 / ServiceHostingEnvironment.cs
//---------------------------------------------------------------------------- // Copyright (c) Microsoft Corporation. All rights reserved. //--------------------------------------------------------------------------- namespace System.ServiceModel { using System.Collections; using System.Collections.Generic; using System.Configuration; using System.Diagnostics; using System.Globalization; using System.Reflection; using System.Runtime; using System.Runtime.Diagnostics; using System.Runtime.CompilerServices; using System.Security; using System.Security.Permissions; using System.ServiceModel.Activation; using System.ServiceModel.Channels; using System.ServiceModel.Configuration; using System.ServiceModel.Activation.Diagnostics; using System.ServiceModel.Description; using System.Threading; using System.Web; using System.Web.Compilation; using System.Web.Configuration; using System.Web.Hosting; using System.Web.Routing; using System.Xaml.Hosting.Configuration; using System.Text; using SR2 = System.ServiceModel.Activation.SR; using TD2 = System.ServiceModel.Diagnostics.Application.TD; [TypeForwardedFrom("System.ServiceModel, Version=3.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")] public static class ServiceHostingEnvironment { static object syncRoot = new object(); static HostingManager hostingManager; static bool isHosted; static bool isSimpleApplicationHost; static Int64 requestCount; static bool didAssemblyCheck; static bool isApplicationDomainHosted; static bool canGetHtmlErrorMessage = true; static string siteName; static string applicationVirtualPath; static string serviceActivationElementPath; internal const string VerbPost = "POST"; internal const string ISAPIApplicationIdPrefix = "/LM/W3SVC/"; internal const string RelativeVirtualPathPrefix = "~"; internal const string ServiceParserDelimiter = "|"; internal const string RootVirtualPath = "~/"; internal const string PathSeparatorString = "/"; const char FileExtensionSeparator = '.'; const char UriSchemeSeparator = ':'; const char PathSeparator = '/'; const string SystemWebComma = "System.Web,"; [Fx.Tag.SecurityNote(Critical = "Calls into an unsafe UnsafeLogEvent method.", Safe = "Event identities cannot be spoofed as they are constants determined inside the method.")] [SecuritySafeCritical] static void OnUnhandledException(object sender, UnhandledExceptionEventArgs e) { if (DiagnosticUtility.ShouldTraceError) { Exception exception = e.ExceptionObject as Exception; DiagnosticUtility.UnsafeEventLog.UnsafeLogEvent(TraceEventType.Error, System.ServiceModel.Diagnostics.EventLogCategory.WebHost, System.ServiceModel.Diagnostics.EventLogEventId.WebHostUnhandledException, true, TraceUtility.CreateSourceString(sender), exception == null ? string.Empty : exception.ToString()); } } [Fx.Tag.SecurityNote(Miscellaneous = "RequiresReview - called by ProcessRequest outside of the restricted SecurityContext.")] public static bool AspNetCompatibilityEnabled { [Fx.Tag.SecurityNote(Miscellaneous = "RequiresReview - can be called outside of user context.")] get { if (!IsHosted) { return false; } return IsAspNetCompatibilityEnabled(); } } [Fx.Tag.SecurityNote(Miscellaneous = "RequiresReview - called by ProcessRequest outside of the restricted SecurityContext.")] public static bool MultipleSiteBindingsEnabled { [Fx.Tag.SecurityNote(Miscellaneous = "RequiresReview - can be called outside of user context.")] get { if (!IsHosted) return false; return IsMultipleSiteBindingsEnabledEnabled(); } } [Fx.Tag.SecurityNote(Miscellaneous = "RequiresReview - called by ServiceHostFactory.CreateServiceHost.")] internal static Uri[] PrefixFilters { [Fx.Tag.SecurityNote(Miscellaneous = "RequiresReview")] get { if (!IsHosted) { return null; } return GetBaseAddressPrefixFilters(); } } [Fx.Tag.SecurityNote(Miscellaneous = "RequiresReview - can be called outside of user context.")] [MethodImpl(MethodImplOptions.NoInlining)] static bool IsAspNetCompatibilityEnabled() { return hostingManager.AspNetCompatibilityEnabled; } [Fx.Tag.SecurityNote(Miscellaneous = "RequiresReview - can be called outside of user context.")] [MethodImpl(MethodImplOptions.NoInlining)] static bool IsMultipleSiteBindingsEnabledEnabled() { return hostingManager.MultipleSiteBindingsEnabled; } [Fx.Tag.SecurityNote(Miscellaneous = "RequiresReview - can be called outside of user context.")] [MethodImpl(MethodImplOptions.NoInlining)] static Uri[] GetBaseAddressPrefixFilters() { return hostingManager.BaseAddressPrefixFilters; } public static void EnsureServiceAvailable(string virtualPath) { if (string.IsNullOrEmpty(virtualPath)) { throw FxTrace.Exception.ArgumentNull("virtualPath"); } if (virtualPath.IndexOf(UriSchemeSeparator) > 0) { throw FxTrace.Exception.Argument("virtualPath", SR2.Hosting_AddressIsAbsoluteUri(virtualPath)); } EnsureInitialized(); virtualPath = NormalizeVirtualPath(virtualPath); EnsureServiceAvailableFast(virtualPath); } internal static void EnsureServiceAvailableFast(string relativeVirtualPath) { try { hostingManager.EnsureServiceAvailable(relativeVirtualPath); } catch (ServiceActivationException exception) { LogServiceActivationException(exception); throw; } } [Fx.Tag.SecurityNote(Critical = "Calls into an unsafe UnsafeLogEvent method.", Safe = "Event identities cannot be spoofed as they are constants determined inside the method.")] [SecuritySafeCritical] private static void LogServiceActivationException(ServiceActivationException exception) { if (exception.InnerException is HttpException) { string messageAsString = SafeTryGetHtmlErrorMessage((HttpException)exception.InnerException); if (string.IsNullOrEmpty(messageAsString)) { messageAsString = exception.Message; } DiagnosticUtility.UnsafeEventLog.UnsafeLogEvent(TraceEventType.Error, System.ServiceModel.Diagnostics.EventLogCategory.WebHost, System.ServiceModel.Diagnostics.EventLogEventId.WebHostHttpError, true, TraceUtility.CreateSourceString(hostingManager), messageAsString, exception.ToString()); } else { DiagnosticUtility.UnsafeEventLog.UnsafeLogEvent(TraceEventType.Error, System.ServiceModel.Diagnostics.EventLogCategory.WebHost, System.ServiceModel.Diagnostics.EventLogEventId.WebHostFailedToProcessRequest, true, TraceUtility.CreateSourceString(hostingManager), exception.ToString()); } if (TD2.ServiceExceptionIsEnabled()) { TD2.ServiceException(exception.ToString(), typeof(ServiceActivationException).FullName); } } static string SafeTryGetHtmlErrorMessage(HttpException exception) { if (exception != null && canGetHtmlErrorMessage) { try { return exception.GetHtmlErrorMessage(); } catch (SecurityException e) { canGetHtmlErrorMessage = false; // not re-throwing on purpose if (DiagnosticUtility.ShouldTraceWarning) { DiagnosticUtility.ExceptionUtility.TraceHandledException(e, TraceEventType.Warning); } } } return null; } [Fx.Tag.SecurityNote(Miscellaneous = "RequiresReview - can be called outside of user context.")] internal static void IncrementRequestCount() { Interlocked.Increment(ref requestCount); if (TD.WebHostRequestStartIsEnabled()) { TD.WebHostRequestStart(); } } internal static void DecrementRequestCount() { Interlocked.Decrement(ref requestCount); Fx.Assert(requestCount >= 0, "Request count should always be non-nagative."); if (requestCount == 0) { if (hostingManager != null) { hostingManager.NotifyAllRequestDone(); } } if (TD.WebHostRequestStopIsEnabled()) { TD.WebHostRequestStop(); } } internal static string CurrentVirtualPath { get { Fx.Assert(IsHosted, "CurrentVirtualPath should not be called from non web-hosted environment."); return HostingManager.CurrentVirtualPath; } } internal static string ServiceActivationElementPath { get { if (ServiceHostingEnvironment.serviceActivationElementPath == null) { ServiceHostingEnvironment.serviceActivationElementPath = string.Format(CultureInfo.CurrentCulture, "{0}/{1}", ConfigurationStrings.ServiceHostingEnvironmentSectionPath, ConfigurationStrings.ServiceActivations); } return ServiceHostingEnvironment.serviceActivationElementPath; } } internal static string SiteName { get { if (ServiceHostingEnvironment.siteName == null) { ServiceHostingEnvironment.siteName = HostingEnvironment.SiteName; } return ServiceHostingEnvironment.siteName; } } internal static string ApplicationVirtualPath { get { if (ServiceHostingEnvironment.applicationVirtualPath == null) { ServiceHostingEnvironment.applicationVirtualPath = HostingEnvironment.ApplicationVirtualPath; } return ServiceHostingEnvironment.applicationVirtualPath; } } internal static string FullVirtualPath { get { Fx.Assert(IsHosted, "FullVirtualPath should not be called from non web-hosted environment."); return HostingManager.FullVirtualPath; } } internal static string XamlFileBaseLocation { get { Fx.Assert(IsHosted, "XamlFileBaseLocation should not be called from non web-hosted environment."); return HostingManager.XamlFileBaseLocation; } } internal static bool IsConfigurationBased { get { Fx.Assert(IsHosted, "IsConfigurationBased should not be called from non web-hosted environment."); return HostingManager.IsConfigurationBased; } } [Fx.Tag.SecurityNote(Miscellaneous = "RequiresReview - called by ProcessRequest outside of the restricted SecurityContext.")] internal static ServiceType GetServiceType(string extension) { Fx.Assert(IsHosted, "GetServiceType should not be called from non web-hosted environment."); return hostingManager.GetServiceType(extension); } internal static bool EnsureWorkflowService(string path) { Fx.Assert(IsHosted, "EnsureWorkflowService should not be called from non web-hosted environment."); PathInfo pathInfo = PathCache.EnsurePathInfo(path); return pathInfo.IsWorkflowService(); } internal static bool IsRecycling { get { Fx.Assert(IsHosted, "IsRecycling should not be called from non web-hosted environment."); return hostingManager.IsRecycling; } } static object ThisLock { get { return syncRoot; } } [Fx.Tag.SecurityNote(Miscellaneous = "RequiresReview - called by ProcessRequest outside of the restricted SecurityContext.")] internal static bool IsConfigurationBasedService(HttpApplication application) { Fx.Assert(IsHosted, "IsConfigurationBased should not be called from non web-hosted environment."); string dummyString; return IsConfigurationBasedService(application, out dummyString); } [Fx.Tag.SecurityNote(Miscellaneous = "RequiresReview - called by MsmqHostedTransportManager outside of the restricted SecurityContext.")] internal static bool IsConfigurationBasedService(string virtualPath) { Fx.Assert(IsHosted, "IsConfigurationBased should not be called from non web-hosted environment."); return hostingManager.IsConfigurationBasedServiceVirtualPath(virtualPath); } [Fx.Tag.SecurityNote(Miscellaneous = "RequiresReview - called by ProcessRequest outside of the restricted SecurityContext.")] internal static bool IsConfigurationBasedService(HttpApplication application, out string matchedVirtualPath) { Fx.Assert(IsHosted, "IsConfigurationBased should not be called from non web-hosted environment."); bool isCBAService = false; matchedVirtualPath = null; string virtualPath = application.Request.AppRelativeCurrentExecutionFilePath; if (!string.IsNullOrEmpty(virtualPath) && hostingManager.IsConfigurationBasedServiceVirtualPath(virtualPath)) { matchedVirtualPath = virtualPath; isCBAService = true; } return isCBAService; } [Fx.Tag.SecurityNote(Miscellaneous = "RequiresReview - called by ProcessRequest outside of the restricted SecurityContext.")] internal static void SafeEnsureInitialized() { if (hostingManager == null) { AspNetPartialTrustHelpers.PartialTrustInvoke(new ContextCallback(OnEnsureInitialized), null); } } [Fx.Tag.SecurityNote(Miscellaneous = "RequiresReview - can be called outside of user context.")] internal static void EnsureAllReferencedAssemblyLoaded() { BuildManager.GetReferencedAssemblies(); } static void OnEnsureInitialized(object state) { EnsureInitialized(); } internal static void EnsureInitialized() { System.ServiceModel.Diagnostics.TraceUtility.SetEtwProviderId(); if (hostingManager != null) { return; } FxTrace.Trace.SetAnnotation(() => System.ServiceModel.Diagnostics.TraceUtility.GetAnnotation(OperationContext.Current)); lock (ThisLock) { if (hostingManager != null) { return; } if (!HostingEnvironmentWrapper.IsHosted) { throw FxTrace.Exception.AsError(new InvalidOperationException(SR.GetString(SR.Hosting_ProcessNotExecutingUnderHostedContext, "ServiceHostingEnvironment.EnsureServiceAvailable"))); } HostingManager tempHostingManager = new HostingManager(); // register the following code when we use the service environment class // the first time HookADUnhandledExceptionEvent(); Thread.MemoryBarrier(); isSimpleApplicationHost = GetIsSimpleApplicationHost(); HostedAspNetEnvironment.Enable(); hostingManager = tempHostingManager; isHosted = true; } } [Fx.Tag.SecurityNote(Critical = "Satisfies a LinkDemand for SecurityPermission(ControlAppDomain) on HookADUnhandledExceptionEvent.", Safe = "No control flow in for handler.")] [SecuritySafeCritical] static void HookADUnhandledExceptionEvent() { AppDomain.CurrentDomain.UnhandledException += OnUnhandledException; } [Fx.Tag.SecurityNote(Critical = "Uses SecurityCritical property UnsafeApplicationID to get application id with an elevation.", Safe = "Processes result into a simple bool which is not protected.")] [SecuritySafeCritical] static bool GetIsSimpleApplicationHost() { // ASPNET won't provide API to check Cassini. But it's safe and performant to check only // the ApplicationID prefix (MessageBus Bug 24832). return (string.Compare(ISAPIApplicationIdPrefix, 0, HostingEnvironmentWrapper.UnsafeApplicationID, 0, ISAPIApplicationIdPrefix.Length, StringComparison.OrdinalIgnoreCase) != 0); } // customer input can be "/appname//filename" or "~/ /filename, we will normalize them to application relative one // i.e., "~/ /filename internal static string NormalizeVirtualPath(string virtualPath) { string processedVirtualPath = null; try { // Convert the virtual path to relative if not already is. processedVirtualPath = VirtualPathUtility.ToAppRelative(virtualPath, HostingEnvironmentWrapper.ApplicationVirtualPath); } catch (HttpException exception) { // We want to throw an ArgumentException. throw FxTrace.Exception.AsError(new ArgumentException(exception.Message, "virtualPath", exception)); } if (string.IsNullOrEmpty(processedVirtualPath) || !processedVirtualPath.StartsWith(RelativeVirtualPathPrefix, StringComparison.Ordinal)) { throw FxTrace.Exception.Argument("virtualPath", SR2.Hosting_AddressPointsOutsideTheVirtualDirectory(virtualPath, HostingEnvironmentWrapper.ApplicationVirtualPath)); } // Find the position to start. int pos = processedVirtualPath.IndexOf(FileExtensionSeparator); while (pos > 0) { // Search inside the processedVirtualPath to find the extension. pos = processedVirtualPath.IndexOf(PathSeparator, pos + 1); string subVirtualPath = (pos == -1) ? processedVirtualPath : processedVirtualPath.Substring(0, pos); string extension = VirtualPathUtility.GetExtension(subVirtualPath); if ((!string.IsNullOrEmpty(extension)) && ServiceHostingEnvironment.GetServiceType(extension)!=ServiceType.Unknown) { // Remove the pathinfo. return subVirtualPath; } } throw FxTrace.Exception.AsError(new EndpointNotFoundException(SR2.Hosting_ServiceNotExist(virtualPath))); } internal static bool IsHosted { [Fx.Tag.SecurityNote(Miscellaneous = "RequiresReview - can be called outside of user context.")] get { return isHosted; } } internal static bool IsSimpleApplicationHost { get { Fx.Assert(IsHosted, "IsSimpleApplicationHost should not be called from non web-hosted environment."); return isSimpleApplicationHost; } } internal static bool ApplicationDomainHosted { get { if (didAssemblyCheck) { return isApplicationDomainHosted; } Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies(); for (int i = 0; i < assemblies.Length; i++) { if (string.Compare(assemblies[i].FullName, 0, SystemWebComma, 0, SystemWebComma.Length, StringComparison.OrdinalIgnoreCase) == 0) { isApplicationDomainHosted = IsApplicationDomainHosted(); break; } } didAssemblyCheck = true; return isApplicationDomainHosted; } } [Fx.Tag.SecurityNote(Critical = "Assert a demand for AspNetHostingPermission.", Safe = "Only queries if we are hosted - no actual action is initiated, no critical information is leaking.")] [MethodImpl(MethodImplOptions.NoInlining)] [SecuritySafeCritical] [AspNetHostingPermission(SecurityAction.Assert, Level = AspNetHostingPermissionLevel.Minimal)] static bool IsApplicationDomainHosted() { return HostingEnvironment.IsHosted; } internal enum ServiceType { Unknown = 0, WCF, Workflow } class HostingManager : IRegisteredObject { readonly Hashtable directory; readonly ExtensionHelper extensions; bool aspNetCompatibilityEnabled; bool multipleSiteBindingsEnabled; bool isUnregistered; bool isRecycling; bool isStopStarted; static bool canDebugPrint = true; static object syncRoot = new object(); Uri[] baseAddressPrefixFilters; Hashtable serviceActivations; //used to track if HostingEnvironment.RegisterObject has been called. bool isRegistered; // One instance per appdomain, don't need to be disposed. ManualResetEvent allRequestDoneInStop = new ManualResetEvent(false); [Fx.Tag.SecurityNote(Critical = "Admin-provided value that allows for machine resource allocation.")] [SecurityCritical] int minFreeMemoryPercentageToActivateService; [ThreadStatic] static string currentVirtualPath; [ThreadStatic] static string fullVirtualPath; [ThreadStatic] static string xamlFileBaseLocation; [ThreadStatic] static bool isConfigurationBased; [ThreadStatic] static bool isAspNetRoutedRequest; internal HostingManager() { this.directory = new Hashtable(16, StringComparer.OrdinalIgnoreCase); this.extensions = new ExtensionHelper(); LoadConfigParameters(); } [Fx.Tag.SecurityNote(Critical = "Uses SecurityCritical method UnsafeGetSection to get config with an elevation. Sets minFreeMemoryPercentageToActivateService", Safe = "Does not leak config objects.")] [SecuritySafeCritical] void LoadConfigParameters() { ServiceHostingEnvironmentSection section = ServiceHostingEnvironmentSection.UnsafeGetSection(); this.aspNetCompatibilityEnabled = section.AspNetCompatibilityEnabled; this.multipleSiteBindingsEnabled = section.MultipleSiteBindingsEnabled; this.minFreeMemoryPercentageToActivateService = section.MinFreeMemoryPercentageToActivateService; List prefixFilters = new List (); foreach (BaseAddressPrefixFilterElement element in section.BaseAddressPrefixFilters) { prefixFilters.Add(element.Prefix); } this.baseAddressPrefixFilters = prefixFilters.ToArray(); this.serviceActivations = new Hashtable(StringComparer.CurrentCultureIgnoreCase); foreach (ServiceActivationElement element in section.ServiceActivations) { if (string.IsNullOrEmpty(element.Factory) && string.IsNullOrEmpty(element.Service)) { throw FxTrace.Exception.AsError(new ConfigurationErrorsException(SR2.Hosting_NoServiceAndFactorySpecifiedForFilelessService(ConfigurationStrings.Factory, ConfigurationStrings.Service, element.RelativeAddress, ServiceActivationElementPath))); } string normalizedRelativeAddress = NormalizedRelativeAddress(element.RelativeAddress); string value = string.Format(CultureInfo.CurrentCulture, "{0}|{1}|{2}", normalizedRelativeAddress, element.Factory, element.Service); try { this.serviceActivations.Add(normalizedRelativeAddress, value); if (TD.CBAEntryReadIsEnabled()) { TD.CBAEntryRead(element.RelativeAddress, normalizedRelativeAddress); } } catch (ArgumentException) { throw FxTrace.Exception.AsError(new ConfigurationErrorsException(SR2.Hosting_RelativeAddressHasBeenAdded(element.RelativeAddress, ServiceActivationElementPath))); } } } [Fx.Tag.SecurityNote(Miscellaneous = "RequiresReview - can be called outside of user context.")] internal ServiceType GetServiceType(string extension) { return extensions.GetServiceType(extension); } internal bool AspNetCompatibilityEnabled { [Fx.Tag.SecurityNote(Miscellaneous = "RequiresReview - can be called outside of user context.")] get { return this.aspNetCompatibilityEnabled; } } internal bool MultipleSiteBindingsEnabled { [Fx.Tag.SecurityNote(Miscellaneous = "RequiresReview - can be called outside of user context.")] get { return this.multipleSiteBindingsEnabled; } } internal Uri[] BaseAddressPrefixFilters { [Fx.Tag.SecurityNote(Miscellaneous = "RequiresReview - can be called outside of user context.")] get { return this.baseAddressPrefixFilters; } } internal static string CurrentVirtualPath { get { return currentVirtualPath; } } internal static string FullVirtualPath { get { return fullVirtualPath; } } internal static string XamlFileBaseLocation { get { return xamlFileBaseLocation; } } internal static bool IsConfigurationBased { get { return isConfigurationBased; } } internal static object ThisLock { get { return syncRoot; } } internal bool IsRecycling { get { return isRecycling; } } internal string NormalizedRelativeAddress(string relativeAddress) { // since it is almost impossible for us to validate the format of a relativeAddress // we just take what users' inputs but we need to normalize them with a formal format // so that we can index them in a table. // we will convert "[folder/]filename.extension" to "~/[folder/]filename.extension" string originalRelativeAddress = relativeAddress; try { if (VirtualPathUtility.IsAbsolute(relativeAddress)) { throw FxTrace.Exception.AsError(new ConfigurationErrorsException(SR2.Hosting_RelativeAddressFormatError(relativeAddress))); } relativeAddress = VirtualPathUtility.Combine(RootVirtualPath, relativeAddress); string extension = VirtualPathUtility.GetExtension(relativeAddress); if (string.IsNullOrEmpty(extension)) { throw FxTrace.Exception.AsError(new ConfigurationErrorsException(SR2.Hosting_NoValidExtensionFoundForRegistedFilelessService(originalRelativeAddress, ServiceActivationElementPath))); } else if (GetServiceType(extension)==ServiceType.Unknown) { throw FxTrace.Exception.AsError(new ConfigurationErrorsException(SR2.Hosting_RelativeAddressExtensionNotSupportError(extension, originalRelativeAddress, ServiceActivationElementPath))); } } // since we did Empty/Null string checking in configuration element validator, we should not hit ArgumentException, just catch HttpException for invalid characher catch (HttpException ex) { throw FxTrace.Exception.AsError(new ConfigurationErrorsException(SR2.Hosting_RelativeAddressFormatError(originalRelativeAddress), ex)); } return relativeAddress; } [Fx.Tag.SecurityNote(Miscellaneous = "RequiresReview - can be called outside of user context.")] internal bool IsConfigurationBasedServiceVirtualPath(string normalizedVirtualPath) { return this.serviceActivations.ContainsKey(normalizedVirtualPath); } [Fx.Tag.SecurityNote(Miscellaneous = "RequiresReview - can be called outside of user context.")] internal bool TryGetCompiledCustomStringFromCBA(string normalizedVirtualPath, out string compiledCustomString) { compiledCustomString = null; bool isCBAService = false; if (isConfigurationBased) { compiledCustomString = (string)serviceActivations[normalizedVirtualPath]; isCBAService = true; } return isCBAService; } internal void EnsureServiceAvailable(string normalizedVirtualPath) { TryDebugPrint("HostingManager.EnsureServiceAvailable(" + normalizedVirtualPath + ")"); ServiceActivationInfo activationInfo = null; // 1. Try finding the service without a lock. activationInfo = (ServiceActivationInfo)this.directory[normalizedVirtualPath]; if (activationInfo != null && activationInfo.Service != null) { return; } isAspNetRoutedRequest = ServiceRouteHandler.IsActiveAspNetRoute(normalizedVirtualPath); isConfigurationBased = IsConfigurationBasedServiceVirtualPath(normalizedVirtualPath); // 2. Use global lock to create ServiceActivationInfo if necessary. lock (ThisLock) { if (!isRegistered) { RegisterObject(); isRegistered = true; } activationInfo = (ServiceActivationInfo)this.directory[normalizedVirtualPath]; if (activationInfo != null && activationInfo.Service != null) { return; } FailActivationIfRecyling(normalizedVirtualPath); if (activationInfo == null) { // Check service file existence if not config based activation or aspnet routing. if (!isAspNetRoutedRequest && !isConfigurationBased && !HostingEnvironmentWrapper.ServiceFileExists(normalizedVirtualPath)) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError( new EndpointNotFoundException( SR2.Hosting_ServiceNotExist( VirtualPathUtility.ToAbsolute(normalizedVirtualPath, HostingEnvironmentWrapper.ApplicationVirtualPath)))); } activationInfo = new ServiceActivationInfo(normalizedVirtualPath); directory.Add(normalizedVirtualPath, activationInfo); } } // 3. Use local lock to activate the service. ServiceHostBase newService = null; lock (activationInfo) { if (activationInfo.Service != null) { // The service has been activated by another thread. return; } FailActivationIfRecyling(normalizedVirtualPath); try { CheckMemoryGates(); newService = ActivateService(normalizedVirtualPath); // We need to lock and check IsRecycling here because it could ---- with Abort method. lock (ThisLock) { if (!IsRecycling) { activationInfo.Service = newService; } } if (DiagnosticUtility.ShouldTraceInformation) { TraceUtility.TraceEvent( TraceEventType.Information, TraceCode.WebHostServiceActivated, SR2.TraceCodeWebHostServiceActivated, new StringTraceRecord("VirtualPath", VirtualPathUtility.ToAbsolute(normalizedVirtualPath, HostingEnvironmentWrapper.ApplicationVirtualPath)), this, (Exception)null); } if (TD.ServiceHostStartedIsEnabled()) { string serviceName = string.Empty; ServiceHostBase host = newService as ServiceHostBase; if (host != null) { if (null != host.Description.ServiceType) { serviceName = host.Description.ServiceType.FullName; } else { serviceName = host.Description.Namespace + host.Description.Name; } } if(string.IsNullOrEmpty(serviceName)) { serviceName = SR2.ServiceTypeUnknown; } string servicePath = normalizedVirtualPath.Replace("~", ServiceHostingEnvironment.ApplicationVirtualPath + "|"); string hostReference = string.Format(CultureInfo.InvariantCulture, "{0}{1}|{2}", ServiceHostingEnvironment.SiteName, servicePath, host.Description.Name); TD.ServiceHostStarted(serviceName, hostReference); } } catch (HttpCompileException ex) { throw FxTrace.Exception.AsError( new ServiceActivationException(SR2.Hosting_ServiceCannotBeActivated(VirtualPathUtility.ToAbsolute(normalizedVirtualPath, HostingEnvironmentWrapper.ApplicationVirtualPath), ex.Message), ex)); } catch (ServiceActivationException) { throw; } catch (Exception ex) { // If it is a fatal exception, don't wrap it. if (Fx.IsFatal(ex)) { throw; } throw FxTrace.Exception.AsError( new ServiceActivationException(SR2.Hosting_ServiceCannotBeActivated(VirtualPathUtility.ToAbsolute(normalizedVirtualPath, HostingEnvironmentWrapper.ApplicationVirtualPath), ex.Message), ex)); } finally { currentVirtualPath = null; fullVirtualPath = null; xamlFileBaseLocation = null; } } if (activationInfo.Service == null) { Fx.Assert( IsRecycling && (newService != null), "Must happen in recycling state, also new service must has been created."); newService.Abort(); } FailActivationIfRecyling(normalizedVirtualPath); } [Fx.Tag.SecurityNote(Critical = "Accesses minFreeMemoryPercentageToActivateService, calls Check.", Safe = "No input / output, safe operation if called with administrator-provided value.")] [SecuritySafeCritical] void CheckMemoryGates() { ServiceMemoryGates.Check(this.minFreeMemoryPercentageToActivateService); } ServiceHostBase ActivateService(string normalizedVirtualPath) { ServiceHostBase service = CreateService(normalizedVirtualPath); service.Closed += this.OnServiceClosed; service.Faulted += this.OnServiceFaulted; FailActivationIfRecyling(normalizedVirtualPath); try { if (TD.ServiceHostOpenStartIsEnabled()) { TD.ServiceHostOpenStart(); } service.Open(); if (TD.ServiceHostOpenStopIsEnabled()) { TD.ServiceHostOpenStop(); } } finally { if (service.State != CommunicationState.Opened) { // Abort the service to clear possible cached information. service.Abort(); } } if (TD.AspNetRoutingServiceIsEnabled() && isAspNetRoutedRequest) { TD.AspNetRoutingService(normalizedVirtualPath); } return service; } // Why this triple try blocks instead of using "using" statement: // 1. "using" will do the impersonation prior to entering the try, // which leaves an opertunity to Thread.Abort this thread and get it to exit the method still impersonated. // 2. put the assignment of unsafeImpersonate in a finally block // in order to prevent Threat.Abort after impersonation but before the assignment. // 3. the finally of a "using" doesn't run until exception filters higher up the stack have executed. // they will do so in the impersonated context if an exception is thrown inside the try. // In sumary, this should prevent the thread from existing this method well still impersonated. [Fx.Tag.SecurityNote(Critical = "Uses SecurityCritical method UnsafeImpersonate to establish the impersonation context.", Safe = "Does not leak anything, does not let caller influence impersonation.")] [SecuritySafeCritical] string GetCompiledCustomString(string normalizedVirtualPath) { try { IDisposable unsafeImpersonate = null; try { string result = null; if (!this.TryGetCompiledCustomStringFromCBA(normalizedVirtualPath, out result)) { try { } finally { unsafeImpersonate = HostingEnvironmentWrapper.UnsafeImpersonate(); } result = BuildManager.GetCompiledCustomString(normalizedVirtualPath); } return result; } finally { if (null != unsafeImpersonate) { unsafeImpersonate.Dispose(); } } } catch { throw; } } [SecuritySafeCritical] internal Type GetCompiledType(string normalizedVirtualPath) { try { IDisposable unsafeImpersonate = null; try { try { } finally { unsafeImpersonate = HostingEnvironmentWrapper.UnsafeImpersonate(); } return BuildManager.GetCompiledType(normalizedVirtualPath); } finally { if (null != unsafeImpersonate) { unsafeImpersonate.Dispose(); } } } catch { throw; } } static Uri[] FilterBaseAddressList(Uri[] baseAddresses, Uri[] prefixFilters) { // Precondition assumption: // filterAddresses only contains one Uri per scheme. // Enforced by throwing exception when duplicates found. List results = new List (); Dictionary schemeMappings = new Dictionary (); foreach (Uri filterUri in prefixFilters) { if (!schemeMappings.ContainsKey(filterUri.Scheme)) { schemeMappings.Add(filterUri.Scheme, filterUri); } else { throw FxTrace.Exception.AsError(new InvalidOperationException(SR.GetString(SR.BaseAddressDuplicateScheme, filterUri.Scheme))); } } foreach (Uri baseUri in baseAddresses) { string scheme = baseUri.Scheme; if (schemeMappings.ContainsKey(scheme)) { Uri filterUri = schemeMappings[scheme]; if ((baseUri.Port == filterUri.Port) && (string.Compare(baseUri.Host, filterUri.Host, StringComparison.OrdinalIgnoreCase) == 0)) { results.Add(baseUri); } } else { results.Add(baseUri); } } return results.ToArray(); } ServiceHostBase CreateService(string normalizedVirtualPath) { string virtualPath; string factoryType = ""; string constructorString; ServiceHostBase service = null; ServiceHostFactoryBase factory = null; string[] compiledStrings = null; string compiledString = ""; if (TD.CompilationStartIsEnabled()) { TD.CompilationStart(); } // 0. Check AspNet Routing vs CBA // check whether there is a conflict between CBA and AspNetRouting // if there is a conflict, using AspNet routing policy to decide which service should be activated // we treat CBA as file. RouteExistingFiles is false means Routing should not override File // Todo: when there is a conflict between file/CBA adn route and routing policy was changed dynamically, we still use the old service CSD105890 if (isAspNetRoutedRequest && isConfigurationBased) { if (!RouteTable.Routes.RouteExistingFiles) { ServiceRouteHandler.MarkARouteAsInactive(normalizedVirtualPath); isAspNetRoutedRequest = false; } else { isConfigurationBased = false; } } // 1. Compile the service // The expected format is: // | | // The first two cannot be empty. if (!isAspNetRoutedRequest) { compiledString = GetCompiledCustomString(normalizedVirtualPath); if (string.IsNullOrEmpty(compiledString)) { // Assume it is a workflow service - optimize by not calling BuildManager.GetCompiledType // but we need to convert the filename to case sensitive one from the physical file // e.g., incoming request with ~/file.xamlx but physical file has name FiLe.Xamlx // we should convert the virtualPath to ~/FiLe.Xamlx, so that mex can show right case // we cannot make directory path case sensitive as we cannot get this path info with right case string fileName = HostingEnvironmentWrapper.GetServiceFile(normalizedVirtualPath).Name; string pathSegment = normalizedVirtualPath.Substring(0, normalizedVirtualPath.LastIndexOf(PathSeparator) + 1); normalizedVirtualPath = String.Format(CultureInfo.CurrentCulture, "{0}{1}", pathSegment, fileName); constructorString = virtualPath = normalizedVirtualPath; factory = CreateWorkflowServiceHostFactory(normalizedVirtualPath); } else { TryDebugPrint("HostingManager.CreateService() BuildManager.GetCompiledCustomString() returned compiledString: " + compiledString); compiledStrings = compiledString.Split(ServiceParserDelimiter.ToCharArray()); if (compiledStrings.Length < 3) { throw FxTrace.Exception.AsError(new InvalidOperationException(SR2.Hosting_CompilationResultInvalid(normalizedVirtualPath))); } virtualPath = compiledStrings[0]; factoryType = compiledStrings[1]; constructorString = compiledStrings[2]; } } else { ServiceDeploymentInfo serviceInfo = ServiceRouteHandler.GetServiceInfo(normalizedVirtualPath); // use the registered virtualpath to ensure correct case in asp.net route virtualPath = serviceInfo.VirtualPath; constructorString = serviceInfo.ServiceType; factory = serviceInfo.ServiceHostFactory; } // We get the virtual path from compiled string so that it will have the correct case. // normalizedVirtualPath should be application relative e.g., ~/service.svc // absolute path start with / and application name, e.g., /appName/service.svc normalizedVirtualPath = virtualPath; // convert relative virtualpath to app absolute one for consistency, since we gave an absolute path in compiledcustomstring previously // xamlx, CBA, and AspNet routing use relative virtualpath, while configuration/administration needs an absolute one virtualPath = VirtualPathUtility.ToAbsolute(virtualPath); // 2. Add the base addresses Uri[] baseAddresses = HostedTransportConfigurationManager.GetBaseAddresses(virtualPath); Uri[] prefixFilters = ServiceHostingEnvironment.PrefixFilters; if (!this.multipleSiteBindingsEnabled && prefixFilters != null && prefixFilters.Length > 0) { baseAddresses = FilterBaseAddressList(baseAddresses, prefixFilters); } fullVirtualPath = virtualPath; if (fullVirtualPath.Length == 0) { fullVirtualPath = "/"; } // Get the current virtual path (full path except for the .svc file name). currentVirtualPath = virtualPath.Substring(0, virtualPath.LastIndexOf(PathSeparator)); if (currentVirtualPath.Length == 0) { currentVirtualPath = "/"; xamlFileBaseLocation = RootVirtualPath; } else { // add trailing slash to support ../a.xamlx in the case .xamlx file is wrapped with .svc // otherwise when combining ~/sub with ../a.xamlx, VirtualPathUtility will return wrong value ~/a.xamlx xamlFileBaseLocation = VirtualPathUtility.AppendTrailingSlash(currentVirtualPath); } if (isConfigurationBased) { xamlFileBaseLocation = RootVirtualPath; if (TD.CBAMatchFoundIsEnabled()) { TD.CBAMatchFound(normalizedVirtualPath); } } if (TD.ServiceHostFactoryCreationStartIsEnabled()) { TD.ServiceHostFactoryCreationStart(); } // 3. Create service if (factory == null) { if (string.IsNullOrEmpty(factoryType)) { Fx.Assert(!string.IsNullOrEmpty(compiledString), "The compiled string can't be null or empty"); factory = new ServiceHostFactory(); } else { Type compiledType = Type.GetType(factoryType); //check the type from the assemblies in current domain //since compiledcustomstring does not contain fullname for configured virtual path if (compiledType == null && isConfigurationBased) { EnsureAllReferencedAssemblyLoaded(); Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies(); for (int i = 0; i < assemblies.Length; i++) { compiledType = assemblies[i].GetType(factoryType, false); if (compiledType != null) { break; } } } if (compiledType == null) { throw FxTrace.Exception.AsError(new InvalidOperationException(SR2.Hosting_FactoryTypeNotResolved(factoryType))); } if (!typeof(ServiceHostFactoryBase).IsAssignableFrom(compiledType)) { throw FxTrace.Exception.AsError(new InvalidOperationException(SR2.Hosting_IServiceHostNotImplemented(factoryType))); } ConstructorInfo ctor = compiledType.GetConstructor(new Type[] { }); if (ctor == null) { throw FxTrace.Exception.AsError(new InvalidOperationException(SR2.Hosting_NoDefaultCtor(factoryType))); } factory = (ServiceHostFactoryBase)ctor.Invoke(new object[] { }); } } if (TD.ServiceHostFactoryCreationStopIsEnabled()) { TD.ServiceHostFactoryCreationStop(); } // Push assembly context into ServiceHostFactory // it is OK for us to ignore CBA case here since no referenced assembly in compiledString for CBA // but do not do it for AspNet routing, since there is no compiledString if (factory is ServiceHostFactory && !isConfigurationBased && !isAspNetRoutedRequest) { Fx.Assert(!string.IsNullOrEmpty(compiledString), "The compiled string can't be null or empty"); for (int index = 3; index < compiledStrings.Length; ++index) { ((ServiceHostFactory)factory).AddAssemblyReference(compiledStrings[index]); } } if (TD.CreateServiceHostStartIsEnabled()) { TD.CreateServiceHostStart(); } service = factory.CreateServiceHost(constructorString, baseAddresses); if (TD.CreateServiceHostStopIsEnabled()) { TD.CreateServiceHostStop(); } if (service == null) { throw FxTrace.Exception.AsError(new InvalidOperationException(SR2.Hosting_ServiceHostBaseIsNull(constructorString))); } // 4. Create VirtualPathExtension for ServiceHostBase service.Extensions.Add(new VirtualPathExtension(normalizedVirtualPath, ServiceHostingEnvironment.ApplicationVirtualPath, ServiceHostingEnvironment.SiteName)); if (service.Description != null) { service.Description.Behaviors.Add(new ApplyHostConfigurationBehavior()); if (this.multipleSiteBindingsEnabled && service.Description.Behaviors.Find () == null) { service.Description.Behaviors.Add(new UseRequestHeadersForMetadataAddressBehavior()); } } if (TD.CompilationStopIsEnabled()) { TD.CompilationStop(); } return service; } //NoInlining - we don't want to load Workflow dlls while activating 3.0 services [MethodImpl(MethodImplOptions.NoInlining)] ServiceHostFactoryBase CreateWorkflowServiceHostFactory(string path) { return PathCache.EnsurePathInfo(path).ServiceModelActivationHandler.GetFactory(); } void FailActivationIfRecyling(string normalizedVirtualPath) { if (IsRecycling) { InvalidOperationException exception = new InvalidOperationException( SR2.Hosting_EnvironmentShuttingDown(normalizedVirtualPath, HostingEnvironmentWrapper.ApplicationVirtualPath)); throw FxTrace.Exception.AsError(new ServiceActivationException(exception.Message, exception)); } } public void Stop(bool immediate) { if (!immediate) { // Try to wait for all requests to be done, then close all the ServiceHosts. ActionItem.Schedule(new Action
Link Menu
This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- Input.cs
- FileFormatException.cs
- SmiSettersStream.cs
- ReachDocumentReferenceCollectionSerializer.cs
- DirectionalLight.cs
- StreamSecurityUpgradeInitiatorAsyncResult.cs
- SettingsProperty.cs
- OracleParameterBinding.cs
- ViewGenResults.cs
- CreateUserWizardAutoFormat.cs
- NativeMethods.cs
- NavigationProgressEventArgs.cs
- sqlstateclientmanager.cs
- InvokeProviderWrapper.cs
- BooleanSwitch.cs
- FreeFormDesigner.cs
- Accessible.cs
- StickyNoteHelper.cs
- BindingContext.cs
- ProfileService.cs
- TemplateKey.cs
- ToolStripItemTextRenderEventArgs.cs
- DBCSCodePageEncoding.cs
- oledbmetadatacollectionnames.cs
- X509CertificateValidator.cs
- SingleKeyFrameCollection.cs
- ValidationError.cs
- WorkflowInstanceContextProvider.cs
- ToggleProviderWrapper.cs
- PublisherMembershipCondition.cs
- MenuStrip.cs
- StateMachine.cs
- _emptywebproxy.cs
- XLinq.cs
- COM2FontConverter.cs
- DmlSqlGenerator.cs
- PerformanceCounterPermission.cs
- ElementNotAvailableException.cs
- AdRotator.cs
- SqlConnectionStringBuilder.cs
- HMACRIPEMD160.cs
- StructureChangedEventArgs.cs
- Point3D.cs
- UnmanagedHandle.cs
- OperatingSystem.cs
- BindableAttribute.cs
- InputBinding.cs
- StringStorage.cs
- ConfigurationValidatorAttribute.cs
- DictationGrammar.cs
- ObservableDictionary.cs
- StatusBarPanelClickEvent.cs
- CaseInsensitiveHashCodeProvider.cs
- AutoResizedEvent.cs
- MetricEntry.cs
- RowVisual.cs
- TraceLog.cs
- PersonalizationProviderCollection.cs
- MetadataPropertyvalue.cs
- StorageAssociationTypeMapping.cs
- SystemInfo.cs
- ContractCodeDomInfo.cs
- MarshalDirectiveException.cs
- WSFederationHttpSecurity.cs
- BitmapEncoder.cs
- XmlDocumentFragment.cs
- ControlCommandSet.cs
- NavigationProperty.cs
- CollectionViewSource.cs
- XmlEventCache.cs
- ListDictionaryInternal.cs
- Pen.cs
- StackSpiller.Bindings.cs
- AttributeAction.cs
- SaveFileDialog.cs
- SessionStateModule.cs
- ApplicationDirectoryMembershipCondition.cs
- RemotingConfigParser.cs
- FontStyleConverter.cs
- BindingManagerDataErrorEventArgs.cs
- Brush.cs
- X509Extension.cs
- ToolStripContentPanel.cs
- PerformanceCounter.cs
- XmlWriterTraceListener.cs
- DateTimeStorage.cs
- CollectionMarkupSerializer.cs
- SmtpException.cs
- MenuAdapter.cs
- IxmlLineInfo.cs
- UIPropertyMetadata.cs
- ValidationErrorEventArgs.cs
- OdbcConnectionFactory.cs
- activationcontext.cs
- EmptyControlCollection.cs
- PointLight.cs
- RtType.cs
- TypeSystem.cs
- MergeFailedEvent.cs
- OutputCacheSettings.cs