Code:
/ WCF / WCF / 3.5.30729.1 / untmp / Orcas / SP / ndp / cdf / src / WCF / ServiceModel / System / ServiceModel / ServiceHostingEnvironment.cs / 3 / ServiceHostingEnvironment.cs
//----------------------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
//---------------------------------------------------------------------------
namespace System.ServiceModel
{
using System.Configuration;
using System.Collections;
using System.Collections.Specialized;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Reflection;
using System.Net;
using System.Runtime.CompilerServices;
using System.ServiceModel.Activation;
using System.ServiceModel.Channels;
using System.ServiceModel.Diagnostics;
using System.ServiceModel.ComIntegration;
using System.Threading;
using System.Web;
using System.Web.Compilation;
using System.Web.Configuration;
using System.Web.Hosting;
using System.Runtime.Serialization;
using System.Security.Principal;
using System.ServiceModel.Configuration;
using System.Runtime;
using System.Runtime.InteropServices;
using System.ComponentModel;
using System.Security.Permissions;
using System.Security;
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;
internal const string VerbPost = "POST";
internal const string ISAPIApplicationIdPrefix = "/LM/W3SVC/";
internal const string RelativeVirtualPathPrefix = "~";
internal const string ServiceParserDelimiter = "|";
const char FileExtensionSeparator = '.';
const char UriSchemeSeparator = ':';
const char PathSeparator = '/';
///
/// Critical - Calls into an unsafe UnsafeLogEvent method
/// TreatAsSafe - Event identities cannot be spoofed as they are constants determined inside the method
///
[SecurityCritical, SecurityTreatAsSafe]
static void OnUnhandledException(object sender, UnhandledExceptionEventArgs e)
{
if (DiagnosticUtility.ShouldTraceError)
{
Exception exception = e.ExceptionObject as Exception;
DiagnosticUtility.UnsafeEventLog.UnsafeLogEvent(TraceEventType.Error, EventLogCategory.WebHost, EventLogEventId.WebHostUnhandledException, true,
DiagnosticTrace.CreateSourceString(sender),
exception == null ? string.Empty : exception.ToString());
}
}
///
/// Review - called by ProcessRequest outside of the restricted SecurityContext
///
[SecurityRequiresReview]
public static bool AspNetCompatibilityEnabled
{
///
/// Review - can be called outside of user context.
///
[SecurityRequiresReview]
get
{
if (!IsHosted)
return false;
return IsAspNetCompatibilityEnabled();
}
}
///
/// Review - called by ServiceHostFactory.CreateServiceHost
///
[SecurityRequiresReview]
internal static Uri[] PrefixFilters
{
[SecurityRequiresReview]
get
{
if (!IsHosted)
return null;
return GetBaseAddressPrefixFilters();
}
}
///
/// Review - can be called outside of user context.
///
[SecurityRequiresReview]
[MethodImpl(MethodImplOptions.NoInlining)]
static bool IsAspNetCompatibilityEnabled()
{
return hostingManager.AspNetCompatibilityEnabled;
}
///
/// Review - can be called outside of user context.
///
[SecurityRequiresReview]
[MethodImpl(MethodImplOptions.NoInlining)]
static Uri[] GetBaseAddressPrefixFilters()
{
return hostingManager.BaseAddressPrefixFilters;
}
public static void EnsureServiceAvailable(string virtualPath)
{
if (string.IsNullOrEmpty(virtualPath))
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("virtualPath"));
if (virtualPath.IndexOf(UriSchemeSeparator) > 0)
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentException(SR.GetString(SR.Hosting_AddressIsAbsoluteUri, virtualPath), "virtualPath"));
EnsureInitialized();
virtualPath = NormalizeVirtualPath(virtualPath);
EnsureServiceAvailableFast(virtualPath);
}
internal static void EnsureServiceAvailableFast(string relativeVirtualPath)
{
try
{
hostingManager.EnsureServiceAvailable(relativeVirtualPath);
}
catch (ServiceActivationException exception)
{
LogServiceActivationException(exception);
throw;
}
}
///
/// Critical - Calls into an unsafe UnsafeLogEvent method
/// TreatAsSafe - Event identities cannot be spoofed as they are constants determined inside the method
///
[SecurityCritical, SecurityTreatAsSafe]
private static void LogServiceActivationException(ServiceActivationException exception)
{
if (exception.InnerException is HttpException)
{
string messageAsString = SafeTryGetHtmlErrorMessage((HttpException)exception.InnerException);
if (messageAsString == null || messageAsString.Length == 0)
messageAsString = exception.Message;
DiagnosticUtility.UnsafeEventLog.UnsafeLogEvent(TraceEventType.Error, EventLogCategory.WebHost, EventLogEventId.WebHostHttpError, true,
DiagnosticTrace.CreateSourceString(hostingManager),
messageAsString,
exception == null ? string.Empty : exception.ToString());
}
else
{
DiagnosticUtility.UnsafeEventLog.UnsafeLogEvent(TraceEventType.Error, EventLogCategory.WebHost, EventLogEventId.WebHostFailedToProcessRequest, true,
DiagnosticTrace.CreateSourceString(hostingManager),
exception == null ? string.Empty : exception.ToString());
}
}
static bool canGetHtmlErrorMessage = true;
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;
}
///
/// Review - can be called outside of user context.
///
[SecurityRequiresReview]
internal static void IncrementRequestCount()
{
Interlocked.Increment(ref requestCount);
}
internal static void DecrementRequestCount()
{
Interlocked.Decrement(ref requestCount);
Debug.Assert(requestCount >= 0, "Request count should always be non-nagative.");
if (requestCount == 0)
{
if (hostingManager != null)
{
hostingManager.NotifyAllRequestDone();
}
}
}
internal static string CurrentVirtualPath
{
get
{
DiagnosticUtility.DebugAssert(IsHosted, "CurrentVirtualPath should not be called from non web-hosted environment.");
return hostingManager.CurrentVirtualPath;
}
}
internal static void ProcessNotMatchedEndpointAddress(Uri uri, string endpointName)
{
if (ServiceHostingEnvironment.AspNetCompatibilityEnabled &&
!object.ReferenceEquals(uri.Scheme, Uri.UriSchemeHttp) &&
!object.ReferenceEquals(uri.Scheme, Uri.UriSchemeHttps))
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.Hosting_NonHTTPInCompatibilityMode, endpointName)));
}
}
///
/// Review - called by ProcessRequest outside of the restricted SecurityContext
///
[SecurityRequiresReview]
internal static bool GetExtensionSupported(string extension)
{
DiagnosticUtility.DebugAssert(IsHosted, "GetExtensionSupported should not be called from non web-hosted environment.");
return hostingManager.GetExtensionSupported(extension);
}
internal static bool IsRecycling
{
get
{
DiagnosticUtility.DebugAssert(IsHosted, "IsRecycling should not be called from non web-hosted environment.");
return hostingManager.IsRecycling;
}
}
static object ThisLock
{
get
{
return syncRoot;
}
}
internal static void DecrementBusyCount()
{
if (ServiceHostingEnvironment.IsHosted)
HostingEnvironmentWrapper.DecrementBusyCount();
}
internal static void IncrementBusyCount()
{
if (ServiceHostingEnvironment.IsHosted)
HostingEnvironmentWrapper.IncrementBusyCount();
}
///
/// Review - called by ProcessRequest outside of the restricted SecurityContext
///
[SecurityRequiresReview]
internal static void SafeEnsureInitialized()
{
if (hostingManager == null)
{
PartialTrustHelpers.PartialTrustInvoke(new ContextCallback(OnEnsureInitialized), null);
}
}
static void OnEnsureInitialized(object state)
{
EnsureInitialized();
}
internal static void EnsureInitialized()
{
if (hostingManager != null)
return;
lock (ThisLock)
{
if (hostingManager != null)
return;
if (!HostingEnvironmentWrapper.IsHosted)
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(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();
hostingManager = tempHostingManager;
isHosted = true;
}
}
///
/// Critical - Satisfies a LinkDemand for SecurityPermission(ControlAppDomain) on HookADUnhandledExceptionEvent
/// Safe - no control flow in for handler
///
[SecurityCritical, SecurityTreatAsSafe]
static void HookADUnhandledExceptionEvent()
{
AppDomain.CurrentDomain.UnhandledException += OnUnhandledException;
}
///
/// Critical - Uses SecurityCritical property UnsafeApplicationID to get application id with an elevation
/// Safe - processes result into a simple bool which is not protected
///
[SecurityCritical, SecurityTreatAsSafe]
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);
}
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 DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentException(exception.Message, "virtualPath", exception));
}
if (string.IsNullOrEmpty(processedVirtualPath) ||
!processedVirtualPath.StartsWith(RelativeVirtualPathPrefix, StringComparison.Ordinal))
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentException(SR.GetString(SR.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.GetExtensionSupported(extension))
{
// Remove the pathinfo.
return subVirtualPath;
}
}
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new EndpointNotFoundException(SR.GetString(SR.Hosting_ServiceNotExist, virtualPath)));
}
internal static bool IsHosted
{
///
/// Review - can be called outside of user context.
///
[SecurityRequiresReview]
get
{
return isHosted;
}
}
internal static bool IsSimpleApplicationHost
{
get
{
DiagnosticUtility.DebugAssert(IsHosted, "IsSimpleApplicationHost should not be called from non web-hosted environment.");
return isSimpleApplicationHost;
}
}
const string SystemWebComma = "System.Web,";
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;
}
}
///
/// 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)]
[SecurityCritical, SecurityTreatAsSafe]
[AspNetHostingPermission(SecurityAction.Assert, Level = AspNetHostingPermissionLevel.Minimal)]
static bool IsApplicationDomainHosted()
{
return HostingEnvironment.IsHosted;
}
class HostingManager : IRegisteredObject
{
IDictionary directory;
readonly ExtensionHelper extensions;
bool aspNetCompatibilityEnabled;
bool isUnregistered;
bool isRecycling;
bool isStopStarted;
static object syncRoot = new object();
Uri[] baseAddressPrefixFilters;
// One instance per appdomain, don't need to be disposed.
ManualResetEvent allRequestDoneInStop = new ManualResetEvent(false);
///
/// Critical - Admin-provided value that allows for machine resource allocation
///
[SecurityCritical]
int minFreeMemoryPercentageToActivateService;
[ThreadStatic]
string currentVirtualPath;
internal HostingManager()
{
this.directory = new Dictionary(16, StringComparer.OrdinalIgnoreCase);
try
{
RegisterObject();
LoadConfigParameters();
this.extensions = new ExtensionHelper();
}
finally
{
// Make sure failure to construct is idempotent
if (this.extensions == null)
{
UnregisterObject();
}
}
}
///
/// Critical - Uses SecurityCritical method UnsafeGetSection to get config with an elevation
/// - Sets minFreeMemoryPercentageToActivateService
/// Safe - does not leak config objects
///
[SecurityCritical, SecurityTreatAsSafe]
private void LoadConfigParameters()
{
ServiceHostingEnvironmentSection section = ServiceHostingEnvironmentSection.UnsafeGetSection();
this.aspNetCompatibilityEnabled = section.AspNetCompatibilityEnabled;
this.minFreeMemoryPercentageToActivateService = section.MinFreeMemoryPercentageToActivateService;
List prefixFilters = new List();
foreach (BaseAddressPrefixFilterElement element in section.BaseAddressPrefixFilters)
{
prefixFilters.Add(element.Prefix);
}
this.baseAddressPrefixFilters = prefixFilters.ToArray();
}
///
/// Review - can be called outside of user context.
///
[SecurityRequiresReview]
internal bool GetExtensionSupported(string extension)
{
return extensions.GetExtensionSupported(extension);
}
internal bool AspNetCompatibilityEnabled
{
///
/// Review - can be called outside of user context.
///
[SecurityRequiresReview]
get
{
return aspNetCompatibilityEnabled;
}
}
internal Uri[] BaseAddressPrefixFilters
{
///
/// Review - can be called outside of user context.
///
[SecurityRequiresReview]
get
{
return baseAddressPrefixFilters;
}
}
internal string CurrentVirtualPath { get { return currentVirtualPath; } }
internal static object ThisLock
{
get
{
return syncRoot;
}
}
internal bool IsRecycling
{
get
{
return isRecycling;
}
}
internal void EnsureServiceAvailable(string normalizedVirtualPath)
{
TryDebugPrint("HostingManager.EnsureServiceAvailable(" + normalizedVirtualPath + ")");
ServiceActivationInfo activationInfo = null;
// 1. Use global lock to find ServiceActivationInfo
lock (ThisLock)
{
if (directory.TryGetValue(normalizedVirtualPath, out activationInfo))
{
if (activationInfo.Service != null)
return;
}
FailActivationIfRecyling(normalizedVirtualPath);
if (activationInfo == null)
{
// Check service file existence.
if (!HostingEnvironment.VirtualPathProvider.FileExists(normalizedVirtualPath))
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
new EndpointNotFoundException(
SR.GetString(
SR.Hosting_ServiceNotExist,
VirtualPathUtility.ToAbsolute(normalizedVirtualPath, HostingEnvironmentWrapper.ApplicationVirtualPath))));
}
activationInfo = new ServiceActivationInfo(normalizedVirtualPath);
directory.Add(normalizedVirtualPath, activationInfo);
}
}
// 2. 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 race with Abort method.
lock (ThisLock)
{
if (!IsRecycling)
{
activationInfo.Service = newService;
}
}
if (DiagnosticUtility.ShouldTraceInformation)
{
TraceUtility.TraceEvent(
TraceEventType.Information, TraceCode.WebHostServiceActivated,
new StringTraceRecord("VirtualPath", VirtualPathUtility.ToAbsolute(normalizedVirtualPath, HostingEnvironmentWrapper.ApplicationVirtualPath)), this, (Exception)null);
}
}
catch (HttpCompileException ex)
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
new ServiceActivationException(SR.GetString(SR.Hosting_ServiceCannotBeActivated, VirtualPathUtility.ToAbsolute(normalizedVirtualPath, HostingEnvironmentWrapper.ApplicationVirtualPath), ex.Message), ex));
}
catch (ServiceActivationException)
{
throw;
}
#pragma warning suppress 56500 // covered by FxCOP
catch (Exception ex)
{
// If it is a fatal exception, don't wrap it.
if (DiagnosticUtility.IsFatal(ex))
{
throw;
}
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
new ServiceActivationException(SR.GetString(SR.Hosting_ServiceCannotBeActivated, VirtualPathUtility.ToAbsolute(normalizedVirtualPath, HostingEnvironmentWrapper.ApplicationVirtualPath), ex.Message), ex));
}
finally
{
currentVirtualPath = null;
}
}
if (activationInfo.Service == null)
{
DiagnosticUtility.DebugAssert(
IsRecycling && (newService != null),
"Must happen in recycling state, also new service must has been created.");
newService.Abort();
}
FailActivationIfRecyling(normalizedVirtualPath);
}
///
/// Critical - Accesses minFreeMemoryPercentageToActivateService, calls Check
/// Safe - no input / output, safe operation if called with administrator-provided value
///
[SecurityCritical, SecurityTreatAsSafe]
void CheckMemoryGates()
{
ServiceMemoryGates.Check(this.minFreeMemoryPercentageToActivateService);
}
ServiceHostBase ActivateService(string normalizedVirtualPath)
{
ServiceHostBase service = CreateService(normalizedVirtualPath);
service.Closed += this.OnServiceClosed;
FailActivationIfRecyling(normalizedVirtualPath);
try
{
service.Open();
}
finally
{
if (service.State != CommunicationState.Opened)
{
// Abort the service to clear possible cached information.
service.Abort();
}
}
return service;
}
///
/// Critical - Uses SecurityCritical method UnsafeImpersonate to establish the impersonation context
/// Safe - does not leak anything, does not let caller influence impersonation
///
// 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.
[SecurityCritical, SecurityTreatAsSafe]
string GetCompiledCustomString(string normalizedVirtualPath)
{
try
{
IDisposable unsafeImpersonate = null;
try
{
try { }
finally
{
unsafeImpersonate = HostingEnvironmentWrapper.UnsafeImpersonate();
}
return BuildManager.GetCompiledCustomString(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 DiagnosticUtility.ExceptionUtility.ThrowHelperError(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)
{
// 1. Compile the service
// The expected format is:
// ||
// The first two cannot be empty.
string compiledString = GetCompiledCustomString(normalizedVirtualPath);
if (string.IsNullOrEmpty(compiledString))
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.Hosting_CompilationResultEmpty, normalizedVirtualPath)));
}
TryDebugPrint("HostingManager.CreateService() BuildManager.GetCompiledCustomString() returned compiledString: " + compiledString);
string[] compiledStrings = compiledString.Split(ServiceParserDelimiter.ToCharArray());
if (compiledStrings.Length < 3)
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.Hosting_CompilationResultInvalid, normalizedVirtualPath)));
}
// 2. Add the base addresses
Uri[] baseAddresses = HostedTransportConfigurationManager.GetBaseAddresses(compiledStrings[0]);
Uri[] prefixFilters = ServiceHostingEnvironment.PrefixFilters;
if (prefixFilters != null && prefixFilters.Length > 0)
{
baseAddresses = FilterBaseAddressList(baseAddresses, prefixFilters);
}
// We generate the virtual path from compiled string so that it will has correct case.
normalizedVirtualPath = VirtualPathUtility.ToAppRelative(compiledStrings[0], HostingEnvironmentWrapper.ApplicationVirtualPath);
// Get the current virtual path (full path except for the .svc file name).
currentVirtualPath = compiledStrings[0].Substring(0, compiledStrings[0].LastIndexOf('/'));
if (currentVirtualPath.Length == 0)
{
currentVirtualPath = "/";
}
// 3. Create service
ServiceHostBase service = null;
ServiceHostFactoryBase factory = null;
if (string.IsNullOrEmpty(compiledStrings[1]))
factory = new ServiceHostFactory();
else
{
Type compiledType = Type.GetType(compiledStrings[1]);
if (!typeof(ServiceHostFactoryBase).IsAssignableFrom(compiledType))
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.Hosting_IServiceHostNotImplemented, compiledStrings[1])));
ConstructorInfo ctor = compiledType.GetConstructor(new Type[] { });
if (ctor == null)
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.Hosting_NoDefaultCtor, compiledStrings[1])));
factory = (ServiceHostFactoryBase)ctor.Invoke(new object[] { });
}
// Push assembly context into ServiceHostFactory
if (factory is ServiceHostFactory)
{
for (int index = 3; index < compiledStrings.Length; ++index)
((ServiceHostFactory)factory).AddAssemblyReference(compiledStrings[index]);
}
service = factory.CreateServiceHost(compiledStrings[2], baseAddresses);
if (service == null)
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.Hosting_ServiceHostBaseIsNull, compiledStrings[2])));
}
// 4. Create VirtualPathExtension for ServiceHostBase
VirtualPathExtension virtualPathExtension = new VirtualPathExtension(normalizedVirtualPath);
service.Extensions.Add(virtualPathExtension);
return service;
}
void FailActivationIfRecyling(string normalizedVirtualPath)
{
if (IsRecycling)
{
InvalidOperationException exception = new InvalidOperationException(SR.GetString(
SR.Hosting_EnvironmentShuttingDown, normalizedVirtualPath,
HostingEnvironmentWrapper.ApplicationVirtualPath));
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(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.
IOThreadScheduler.ScheduleCallback(new WaitCallback(WaitAndCloseCallback), this);
}
else
{
// Will execute here only if HostingEnvironment.UnregisterObject hasn't been called.
Abort();
}
}
static bool canDebugPrint = true;
[Conditional("DEBUG")]
static void TryDebugPrint(string message)
{
if (canDebugPrint)
{
try
{
Debug.Print(message);
}
catch (SecurityException e)
{
canDebugPrint = false;
// not re-throwing on purpose
if (DiagnosticUtility.ShouldTraceWarning)
{
DiagnosticUtility.ExceptionUtility.TraceHandledException(e, TraceEventType.Warning);
}
}
}
}
void OnServiceClosed(object sender, EventArgs e)
{
lock (ThisLock)
{
if (!isRecycling)
{
ServiceHostBase closedService = (ServiceHostBase)sender;
string key = null;
foreach (string address in directory.Keys)
{
if (directory[address].Service == closedService)
{
key = address;
break;
}
}
if (key != null)
{
directory.Remove(key);
}
}
}
}
internal void NotifyAllRequestDone()
{
if (isStopStarted)
{
allRequestDoneInStop.Set();
}
}
void Abort()
{
allRequestDoneInStop.Set();
List> list = null;
lock (ThisLock)
{
// We need to set isRecycling inside lock because we want to make sure no
// new request will be handed once we start to shut down.
isRecycling = true;
if (UnregisterObject())
{
return;
}
// Make a copy of directory.
list = new List>(directory);
}
// Enumerate all the ServiceHosts, abort them one by one.
for (int i = 0; i < list.Count; i++)
{
//If it is called with immediate=true, then we will abort all the services.
if (list[i].Value.Service != null)
{
try
{
list[i].Value.Service.Abort();
}
catch (Exception exception)
{
if (!(DiagnosticUtility.IsFatal(exception)))
{
LogServiceCloseError(list[i].Key, exception);
}
throw;
}
}
RemoveCachedService(list[i].Key);
}
}
void WaitAndCloseCallback(object obj)
{
isStopStarted = true;
if (ServiceHostingEnvironment.requestCount != 0)
{
allRequestDoneInStop.WaitOne();
}
List> list = null;
lock (ThisLock)
{
if (UnregisterObject())
{
return;
}
// Make a copy of directory.
list = new List>(directory);
}
// Enumerate all the ServiceHosts, close them one by one.
AsyncCallback callback = null;
for (int i = 0; i < list.Count; i++)
{
if (list[i].Value.Service != null)
{
// We will try to close all the services asynchronously.
if (callback == null)
{
callback = DiagnosticUtility.ThunkAsyncCallback(new AsyncCallback(OnCloseService));
}
IAsyncResult result = null;
try
{
// Set timeout to MaxValue and so that only ASP.NET setting is used.
result = list[i].Value.Service.BeginClose(TimeSpan.MaxValue, callback, list[i]);
}
catch (Exception exception)
{
// If BeginClose throw an exception, abort should already have been called.
if (!(DiagnosticUtility.IsFatal(exception)))
{
LogServiceCloseError(list[i].Key, exception);
}
if (!(exception is CommunicationException))
{
throw;
}
// We will remove the service and continue processing other services
// if a CommunicationException happened.
RemoveCachedService(list[i].Key);
}
if (result != null && result.CompletedSynchronously)
{
EndCloseService(result);
}
}
else
{
RemoveCachedService(list[i].Key);
}
}
}
void OnCloseService(IAsyncResult result)
{
if (!result.CompletedSynchronously)
{
EndCloseService(result);
}
}
void EndCloseService(IAsyncResult result)
{
KeyValuePair item = (KeyValuePair)result.AsyncState;
try
{
item.Value.Service.EndClose(result);
}
catch (Exception exception)
{
//If EndClose throw an exception, abort should already have been called.
if (DiagnosticUtility.IsFatal(exception))
{
throw;
}
LogServiceCloseError(item.Key, exception);
}
RemoveCachedService(item.Key);
}
void RemoveCachedService(string path)
{
lock (ThisLock)
{
// At the time when we just removed all the service, we will unregister
// from HostingEnvironement.
directory.Remove(path);
UnregisterObject();
}
}
void LogServiceCloseError(string virtualPath, Exception exception)
{
if (DiagnosticUtility.ShouldTraceError)
{
TraceUtility.TraceEvent(TraceEventType.Error, TraceCode.WebHostServiceCloseFailed,
new StringTraceRecord("VirtualPath", VirtualPathUtility.ToAbsolute(virtualPath, HostingEnvironmentWrapper.ApplicationVirtualPath)),
this, exception);
}
}
///
/// Critical - Uses HostingEnvironmentWrapper.UnsafeRegisterObject which is critical
/// Safe - doesn't allow the caller to control the variable -- only registers 'this'
///
[SecurityCritical, SecurityTreatAsSafe]
void RegisterObject()
{
HostingEnvironmentWrapper.UnsafeRegisterObject(this);
}
// Note : this method should only be called under lock of ThisLock.
///
/// Critical - Uses HostingEnvironmentWrapper.UnsafeUnregisterObject which is critical
/// Safe - doesn't allow the caller to control the variable -- only unregisters 'this'
///
[SecurityCritical, SecurityTreatAsSafe]
bool UnregisterObject()
{
if (directory.Count == 0)
{
if (!isUnregistered)
{
isUnregistered = true;
HostingEnvironmentWrapper.UnsafeUnregisterObject(this);
}
return true;
}
return false;
}
class ExtensionHelper
{
readonly IDictionary buildProviders;
///
/// Critical - loads config through an elevation and stores results
/// Safe - stores results in BuildProviderInfo instances which restrict access to the BuildProvider config object
///
[SecurityCritical, SecurityTreatAsSafe]
public ExtensionHelper()
{
buildProviders = new Dictionary(8, StringComparer.OrdinalIgnoreCase);
CompilationSection compilationSection = (CompilationSection)ConfigurationHelpers.UnsafeGetSectionFromWebConfigurationManager("system.web/compilation");
foreach (System.Web.Configuration.BuildProvider buildProvider in compilationSection.BuildProviders)
{
buildProviders.Add(buildProvider.Extension, new BuildProviderInfo(buildProvider));
}
}
///
/// Review - can be called outside of user context.
///
[SecurityRequiresReview]
public bool GetExtensionSupported(string extension)
{
BuildProviderInfo info;
if (!buildProviders.TryGetValue(extension, out info))
return false;
return info.IsSupported;
}
}
}
class ServiceActivationInfo
{
string virtualPath;
ServiceHostBase service;
public ServiceActivationInfo(string virtualPath)
{
this.virtualPath = virtualPath;
}
public ServiceHostBase Service
{
get
{
return this.service;
}
set
{
this.service = value;
}
}
}
class BuildProviderInfo
{
///
/// Critical - stores the result of an elevation
///
[SecurityCritical]
System.Web.Configuration.BuildProvider buildProvider;
bool initialized;
bool isSupported;
object thisLock = new object();
///
/// Critical - stores the result of an elevation
/// Safe - stores it in a Critical field
///
[SecurityCritical, SecurityTreatAsSafe]
public BuildProviderInfo(System.Web.Configuration.BuildProvider buildProvider)
{
this.buildProvider = buildProvider;
}
///
/// Review - can be called outside of user context.
///
[SecurityRequiresReview]
void EnsureInitialized()
{
if (initialized)
return;
lock (thisLock)
{
if (initialized)
return;
Type type = Type.GetType(BuildProviderType, false);
if (type == null)
{
Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
for (int i = 0; i < assemblies.Length; i++)
{
type = assemblies[i].GetType(BuildProviderType, false);
if (type != null)
break;
}
}
if (type != null)
{
object[] attributes = System.ServiceModel.Description.ServiceReflector.GetCustomAttributes(type, typeof(ServiceActivationBuildProviderAttribute), true);
if (attributes.Length > 0)
{
isSupported = true;
}
}
ClearBuildProvider();
initialized = true;
}
}
string BuildProviderType
{
///
/// Critical - accesses the SecurityCritical buildProvider field
/// Safe - returns the Type property, which is allowed; doesn't leak the BuildProvider instance
///
[SecurityCritical, SecurityTreatAsSafe]
get { return buildProvider.Type; }
}
///
/// Review - can be called outside of user context.
///
[SecurityRequiresReview]
public bool IsSupported
{
get
{
EnsureInitialized();
return isSupported;
}
}
///
/// Critical - accesses the SecurityCritical buildProvider field
/// - Can be called outside user context.
/// Safe - just clears it, doesn't leak anything
///
[SecurityCritical, SecurityTreatAsSafe]
void ClearBuildProvider()
{
this.buildProvider = null;
}
}
}
}
// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.
Link Menu

This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- XmlAnyElementAttributes.cs
- Propagator.cs
- EnumerableRowCollectionExtensions.cs
- DataGridViewRowStateChangedEventArgs.cs
- TextControl.cs
- SystemIPAddressInformation.cs
- OdbcConnectionFactory.cs
- ZoneButton.cs
- UrlUtility.cs
- ObjectItemNoOpAssemblyLoader.cs
- WebControl.cs
- XmlIterators.cs
- ChangeConflicts.cs
- CodeNamespaceCollection.cs
- OleDbFactory.cs
- SymbolMethod.cs
- isolationinterop.cs
- CheckedListBox.cs
- SearchForVirtualItemEventArgs.cs
- HashCodeCombiner.cs
- WriteTimeStream.cs
- CompiledXpathExpr.cs
- ProviderManager.cs
- RecommendedAsConfigurableAttribute.cs
- WebPartDisplayModeCollection.cs
- DataContract.cs
- RuleCache.cs
- StateDesigner.Helpers.cs
- HtmlHistory.cs
- MembershipValidatePasswordEventArgs.cs
- ThemeableAttribute.cs
- DrawingServices.cs
- ConnectionModeReader.cs
- EventItfInfo.cs
- TrackBarDesigner.cs
- SoapInteropTypes.cs
- ConnectionStringsExpressionBuilder.cs
- LateBoundBitmapDecoder.cs
- PaintEvent.cs
- EmptyReadOnlyDictionaryInternal.cs
- ModulesEntry.cs
- MSHTMLHost.cs
- Context.cs
- ScrollChangedEventArgs.cs
- MonthCalendarDesigner.cs
- HiddenField.cs
- ObjectListCommandCollection.cs
- RepeatButton.cs
- TemplatedEditableDesignerRegion.cs
- RootBrowserWindow.cs
- ParameterBuilder.cs
- RootBrowserWindowAutomationPeer.cs
- IsolatedStorageFile.cs
- Token.cs
- GregorianCalendar.cs
- documentsequencetextcontainer.cs
- CellTreeSimplifier.cs
- NullableConverter.cs
- CommonXSendMessage.cs
- EncryptedData.cs
- ContextItem.cs
- RenderData.cs
- InputLanguageManager.cs
- FamilyTypeface.cs
- ListViewSelectEventArgs.cs
- HMAC.cs
- DataGridViewLinkColumn.cs
- ImportCatalogPart.cs
- GlyphInfoList.cs
- CFStream.cs
- NameValueConfigurationElement.cs
- ServiceChannelManager.cs
- AlignmentXValidation.cs
- ArithmeticLiteral.cs
- PaintEvent.cs
- Int16AnimationBase.cs
- SchemaImporterExtensionElement.cs
- EventTrigger.cs
- TextBox.cs
- ItemCheckedEvent.cs
- ListDictionaryInternal.cs
- BehaviorEditorPart.cs
- CngKey.cs
- XsltException.cs
- WindowsGraphics.cs
- DashStyle.cs
- HtmlElementCollection.cs
- URLBuilder.cs
- ObjectStateEntry.cs
- StateValidator.cs
- DoubleCollectionValueSerializer.cs
- VisualBrush.cs
- FileDialogCustomPlace.cs
- Subtree.cs
- MouseCaptureWithinProperty.cs
- _ProxyRegBlob.cs
- NativeActivityFaultContext.cs
- MinimizableAttributeTypeConverter.cs
- Stacktrace.cs
- QueuedDeliveryRequirementsMode.cs