2016-11-10 13:04:39 +00:00
//-----------------------------------------------------------------------------
2016-08-03 10:59:49 +00:00
// Copyright (c) Microsoft Corporation. All rights reserved.
//-----------------------------------------------------------------------------
namespace System.ServiceModel
{
using System ;
using System.Collections.Generic ;
using System.Collections.ObjectModel ;
using System.ComponentModel ;
using System.Diagnostics ;
using System.Globalization ;
using System.Net ;
using System.Runtime ;
using System.Security ;
using System.ServiceModel.Administration ;
using System.ServiceModel.Channels ;
using System.ServiceModel.Configuration ;
using System.ServiceModel.Description ;
using System.ServiceModel.Diagnostics ;
using System.ServiceModel.Dispatcher ;
using System.Text ;
using System.Runtime.Diagnostics ;
using System.Threading ;
using System.ServiceModel.Activation ;
using System.ServiceModel.Diagnostics.Application ;
using System.Reflection ;
using System.Linq.Expressions ;
public abstract class ServiceHostBase : CommunicationObject , IExtensibleObject < ServiceHostBase > , IDisposable
{
internal static readonly Uri EmptyUri = new Uri ( string . Empty , UriKind . RelativeOrAbsolute ) ;
bool initializeDescriptionHasFinished ;
UriSchemeKeyedCollection baseAddresses ;
ChannelDispatcherCollection channelDispatchers ;
TimeSpan closeTimeout = ServiceDefaults . ServiceHostCloseTimeout ;
ServiceDescription description ;
ExtensionCollection < ServiceHostBase > extensions ;
ReadOnlyCollection < Uri > externalBaseAddresses ;
IDictionary < string , ContractDescription > implementedContracts ;
IInstanceContextManager instances ;
TimeSpan openTimeout = ServiceDefaults . OpenTimeout ;
ServicePerformanceCountersBase servicePerformanceCounters ;
DefaultPerformanceCounters defaultPerformanceCounters ;
ServiceThrottle serviceThrottle ;
ServiceCredentials readOnlyCredentials ;
ServiceAuthorizationBehavior readOnlyAuthorization ;
ServiceAuthenticationBehavior readOnlyAuthentication ;
Dictionary < DispatcherBuilder . ListenUriInfo , Collection < ServiceEndpoint > > endpointsByListenUriInfo ;
int busyCount ;
EventTraceActivity eventTraceActivity ;
internal event EventHandler BusyCountIncremented ;
public event EventHandler < UnknownMessageReceivedEventArgs > UnknownMessageReceived ;
protected ServiceHostBase ( )
{
TraceUtility . SetEtwProviderId ( ) ;
this . baseAddresses = new UriSchemeKeyedCollection ( this . ThisLock ) ;
this . channelDispatchers = new ChannelDispatcherCollection ( this , this . ThisLock ) ;
this . extensions = new ExtensionCollection < ServiceHostBase > ( this , this . ThisLock ) ;
this . instances = new InstanceContextManager ( this . ThisLock ) ;
this . serviceThrottle = new ServiceThrottle ( this ) ;
this . TraceOpenAndClose = true ;
this . Faulted + = new EventHandler ( OnServiceHostFaulted ) ;
}
internal EventTraceActivity EventTraceActivity
{
get
{
if ( this . eventTraceActivity = = null )
{
this . eventTraceActivity = new EventTraceActivity ( ) ;
}
return eventTraceActivity ;
}
}
public ServiceAuthorizationBehavior Authorization
{
get
{
if ( this . Description = = null )
{
return null ;
}
else if ( this . State = = CommunicationState . Created | | this . State = = CommunicationState . Opening )
{
return EnsureAuthorization ( this . Description ) ;
}
else
{
return this . readOnlyAuthorization ;
}
}
}
public ServiceAuthenticationBehavior Authentication
{
get
{
if ( this . Description = = null )
{
return null ;
}
else if ( this . State = = CommunicationState . Created | | this . State = = CommunicationState . Opening )
{
return EnsureAuthentication ( this . Description ) ;
}
else
{
return this . readOnlyAuthentication ;
}
}
}
public ReadOnlyCollection < Uri > BaseAddresses
{
get
{
externalBaseAddresses = new ReadOnlyCollection < Uri > ( new List < Uri > ( this . baseAddresses ) ) ;
return externalBaseAddresses ;
}
}
public ChannelDispatcherCollection ChannelDispatchers
{
get { return this . channelDispatchers ; }
}
public TimeSpan CloseTimeout
{
get { return this . closeTimeout ; }
set
{
if ( value < TimeSpan . Zero )
{
string message = SR . GetString ( SR . SFxTimeoutOutOfRange0 ) ;
throw DiagnosticUtility . ExceptionUtility . ThrowHelperError ( new ArgumentOutOfRangeException ( "value" , message ) ) ;
}
if ( TimeoutHelper . IsTooLarge ( value ) )
{
throw DiagnosticUtility . ExceptionUtility . ThrowHelperError ( new ArgumentOutOfRangeException ( "value" , SR . GetString ( SR . SFxTimeoutOutOfRangeTooBig ) ) ) ;
}
lock ( this . ThisLock )
{
this . ThrowIfClosedOrOpened ( ) ;
this . closeTimeout = value ;
}
}
}
internal ServicePerformanceCountersBase Counters
{
get
{
return this . servicePerformanceCounters ;
}
set
{
this . servicePerformanceCounters = value ;
this . serviceThrottle . SetServicePerformanceCounters ( this . servicePerformanceCounters ) ;
}
}
internal DefaultPerformanceCounters DefaultCounters
{
get
{
return this . defaultPerformanceCounters ;
}
set
{
this . defaultPerformanceCounters = value ;
}
}
public ServiceCredentials Credentials
{
get
{
if ( this . Description = = null )
{
return null ;
}
else if ( this . State = = CommunicationState . Created | | this . State = = CommunicationState . Opening )
{
return EnsureCredentials ( this . Description ) ;
}
else
{
return this . readOnlyCredentials ;
}
}
}
protected override TimeSpan DefaultCloseTimeout
{
get { return this . CloseTimeout ; }
}
protected override TimeSpan DefaultOpenTimeout
{
get { return this . OpenTimeout ; }
}
public ServiceDescription Description
{
get { return this . description ; }
}
public IExtensionCollection < ServiceHostBase > Extensions
{
get { return this . extensions ; }
}
protected internal IDictionary < string , ContractDescription > ImplementedContracts
{
get { return this . implementedContracts ; }
}
internal UriSchemeKeyedCollection InternalBaseAddresses
{
get { return this . baseAddresses ; }
}
public int ManualFlowControlLimit
{
get { return this . ServiceThrottle . ManualFlowControlLimit ; }
set { this . ServiceThrottle . ManualFlowControlLimit = value ; }
}
public TimeSpan OpenTimeout
{
get { return this . openTimeout ; }
set
{
if ( value < TimeSpan . Zero )
{
string message = SR . GetString ( SR . SFxTimeoutOutOfRange0 ) ;
throw DiagnosticUtility . ExceptionUtility . ThrowHelperError ( new ArgumentOutOfRangeException ( "value" , message ) ) ;
}
if ( TimeoutHelper . IsTooLarge ( value ) )
{
throw DiagnosticUtility . ExceptionUtility . ThrowHelperError ( new ArgumentOutOfRangeException ( "value" , SR . GetString ( SR . SFxTimeoutOutOfRangeTooBig ) ) ) ;
}
lock ( this . ThisLock )
{
this . ThrowIfClosedOrOpened ( ) ;
this . openTimeout = value ;
}
}
}
internal ServiceThrottle ServiceThrottle
{
get
{
return this . serviceThrottle ;
}
}
internal virtual object DisposableInstance
{
get
{
return null ;
}
}
internal Dictionary < DispatcherBuilder . ListenUriInfo , Collection < ServiceEndpoint > > EndpointsByListenUriInfo
{
get
{
if ( this . endpointsByListenUriInfo = = null )
{
this . endpointsByListenUriInfo = this . GetEndpointsByListenUriInfo ( ) ;
}
return this . endpointsByListenUriInfo ;
}
}
Dictionary < DispatcherBuilder . ListenUriInfo , Collection < ServiceEndpoint > > GetEndpointsByListenUriInfo ( )
{
Dictionary < DispatcherBuilder . ListenUriInfo , Collection < ServiceEndpoint > > endpointDictionary = new Dictionary < DispatcherBuilder . ListenUriInfo , Collection < ServiceEndpoint > > ( ) ;
foreach ( ServiceEndpoint endpoint in this . Description . Endpoints )
{
DispatcherBuilder . ListenUriInfo listenUriInfo = DispatcherBuilder . GetListenUriInfoForEndpoint ( this , endpoint ) ;
if ( ! endpointDictionary . ContainsKey ( listenUriInfo ) )
{
endpointDictionary . Add ( listenUriInfo , new Collection < ServiceEndpoint > ( ) ) ;
}
endpointDictionary [ listenUriInfo ] . Add ( endpoint ) ;
}
return endpointDictionary ;
}
protected void AddBaseAddress ( Uri baseAddress )
{
if ( this . initializeDescriptionHasFinished )
{
throw DiagnosticUtility . ExceptionUtility . ThrowHelperError ( new InvalidOperationException (
SR . GetString ( SR . SFxCannotCallAddBaseAddress ) ) ) ;
}
this . baseAddresses . Add ( baseAddress ) ;
}
public ServiceEndpoint AddServiceEndpoint ( string implementedContract , Binding binding , string address )
{
return this . AddServiceEndpoint ( implementedContract , binding , address , ( Uri ) null ) ;
}
public ServiceEndpoint AddServiceEndpoint ( string implementedContract , Binding binding , string address , Uri listenUri )
{
if ( address = = null )
{
throw DiagnosticUtility . ExceptionUtility . ThrowHelperError ( new ArgumentNullException ( "address" ) ) ;
}
ServiceEndpoint endpoint = this . AddServiceEndpoint ( implementedContract , binding , new Uri ( address , UriKind . RelativeOrAbsolute ) ) ;
if ( listenUri ! = null )
{
endpoint . UnresolvedListenUri = listenUri ;
listenUri = MakeAbsoluteUri ( listenUri , binding ) ;
endpoint . ListenUri = listenUri ;
}
return endpoint ;
}
public ServiceEndpoint AddServiceEndpoint ( string implementedContract , Binding binding , Uri address )
{
return this . AddServiceEndpoint ( implementedContract , binding , address , ( Uri ) null ) ;
}
public ServiceEndpoint AddServiceEndpoint ( string implementedContract , Binding binding , Uri address , Uri listenUri )
{
if ( address = = null )
{
throw DiagnosticUtility . ExceptionUtility . ThrowHelperError ( new ArgumentNullException ( "address" ) ) ;
}
if ( binding = = null )
{
throw DiagnosticUtility . ExceptionUtility . ThrowHelperError ( new ArgumentNullException ( "binding" ) ) ;
}
if ( implementedContract = = null )
{
throw DiagnosticUtility . ExceptionUtility . ThrowHelperError ( new ArgumentNullException ( "implementedContract" ) ) ;
}
if ( this . State ! = CommunicationState . Created & & this . State ! = CommunicationState . Opening )
{
throw DiagnosticUtility . ExceptionUtility . ThrowHelperError ( new InvalidOperationException ( SR . GetString ( SR . SFxServiceHostBaseCannotAddEndpointAfterOpen ) ) ) ;
}
if ( this . Description = = null )
{
throw DiagnosticUtility . ExceptionUtility . ThrowHelperError ( new InvalidOperationException ( SR . GetString ( SR . SFxServiceHostBaseCannotAddEndpointWithoutDescription ) ) ) ;
}
Uri via = this . MakeAbsoluteUri ( address , binding ) ;
ConfigLoader configLoader = new ConfigLoader ( GetContractResolver ( this . implementedContracts ) ) ;
ContractDescription contract = configLoader . LookupContract ( implementedContract , this . Description . Name ) ;
ServiceEndpoint serviceEndpoint = new ServiceEndpoint ( contract , binding , new EndpointAddress ( via ) ) ;
this . Description . Endpoints . Add ( serviceEndpoint ) ;
serviceEndpoint . UnresolvedAddress = address ;
if ( listenUri ! = null )
{
serviceEndpoint . UnresolvedListenUri = listenUri ;
listenUri = MakeAbsoluteUri ( listenUri , binding ) ;
serviceEndpoint . ListenUri = listenUri ;
}
return serviceEndpoint ;
}
public virtual void AddServiceEndpoint ( ServiceEndpoint endpoint )
{
if ( endpoint = = null )
{
throw DiagnosticUtility . ExceptionUtility . ThrowHelperArgumentNull ( "endpoint" ) ;
}
if ( this . State ! = CommunicationState . Created & & this . State ! = CommunicationState . Opening )
{
throw DiagnosticUtility . ExceptionUtility . ThrowHelperError ( new InvalidOperationException ( SR . GetString ( SR . SFxServiceHostBaseCannotAddEndpointAfterOpen ) ) ) ;
}
if ( this . Description = = null )
{
throw DiagnosticUtility . ExceptionUtility . ThrowHelperError ( new InvalidOperationException ( SR . GetString ( SR . SFxServiceHostBaseCannotAddEndpointWithoutDescription ) ) ) ;
}
if ( endpoint . Address = = null )
{
throw DiagnosticUtility . ExceptionUtility . ThrowHelperArgument ( SR . GetString ( SR . SFxEndpointAddressNotSpecified ) ) ;
}
if ( endpoint . Contract = = null )
{
throw DiagnosticUtility . ExceptionUtility . ThrowHelperArgument ( SR . GetString ( SR . SFxEndpointContractNotSpecified ) ) ;
}
if ( endpoint . Binding = = null )
{
throw DiagnosticUtility . ExceptionUtility . ThrowHelperArgument ( SR . GetString ( SR . SFxEndpointBindingNotSpecified ) ) ;
}
if ( ! endpoint . IsSystemEndpoint | | endpoint . Contract . ContractType = = typeof ( IMetadataExchange ) )
{
ConfigLoader loader = new ConfigLoader ( GetContractResolver ( this . implementedContracts ) ) ;
loader . LookupContract ( endpoint . Contract . ConfigurationName , this . Description . Name ) ;
}
this . Description . Endpoints . Add ( endpoint ) ;
}
public void SetEndpointAddress ( ServiceEndpoint endpoint , string relativeAddress )
{
if ( endpoint = = null )
{
throw DiagnosticUtility . ExceptionUtility . ThrowHelperArgumentNull ( "endpoint" ) ;
}
if ( relativeAddress = = null )
{
throw DiagnosticUtility . ExceptionUtility . ThrowHelperArgumentNull ( "relativeAddress" ) ;
}
if ( endpoint . Binding = = null )
{
throw DiagnosticUtility . ExceptionUtility . ThrowHelperArgument ( SR . GetString ( SR . SFxEndpointBindingNotSpecified ) ) ;
}
Uri absoluteUri = MakeAbsoluteUri ( new Uri ( relativeAddress , UriKind . Relative ) , endpoint . Binding ) ;
endpoint . Address = new EndpointAddress ( absoluteUri ) ;
}
internal Uri MakeAbsoluteUri ( Uri relativeOrAbsoluteUri , Binding binding )
{
return MakeAbsoluteUri ( relativeOrAbsoluteUri , binding , this . InternalBaseAddresses ) ;
}
internal static Uri MakeAbsoluteUri ( Uri relativeOrAbsoluteUri , Binding binding , UriSchemeKeyedCollection baseAddresses )
{
Uri result = relativeOrAbsoluteUri ;
if ( ! result . IsAbsoluteUri )
{
if ( binding . Scheme = = string . Empty )
{
throw DiagnosticUtility . ExceptionUtility . ThrowHelperError ( new InvalidOperationException ( SR . GetString ( SR . SFxCustomBindingWithoutTransport ) ) ) ;
}
result = GetVia ( binding . Scheme , result , baseAddresses ) ;
if ( result = = null )
{
throw DiagnosticUtility . ExceptionUtility . ThrowHelperError ( new InvalidOperationException ( SR . GetString ( SR . SFxEndpointNoMatchingScheme , binding . Scheme , binding . Name , GetBaseAddressSchemes ( baseAddresses ) ) ) ) ;
}
}
return result ;
}
protected virtual void ApplyConfiguration ( )
{
if ( this . Description = = null )
{
throw DiagnosticUtility . ExceptionUtility . ThrowHelperError ( new InvalidOperationException ( SR . GetString ( SR . SFxServiceHostBaseCannotApplyConfigurationWithoutDescription ) ) ) ;
}
ConfigLoader configLoader = new ConfigLoader ( GetContractResolver ( implementedContracts ) ) ;
// Call the overload of LoadConfigurationSectionInternal which looks up the serviceElement from ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None)
LoadConfigurationSectionInternal ( configLoader , this . Description , this . Description . ConfigurationName ) ;
EnsureAuthenticationAuthorizationDebug ( this . Description ) ;
}
internal void EnsureAuthenticationAuthorizationDebug ( ServiceDescription description )
{
EnsureAuthentication ( description ) ;
EnsureAuthorization ( description ) ;
EnsureDebug ( description ) ;
}
public virtual ReadOnlyCollection < ServiceEndpoint > AddDefaultEndpoints ( )
{
List < ServiceEndpoint > defaultEndpoints = new List < ServiceEndpoint > ( ) ;
foreach ( Uri baseAddress in this . InternalBaseAddresses )
{
ProtocolMappingItem protocolMappingItem = ConfigLoader . LookupProtocolMapping ( baseAddress . Scheme ) ;
if ( protocolMappingItem ! = null )
{
Binding defaultBinding = ConfigLoader . LookupBinding ( protocolMappingItem . Binding , protocolMappingItem . BindingConfiguration ) ;
if ( defaultBinding ! = null )
{
AddDefaultEndpoints ( defaultBinding , defaultEndpoints ) ;
}
else
{
throw DiagnosticUtility . ExceptionUtility . ThrowHelperError ( new Exception ( SR . GetString ( SR . BindingProtocolMappingNotDefined , baseAddress . Scheme ) ) ) ;
}
}
}
if ( DiagnosticUtility . ShouldTraceInformation & & defaultEndpoints . Count > 0 )
{
Dictionary < string , string > dictionary = new Dictionary < string , string > ( ) ;
dictionary [ "ServiceConfigurationName" ] = this . description . ConfigurationName ;
TraceUtility . TraceEvent ( TraceEventType . Information , TraceCode . DefaultEndpointsAdded , SR . GetString ( SR . TraceCodeDefaultEndpointsAdded ) , new DictionaryTraceRecord ( dictionary ) ) ;
}
return new ReadOnlyCollection < ServiceEndpoint > ( defaultEndpoints ) ;
}
internal virtual void AddDefaultEndpoints ( Binding defaultBinding , List < ServiceEndpoint > defaultEndpoints )
{
}
internal virtual void BindInstance ( InstanceContext instance )
{
this . instances . Add ( instance ) ;
if ( null ! = this . servicePerformanceCounters )
{
lock ( this . ThisLock )
{
if ( null ! = this . servicePerformanceCounters )
{
this . servicePerformanceCounters . ServiceInstanceCreated ( ) ;
}
}
}
}
void IDisposable . Dispose ( )
{
Close ( ) ;
}
protected abstract ServiceDescription CreateDescription ( out IDictionary < string , ContractDescription > implementedContracts ) ;
protected virtual void InitializeRuntime ( )
{
if ( this . Description = = null )
{
throw DiagnosticUtility . ExceptionUtility . ThrowHelperError ( new InvalidOperationException ( SR . GetString ( SR . SFxServiceHostBaseCannotInitializeRuntimeWithoutDescription ) ) ) ;
}
if ( this . Description . Endpoints . Count = = 0 )
{
this . AddDefaultEndpoints ( ) ;
}
this . EnsureAuthenticationSchemes ( ) ;
DispatcherBuilder dispatcherBuilder = new DispatcherBuilder ( ) ;
dispatcherBuilder . InitializeServiceHost ( description , this ) ;
SecurityValidationBehavior . Instance . AfterBuildTimeValidation ( description ) ;
}
internal virtual void AfterInitializeRuntime ( TimeSpan timeout )
{
}
internal virtual IAsyncResult BeginAfterInitializeRuntime ( TimeSpan timeout , AsyncCallback callback , object state )
{
return new CompletedAsyncResult ( callback , state ) ;
}
internal virtual void EndAfterInitializeRuntime ( IAsyncResult result )
{
CompletedAsyncResult . End ( result ) ;
}
ServiceAuthorizationBehavior EnsureAuthorization ( ServiceDescription description )
{
Fx . Assert ( this . State = = CommunicationState . Created | | this . State = = CommunicationState . Opening , "" ) ;
ServiceAuthorizationBehavior a = description . Behaviors . Find < ServiceAuthorizationBehavior > ( ) ;
if ( a = = null )
{
a = new ServiceAuthorizationBehavior ( ) ;
description . Behaviors . Add ( a ) ;
}
return a ;
}
ServiceAuthenticationBehavior EnsureAuthentication ( ServiceDescription description )
{
Fx . Assert ( this . State = = CommunicationState . Created | | this . State = = CommunicationState . Opening , "" ) ;
ServiceAuthenticationBehavior a = description . Behaviors . Find < ServiceAuthenticationBehavior > ( ) ;
if ( a = = null )
{
a = new ServiceAuthenticationBehavior ( ) ;
description . Behaviors . Add ( a ) ;
}
return a ;
}
ServiceDebugBehavior EnsureDebug ( ServiceDescription description )
{
Fx . Assert ( this . State = = CommunicationState . Created | | this . State = = CommunicationState . Opening , "" ) ;
ServiceDebugBehavior m = description . Behaviors . Find < ServiceDebugBehavior > ( ) ;
if ( m = = null )
{
m = new ServiceDebugBehavior ( ) ;
description . Behaviors . Add ( m ) ;
}
return m ;
}
ServiceCredentials EnsureCredentials ( ServiceDescription description )
{
Fx . Assert ( this . State = = CommunicationState . Created | | this . State = = CommunicationState . Opening , "" ) ;
ServiceCredentials c = description . Behaviors . Find < ServiceCredentials > ( ) ;
if ( c = = null )
{
c = new ServiceCredentials ( ) ;
description . Behaviors . Add ( c ) ;
}
return c ;
}
internal void FaultInternal ( )
{
this . Fault ( ) ;
}
internal string GetBaseAddressSchemes ( )
{
return GetBaseAddressSchemes ( baseAddresses ) ;
}
internal static String GetBaseAddressSchemes ( UriSchemeKeyedCollection uriSchemeKeyedCollection )
{
StringBuilder buffer = new StringBuilder ( ) ;
bool firstScheme = true ;
foreach ( Uri address in uriSchemeKeyedCollection )
{
if ( firstScheme )
{
buffer . Append ( address . Scheme ) ;
firstScheme = false ;
}
else
{
buffer . Append ( CultureInfo . CurrentCulture . TextInfo . ListSeparator ) . Append ( address . Scheme ) ;
}
}
return buffer . ToString ( ) ;
}
internal BindingParameterCollection GetBindingParameters ( )
{
return DispatcherBuilder . GetBindingParameters ( this , new Collection < ServiceEndpoint > ( ) ) ;
}
internal BindingParameterCollection GetBindingParameters ( ServiceEndpoint inputEndpoint )
{
Collection < ServiceEndpoint > endpoints ;
if ( inputEndpoint = = null )
{
endpoints = new Collection < ServiceEndpoint > ( ) ;
}
else if ( ! this . EndpointsByListenUriInfo . TryGetValue ( DispatcherBuilder . GetListenUriInfoForEndpoint ( this , inputEndpoint ) , out endpoints ) | | ! endpoints . Contains ( inputEndpoint ) )
{
endpoints = new Collection < ServiceEndpoint > ( ) ;
endpoints . Add ( inputEndpoint ) ;
}
return DispatcherBuilder . GetBindingParameters ( this , endpoints ) ;
}
internal BindingParameterCollection GetBindingParameters ( Collection < ServiceEndpoint > endpoints )
{
return DispatcherBuilder . GetBindingParameters ( this , endpoints ) ;
}
internal ReadOnlyCollection < InstanceContext > GetInstanceContexts ( )
{
return Array . AsReadOnly < InstanceContext > ( this . instances . ToArray ( ) ) ;
}
internal virtual IContractResolver GetContractResolver ( IDictionary < string , ContractDescription > implementedContracts )
{
ServiceAndBehaviorsContractResolver resolver = new ServiceAndBehaviorsContractResolver ( new ImplementedContractsContractResolver ( implementedContracts ) ) ;
resolver . AddBehaviorContractsToResolver ( this . description = = null ? null : this . description . Behaviors ) ;
return resolver ;
}
internal static Uri GetUri ( Uri baseUri , Uri relativeUri )
{
return GetUri ( baseUri , relativeUri . OriginalString ) ;
}
internal static Uri GetUri ( Uri baseUri , string path )
{
if ( path . StartsWith ( "/" , StringComparison . Ordinal ) | | path . StartsWith ( "\\" , StringComparison . Ordinal ) )
{
int i = 1 ;
for ( ; i < path . Length ; + + i )
{
if ( path [ i ] ! = '/' & & path [ i ] ! = '\\' )
{
break ;
}
}
path = path . Substring ( i ) ;
}
// VSWhidbey#541152: new Uri(Uri, string.Empty) is broken
if ( path . Length = = 0 )
return baseUri ;
if ( ! baseUri . AbsoluteUri . EndsWith ( "/" , StringComparison . Ordinal ) )
{
baseUri = new Uri ( baseUri . AbsoluteUri + "/" ) ;
}
return new Uri ( baseUri , path ) ;
}
internal Uri GetVia ( string scheme , Uri address )
{
return ServiceHost . GetVia ( scheme , address , InternalBaseAddresses ) ;
}
internal static Uri GetVia ( string scheme , Uri address , UriSchemeKeyedCollection baseAddresses )
{
Uri via = address ;
if ( ! via . IsAbsoluteUri )
{
if ( ! baseAddresses . Contains ( scheme ) )
{
return null ;
}
via = GetUri ( baseAddresses [ scheme ] , address ) ;
}
return via ;
}
public int IncrementManualFlowControlLimit ( int incrementBy )
{
return this . ServiceThrottle . IncrementManualFlowControlLimit ( incrementBy ) ;
}
protected void InitializeDescription ( UriSchemeKeyedCollection baseAddresses )
{
foreach ( Uri baseAddress in baseAddresses )
{
this . baseAddresses . Add ( baseAddress ) ;
}
IDictionary < string , ContractDescription > implementedContracts = null ;
ServiceDescription description = CreateDescription ( out implementedContracts ) ;
this . description = description ;
this . implementedContracts = implementedContracts ;
ApplyConfiguration ( ) ;
this . initializeDescriptionHasFinished = true ;
}
protected void LoadConfigurationSection ( ServiceElement serviceSection )
{
if ( serviceSection = = null )
{
throw DiagnosticUtility . ExceptionUtility . ThrowHelperArgumentNull ( "serviceSection" ) ;
}
if ( this . Description = = null )
{
throw DiagnosticUtility . ExceptionUtility . ThrowHelperError ( new InvalidOperationException ( SR . GetString ( SR . SFxServiceHostBaseCannotLoadConfigurationSectionWithoutDescription ) ) ) ;
}
ConfigLoader configLoader = new ConfigLoader ( GetContractResolver ( this . ImplementedContracts ) ) ;
LoadConfigurationSectionInternal ( configLoader , this . Description , serviceSection ) ;
}
internal void LoadConfigurationSectionHelper ( Uri baseAddress )
{
this . AddBaseAddress ( baseAddress ) ;
}
[ Fx . Tag . SecurityNote ( Critical = "Calls LookupService which is critical." ,
Safe = "Doesn't leak ServiceElement out of SecurityCritical code." ) ]
[SecuritySafeCritical]
void LoadConfigurationSectionInternal ( ConfigLoader configLoader , ServiceDescription description , string configurationName )
{
ServiceElement serviceSection = configLoader . LookupService ( configurationName ) ;
LoadConfigurationSectionInternal ( configLoader , description , serviceSection ) ;
}
[ Fx . Tag . SecurityNote ( Critical = "Handles a ServiceElement, which should not be leaked out of SecurityCritical code." ,
Safe = "Doesn't leak ServiceElement out of SecurityCritical code." ) ]
[SecuritySafeCritical]
void LoadConfigurationSectionInternal ( ConfigLoader configLoader , ServiceDescription description , ServiceElement serviceSection )
{
// caller must validate arguments before calling
configLoader . LoadServiceDescription ( this , description , serviceSection , this . LoadConfigurationSectionHelper ) ;
}
protected override void OnAbort ( )
{
this . instances . Abort ( ) ;
foreach ( ChannelDispatcherBase dispatcher in this . ChannelDispatchers )
{
if ( dispatcher . Listener ! = null )
{
dispatcher . Listener . Abort ( ) ;
}
dispatcher . Abort ( ) ;
}
ThreadTrace . StopTracing ( ) ;
}
internal void OnAddChannelDispatcher ( ChannelDispatcherBase channelDispatcher )
{
lock ( this . ThisLock )
{
this . ThrowIfClosedOrOpened ( ) ;
channelDispatcher . AttachInternal ( this ) ;
channelDispatcher . Faulted + = new EventHandler ( OnChannelDispatcherFaulted ) ;
}
}
protected override IAsyncResult OnBeginClose ( TimeSpan timeout , AsyncCallback callback , object state )
{
return new CloseAsyncResult ( timeout , callback , state , this ) ;
}
void OnBeginOpen ( )
{
this . TraceServiceHostOpenStart ( ) ;
this . TraceBaseAddresses ( ) ;
MessageLogger . EnsureInitialized ( ) ; //force config validation instead of waiting for the first message exchange
InitializeRuntime ( ) ;
}
protected override IAsyncResult OnBeginOpen ( TimeSpan timeout , AsyncCallback callback , object state )
{
this . OnBeginOpen ( ) ;
return new OpenAsyncResult ( this , timeout , callback , state ) ;
}
IAsyncResult BeginOpenChannelDispatchers ( TimeSpan timeout , AsyncCallback callback , object state )
{
return new OpenCollectionAsyncResult ( timeout , callback , state , this . SnapshotChannelDispatchers ( ) ) ;
}
protected override void OnClose ( TimeSpan timeout )
{
try
{
TimeoutHelper timeoutHelper = new TimeoutHelper ( timeout ) ;
if ( ManagementExtension . IsEnabled & & null ! = this . Description )
{
ManagementExtension . OnServiceClosing ( this ) ;
}
for ( int i = 0 ; i < this . ChannelDispatchers . Count ; i + + )
{
ChannelDispatcherBase dispatcher = this . ChannelDispatchers [ i ] ;
if ( dispatcher . Listener ! = null )
{
dispatcher . Listener . Close ( timeoutHelper . RemainingTime ( ) ) ;
}
}
for ( int i = 0 ; i < this . ChannelDispatchers . Count ; i + + )
{
ChannelDispatcherBase dispatcher = this . ChannelDispatchers [ i ] ;
dispatcher . CloseInput ( timeoutHelper . RemainingTime ( ) ) ;
}
// Wait for existing work to complete
this . instances . CloseInput ( timeoutHelper . RemainingTime ( ) ) ;
// Close instances (closes contexts/channels)
this . instances . Close ( timeoutHelper . RemainingTime ( ) ) ;
// Close dispatchers
for ( int i = 0 ; i < this . ChannelDispatchers . Count ; i + + )
{
ChannelDispatcherBase dispatcher = this . ChannelDispatchers [ i ] ;
dispatcher . Close ( timeoutHelper . RemainingTime ( ) ) ;
}
this . ReleasePerformanceCounters ( ) ;
this . TraceBaseAddresses ( ) ;
ThreadTrace . StopTracing ( ) ;
}
catch ( TimeoutException e )
{
if ( TD . CloseTimeoutIsEnabled ( ) )
{
TD . CloseTimeout ( SR . GetString ( SR . TraceCodeServiceHostTimeoutOnClose ) ) ;
}
if ( DiagnosticUtility . ShouldTraceWarning )
{
TraceUtility . TraceEvent ( TraceEventType . Warning , TraceCode . ServiceHostTimeoutOnClose , SR . GetString ( SR . TraceCodeServiceHostTimeoutOnClose ) , this , e ) ;
}
this . Abort ( ) ;
}
}
protected override void OnClosed ( )
{
try
{
for ( int i = 0 ; i < this . ChannelDispatchers . Count ; i + + )
{
ChannelDispatcher dispatcher = this . ChannelDispatchers [ i ] as ChannelDispatcher ;
if ( dispatcher ! = null )
{
dispatcher . ReleasePerformanceCounters ( ) ;
}
}
}
finally
{
base . OnClosed ( ) ;
}
}
void TraceBaseAddresses ( )
{
if ( DiagnosticUtility . ShouldTraceInformation & & this . baseAddresses ! = null
& & this . baseAddresses . Count > 0 )
{
TraceUtility . TraceEvent ( TraceEventType . Information ,
TraceCode . ServiceHostBaseAddresses ,
SR . GetString ( SR . TraceCodeServiceHostBaseAddresses ) ,
new CollectionTraceRecord ( "BaseAddresses" , "Address" , this . baseAddresses ) ,
this , null ) ;
}
}
void TraceServiceHostOpenStart ( )
{
if ( TD . ServiceHostOpenStartIsEnabled ( ) )
{
TD . ServiceHostOpenStart ( this . EventTraceActivity ) ;
}
}
protected override void OnEndClose ( IAsyncResult result )
{
try
{
CloseAsyncResult . End ( result ) ;
this . TraceBaseAddresses ( ) ;
ThreadTrace . StopTracing ( ) ;
}
catch ( TimeoutException e )
{
if ( TD . CloseTimeoutIsEnabled ( ) )
{
TD . CloseTimeout ( SR . GetString ( SR . TraceCodeServiceHostTimeoutOnClose ) ) ;
}
if ( DiagnosticUtility . ShouldTraceWarning )
{
TraceUtility . TraceEvent ( TraceEventType . Warning , TraceCode . ServiceHostTimeoutOnClose ,
SR . GetString ( SR . TraceCodeServiceHostTimeoutOnClose ) , this , e ) ;
}
this . Abort ( ) ;
}
}
protected override void OnEndOpen ( IAsyncResult result )
{
OpenAsyncResult . End ( result ) ;
}
void EndOpenChannelDispatchers ( IAsyncResult result )
{
OpenCollectionAsyncResult . End ( result ) ;
}
void EnsureAuthenticationSchemes ( )
{
if ( this . Authentication = = null )
{
return ;
}
//Exit immediately when not hosted in IIS or if VirtualPathExtension is not set. VirtualPathExtension is used as a flag to indicate whether a ServiceHost
// is webhosted (WsDualHttpBinding-ChannelFactory is using HttpListener instead of IIS even when running in IIS)
if ( ! AspNetEnvironment . Enabled | |
this . Extensions . Find < VirtualPathExtension > ( ) = = null )
{
return ;
}
foreach ( ServiceEndpoint serviceEndpoint in this . Description . Endpoints )
{
if ( serviceEndpoint . Binding ! = null & &
serviceEndpoint . ListenUri ! = null & &
( "http" . Equals ( serviceEndpoint . ListenUri . Scheme , StringComparison . OrdinalIgnoreCase ) | | "https" . Equals ( serviceEndpoint . ListenUri . Scheme , StringComparison . OrdinalIgnoreCase ) ) & &
this . baseAddresses . Contains ( serviceEndpoint . ListenUri . Scheme ) )
{
HttpTransportBindingElement httpTransportBindingElement = serviceEndpoint . Binding . CreateBindingElements ( ) . Find < HttpTransportBindingElement > ( ) ;
if ( httpTransportBindingElement ! = null )
{
AuthenticationSchemes hostSupportedAuthenticationSchemes = AspNetEnvironment . Current . GetAuthenticationSchemes ( this . baseAddresses [ serviceEndpoint . ListenUri . Scheme ] ) ;
if ( hostSupportedAuthenticationSchemes ! = AuthenticationSchemes . None )
{
//If no authentication schemes are explicitly defined for the ServiceHost...
if ( this . Authentication . AuthenticationSchemes = = AuthenticationSchemes . None )
{
//Inherit authentication schemes from IIS
this . Authentication . AuthenticationSchemes = hostSupportedAuthenticationSchemes ;
}
else
{
// Build intersection between authenticationSchemes on the ServiceHost and in IIS
this . Authentication . AuthenticationSchemes & = hostSupportedAuthenticationSchemes ;
}
}
}
break ;
}
}
}
protected override void OnOpen ( TimeSpan timeout )
{
TimeoutHelper timeoutHelper = new TimeoutHelper ( timeout ) ;
this . OnBeginOpen ( ) ;
AfterInitializeRuntime ( timeoutHelper . RemainingTime ( ) ) ;
for ( int i = 0 ; i < this . ChannelDispatchers . Count ; i + + )
{
ChannelDispatcherBase dispatcher = this . ChannelDispatchers [ i ] ;
dispatcher . Open ( timeoutHelper . RemainingTime ( ) ) ;
}
}
protected override void OnOpened ( )
{
if ( this . Description ! = null )
{
ServiceCredentials c = description . Behaviors . Find < ServiceCredentials > ( ) ;
if ( c ! = null )
{
ServiceCredentials credentialsCopy = c . Clone ( ) ;
credentialsCopy . MakeReadOnly ( ) ;
this . readOnlyCredentials = credentialsCopy ;
}
ServiceAuthorizationBehavior authorization = description . Behaviors . Find < ServiceAuthorizationBehavior > ( ) ;
if ( authorization ! = null )
{
ServiceAuthorizationBehavior authorizationCopy = authorization . Clone ( ) ;
authorizationCopy . MakeReadOnly ( ) ;
this . readOnlyAuthorization = authorizationCopy ;
}
ServiceAuthenticationBehavior authentication = description . Behaviors . Find < ServiceAuthenticationBehavior > ( ) ;
if ( authentication ! = null )
{
ServiceAuthenticationBehavior authenticationCopy = authentication . Clone ( ) ;
authentication . MakeReadOnly ( ) ;
this . readOnlyAuthentication = authenticationCopy ;
}
if ( ManagementExtension . IsEnabled )
{
ManagementExtension . OnServiceOpened ( this ) ;
}
2016-11-10 13:04:39 +00:00
// log telemetry data for the current WCF service.
TelemetryTraceLogging . LogSeriveKPIData ( this . Description ) ;
2016-08-03 10:59:49 +00:00
}
base . OnOpened ( ) ;
if ( TD . ServiceHostOpenStopIsEnabled ( ) )
{
TD . ServiceHostOpenStop ( this . EventTraceActivity ) ;
}
}
internal void OnRemoveChannelDispatcher ( ChannelDispatcherBase channelDispatcher )
{
lock ( this . ThisLock )
{
this . ThrowIfClosedOrOpened ( ) ;
channelDispatcher . DetachInternal ( this ) ;
}
}
void OnChannelDispatcherFaulted ( object sender , EventArgs e )
{
this . Fault ( ) ;
}
void OnServiceHostFaulted ( object sender , EventArgs args )
{
if ( TD . ServiceHostFaultedIsEnabled ( ) )
{
TD . ServiceHostFaulted ( this . EventTraceActivity , this ) ;
}
if ( DiagnosticUtility . ShouldTraceWarning )
{
TraceUtility . TraceEvent ( TraceEventType . Warning , TraceCode . ServiceHostFaulted ,
SR . GetString ( SR . TraceCodeServiceHostFaulted ) , this ) ;
}
foreach ( ICommunicationObject channelDispatcher in this . SnapshotChannelDispatchers ( ) )
{
if ( channelDispatcher . State = = CommunicationState . Opened )
{
channelDispatcher . Abort ( ) ;
}
}
}
internal void RaiseUnknownMessageReceived ( Message message )
{
try
{
EventHandler < UnknownMessageReceivedEventArgs > handler = UnknownMessageReceived ;
if ( handler ! = null )
{
handler ( this , new UnknownMessageReceivedEventArgs ( message ) ) ;
}
}
catch ( Exception e )
{
if ( Fx . IsFatal ( e ) )
throw ;
throw DiagnosticUtility . ExceptionUtility . ThrowHelperCallback ( e ) ;
}
}
protected void ReleasePerformanceCounters ( )
{
if ( this . servicePerformanceCounters ! = null )
{
lock ( this . ThisLock )
{
if ( this . servicePerformanceCounters ! = null )
{
this . servicePerformanceCounters . Dispose ( ) ;
this . servicePerformanceCounters = null ;
}
}
}
if ( this . defaultPerformanceCounters ! = null )
{
lock ( this . ThisLock )
{
if ( this . defaultPerformanceCounters ! = null )
{
this . defaultPerformanceCounters . Dispose ( ) ;
this . defaultPerformanceCounters = null ;
}
}
}
}
ICommunicationObject [ ] SnapshotChannelDispatchers ( )
{
lock ( this . ThisLock )
{
ICommunicationObject [ ] array = new ICommunicationObject [ this . ChannelDispatchers . Count ] ;
for ( int i = 0 ; i < array . Length ; i + + )
{
array [ i ] = this . ChannelDispatchers [ i ] ;
}
return array ;
}
}
internal virtual void UnbindInstance ( InstanceContext instance )
{
this . instances . Remove ( instance ) ;
if ( null ! = this . servicePerformanceCounters )
{
lock ( this . ThisLock )
{
if ( null ! = this . servicePerformanceCounters )
{
this . servicePerformanceCounters . ServiceInstanceRemoved ( ) ;
}
}
}
}
internal void IncrementBusyCount ( )
{
if ( AspNetEnvironment . Enabled )
{
AspNetEnvironment . Current . IncrementBusyCount ( ) ;
Interlocked . Increment ( ref this . busyCount ) ;
}
EventHandler handler = this . BusyCountIncremented ;
if ( handler ! = null )
{
try
{
handler ( this , EventArgs . Empty ) ;
}
catch ( Exception exception )
{
if ( Fx . IsFatal ( exception ) )
throw ;
throw DiagnosticUtility . ExceptionUtility . ThrowHelperCallback ( exception ) ;
}
}
}
internal void DecrementBusyCount ( )
{
if ( AspNetEnvironment . Enabled )
{
Interlocked . Decrement ( ref this . busyCount ) ;
AspNetEnvironment . Current . DecrementBusyCount ( ) ;
}
}
internal int BusyCount
{
get
{
return this . busyCount ;
}
}
class OpenAsyncResult : AsyncResult
{
static AsyncCompletion handleEndAfterInitializeRuntime = new AsyncCompletion ( HandleEndAfterInitializeRuntime ) ;
static AsyncCompletion handleEndOpenChannelDispatchers = new AsyncCompletion ( HandleEndOpenChannelDispatchers ) ;
TimeoutHelper timeoutHelper ;
ServiceHostBase host ;
public OpenAsyncResult ( ServiceHostBase host , TimeSpan timeout , AsyncCallback callback , object state )
: base ( callback , state )
{
this . timeoutHelper = new TimeoutHelper ( timeout ) ;
this . host = host ;
if ( ProcessAfterInitializeRuntime ( ) )
{
Complete ( true ) ;
}
}
bool ProcessAfterInitializeRuntime ( )
{
IAsyncResult result = this . host . BeginAfterInitializeRuntime (
this . timeoutHelper . RemainingTime ( ) , PrepareAsyncCompletion ( handleEndAfterInitializeRuntime ) , this ) ;
return SyncContinue ( result ) ;
}
static bool HandleEndAfterInitializeRuntime ( IAsyncResult result )
{
OpenAsyncResult thisPtr = ( OpenAsyncResult ) result . AsyncState ;
thisPtr . host . EndAfterInitializeRuntime ( result ) ;
return thisPtr . ProcessOpenChannelDispatchers ( ) ;
}
bool ProcessOpenChannelDispatchers ( )
{
IAsyncResult result = this . host . BeginOpenChannelDispatchers (
this . timeoutHelper . RemainingTime ( ) , PrepareAsyncCompletion ( handleEndOpenChannelDispatchers ) , this ) ;
return SyncContinue ( result ) ;
}
static bool HandleEndOpenChannelDispatchers ( IAsyncResult result )
{
OpenAsyncResult thisPtr = ( OpenAsyncResult ) result . AsyncState ;
thisPtr . host . EndOpenChannelDispatchers ( result ) ;
return true ;
}
public static void End ( IAsyncResult result )
{
AsyncResult . End < OpenAsyncResult > ( result ) ;
}
}
class CloseAsyncResult : AsyncResult
{
ServiceHostBase serviceHost ;
TimeoutHelper timeoutHelper ;
public CloseAsyncResult ( TimeSpan timeout , AsyncCallback callback , object state , ServiceHostBase serviceHost )
: base ( callback , state )
{
this . timeoutHelper = new TimeoutHelper ( timeout ) ;
this . serviceHost = serviceHost ;
if ( ManagementExtension . IsEnabled & & null ! = serviceHost . Description )
{
ManagementExtension . OnServiceClosing ( serviceHost ) ;
}
this . CloseListeners ( true ) ;
}
void CloseListeners ( bool completedSynchronously )
{
List < ICommunicationObject > listeners = new List < ICommunicationObject > ( ) ;
for ( int i = 0 ; i < this . serviceHost . ChannelDispatchers . Count ; i + + )
{
if ( this . serviceHost . ChannelDispatchers [ i ] . Listener ! = null )
{
listeners . Add ( this . serviceHost . ChannelDispatchers [ i ] . Listener ) ;
}
}
AsyncCallback callback = Fx . ThunkCallback ( this . CloseListenersCallback ) ;
TimeSpan timeout = this . timeoutHelper . RemainingTime ( ) ;
Exception exception = null ;
IAsyncResult result = null ;
try
{
result = new CloseCollectionAsyncResult ( timeout , callback , this , listeners ) ;
}
catch ( Exception e )
{
if ( Fx . IsFatal ( e ) | | completedSynchronously )
{
throw ;
}
exception = e ;
}
if ( exception ! = null )
{
this . CallComplete ( completedSynchronously , exception ) ;
}
else if ( result . CompletedSynchronously )
{
this . FinishCloseListeners ( result , completedSynchronously ) ;
}
}
void CloseListenersCallback ( IAsyncResult result )
{
if ( ! result . CompletedSynchronously )
{
( ( CloseAsyncResult ) result . AsyncState ) . FinishCloseListeners ( result , false ) ;
}
}
void FinishCloseListeners ( IAsyncResult result , bool completedSynchronously )
{
Exception exception = null ;
try
{
CloseCollectionAsyncResult . End ( result ) ;
}
catch ( Exception e )
{
if ( Fx . IsFatal ( e ) | | completedSynchronously )
{
throw ;
}
exception = e ;
}
if ( exception ! = null )
{
this . CallComplete ( completedSynchronously , exception ) ;
}
else
{
this . CloseInput ( completedSynchronously ) ;
}
}
// Wait for existing work to complete
void CloseInput ( bool completedSynchronously )
{
AsyncCallback callback = Fx . ThunkCallback ( this . CloseInputCallback ) ;
Exception exception = null ;
IAsyncResult result = null ;
try
{
for ( int i = 0 ; i < this . serviceHost . ChannelDispatchers . Count ; i + + )
{
ChannelDispatcherBase dispatcher = this . serviceHost . ChannelDispatchers [ i ] ;
dispatcher . CloseInput ( this . timeoutHelper . RemainingTime ( ) ) ;
}
result = this . serviceHost . instances . BeginCloseInput ( this . timeoutHelper . RemainingTime ( ) , callback , this ) ;
}
catch ( Exception e )
{
if ( Fx . IsFatal ( e ) | | completedSynchronously )
{
throw ;
}
exception = e ;
}
if ( exception ! = null )
{
// Any exception during async processing causes this
// async callback to report the error and then relies on
// Abort to cleanup any unclosed channels or instance contexts.
FxTrace . Exception . AsWarning ( exception ) ;
this . CallComplete ( completedSynchronously , exception ) ;
}
else if ( result . CompletedSynchronously )
{
this . FinishCloseInput ( result , completedSynchronously ) ;
}
}
void CloseInputCallback ( IAsyncResult result )
{
if ( ! result . CompletedSynchronously )
{
( ( CloseAsyncResult ) result . AsyncState ) . FinishCloseInput ( result , false ) ;
}
}
void FinishCloseInput ( IAsyncResult result , bool completedSynchronously )
{
Exception exception = null ;
try
{
serviceHost . instances . EndCloseInput ( result ) ;
}
catch ( Exception e )
{
if ( Fx . IsFatal ( e ) | | completedSynchronously )
{
throw ;
}
exception = e ;
}
if ( exception ! = null )
{
this . CallComplete ( completedSynchronously , exception ) ;
}
else
{
this . CloseInstances ( completedSynchronously ) ;
}
}
// Close instances (closes contexts/channels)
void CloseInstances ( bool completedSynchronously )
{
AsyncCallback callback = Fx . ThunkCallback ( this . CloseInstancesCallback ) ;
TimeSpan timeout = this . timeoutHelper . RemainingTime ( ) ;
Exception exception = null ;
IAsyncResult result = null ;
try
{
result = this . serviceHost . instances . BeginClose ( timeout , callback , this ) ;
}
catch ( Exception e )
{
if ( Fx . IsFatal ( e ) | | completedSynchronously )
{
throw ;
}
exception = e ;
}
if ( exception ! = null )
{
this . CallComplete ( completedSynchronously , exception ) ;
}
else if ( result . CompletedSynchronously )
{
this . FinishCloseInstances ( result , completedSynchronously ) ;
}
}
void CloseInstancesCallback ( IAsyncResult result )
{
if ( ! result . CompletedSynchronously )
{
( ( CloseAsyncResult ) result . AsyncState ) . FinishCloseInstances ( result , false ) ;
}
}
void FinishCloseInstances ( IAsyncResult result , bool completedSynchronously )
{
Exception exception = null ;
try
{
this . serviceHost . instances . EndClose ( result ) ;
}
catch ( Exception e )
{
if ( Fx . IsFatal ( e ) | | completedSynchronously )
{
throw ;
}
exception = e ;
}
if ( exception ! = null )
{
this . CallComplete ( completedSynchronously , exception ) ;
}
else
{
this . CloseChannelDispatchers ( completedSynchronously ) ;
}
}
void CloseChannelDispatchers ( bool completedSynchronously )
{
IList < ICommunicationObject > channelDispatchers = this . serviceHost . SnapshotChannelDispatchers ( ) ;
AsyncCallback callback = Fx . ThunkCallback ( this . CloseChannelDispatchersCallback ) ;
TimeSpan timeout = this . timeoutHelper . RemainingTime ( ) ;
Exception exception = null ;
IAsyncResult result = null ;
try
{
result = new CloseCollectionAsyncResult ( timeout , callback , this , channelDispatchers ) ;
}
catch ( Exception e )
{
if ( Fx . IsFatal ( e ) | | completedSynchronously )
{
throw ;
}
exception = e ;
}
if ( exception ! = null )
{
this . CallComplete ( completedSynchronously , exception ) ;
}
else if ( result . CompletedSynchronously )
{
this . FinishCloseChannelDispatchers ( result , completedSynchronously ) ;
}
}
void CloseChannelDispatchersCallback ( IAsyncResult result )
{
if ( ! result . CompletedSynchronously )
{
( ( CloseAsyncResult ) result . AsyncState ) . FinishCloseChannelDispatchers ( result , false ) ;
}
}
void FinishCloseChannelDispatchers ( IAsyncResult result , bool completedSynchronously )
{
Exception exception = null ;
try
{
CloseCollectionAsyncResult . End ( result ) ;
}
catch ( Exception e )
{
if ( Fx . IsFatal ( e ) | | completedSynchronously )
{
throw ;
}
exception = e ;
}
this . CallComplete ( completedSynchronously , exception ) ;
}
void CallComplete ( bool completedSynchronously , Exception exception )
{
this . Complete ( completedSynchronously , exception ) ;
}
public static void End ( IAsyncResult result )
{
AsyncResult . End < CloseAsyncResult > ( result ) ;
}
}
class ImplementedContractsContractResolver : IContractResolver
{
IDictionary < string , ContractDescription > implementedContracts ;
public ImplementedContractsContractResolver ( IDictionary < string , ContractDescription > implementedContracts )
{
this . implementedContracts = implementedContracts ;
}
public ContractDescription ResolveContract ( string contractName )
{
return this . implementedContracts ! = null & & this . implementedContracts . ContainsKey ( contractName ) ? this . implementedContracts [ contractName ] : null ;
}
}
internal class ServiceAndBehaviorsContractResolver : IContractResolver
{
IContractResolver serviceResolver ;
Dictionary < string , ContractDescription > behaviorContracts ;
public Dictionary < string , ContractDescription > BehaviorContracts
{
get { return behaviorContracts ; }
}
public ServiceAndBehaviorsContractResolver ( IContractResolver serviceResolver )
{
this . serviceResolver = serviceResolver ;
behaviorContracts = new Dictionary < string , ContractDescription > ( ) ;
}
public ContractDescription ResolveContract ( string contractName )
{
ContractDescription contract = serviceResolver . ResolveContract ( contractName ) ;
if ( contract = = null )
{
contract = this . behaviorContracts . ContainsKey ( contractName ) ? this . behaviorContracts [ contractName ] : null ;
}
return contract ;
}
public void AddBehaviorContractsToResolver ( KeyedByTypeCollection < IServiceBehavior > behaviors )
{
// It would be nice to make this loop over all Behaviors... someday.
if ( behaviors ! = null & & behaviors . Contains ( typeof ( ServiceMetadataBehavior ) ) )
{
behaviors . Find < ServiceMetadataBehavior > ( ) . AddImplementedContracts ( this ) ;
}
}
}
}
public class ServiceHost : ServiceHostBase
{
object singletonInstance ;
Type serviceType ;
ReflectedContractCollection reflectedContracts ;
IDisposable disposableInstance ;
protected ServiceHost ( )
{
}
public ServiceHost ( Type serviceType , params Uri [ ] baseAddresses )
{
if ( serviceType = = null )
{
throw DiagnosticUtility . ExceptionUtility . ThrowHelperError ( new ArgumentNullException ( "serviceType" ) ) ;
}
this . serviceType = serviceType ;
using ( ServiceModelActivity activity = DiagnosticUtility . ShouldUseActivity ? ServiceModelActivity . CreateBoundedActivity ( ) : null )
{
if ( DiagnosticUtility . ShouldUseActivity )
{
ServiceModelActivity . Start ( activity , SR . GetString ( SR . ActivityConstructServiceHost , serviceType . FullName ) , ActivityType . Construct ) ;
}
InitializeDescription ( serviceType , new UriSchemeKeyedCollection ( baseAddresses ) ) ;
}
}
public ServiceHost ( object singletonInstance , params Uri [ ] baseAddresses )
{
if ( singletonInstance = = null )
{
throw new ArgumentNullException ( "singletonInstance" ) ;
}
this . singletonInstance = singletonInstance ;
this . serviceType = singletonInstance . GetType ( ) ;
using ( ServiceModelActivity activity = DiagnosticUtility . ShouldUseActivity ? ServiceModelActivity . CreateBoundedActivity ( ) : null )
{
if ( DiagnosticUtility . ShouldUseActivity )
{
ServiceModelActivity . Start ( activity , SR . GetString ( SR . ActivityConstructServiceHost , serviceType . FullName ) , ActivityType . Construct ) ;
}
InitializeDescription ( singletonInstance , new UriSchemeKeyedCollection ( baseAddresses ) ) ;
}
}
public object SingletonInstance
{
get
{
return this . singletonInstance ;
}
}
internal override object DisposableInstance
{
get
{
return this . disposableInstance ;
}
}
public ServiceEndpoint AddServiceEndpoint ( Type implementedContract , Binding binding , string address )
{
return this . AddServiceEndpoint ( implementedContract , binding , address , ( Uri ) null ) ;
}
public ServiceEndpoint AddServiceEndpoint ( Type implementedContract , Binding binding , string address , Uri listenUri )
{
if ( address = = null )
{
throw DiagnosticUtility . ExceptionUtility . ThrowHelperError ( new ArgumentNullException ( "address" ) ) ;
}
ServiceEndpoint endpoint = this . AddServiceEndpoint ( implementedContract , binding , new Uri ( address , UriKind . RelativeOrAbsolute ) ) ;
if ( listenUri ! = null )
{
listenUri = MakeAbsoluteUri ( listenUri , binding ) ;
endpoint . ListenUri = listenUri ;
}
return endpoint ;
}
public ServiceEndpoint AddServiceEndpoint ( Type implementedContract , Binding binding , Uri address )
{
return this . AddServiceEndpoint ( implementedContract , binding , address , ( Uri ) null ) ;
}
void ValidateContractType ( Type implementedContract , ReflectedAndBehaviorContractCollection reflectedAndBehaviorContracts )
{
if ( ! implementedContract . IsDefined ( typeof ( ServiceContractAttribute ) , false ) )
{
#pragma warning suppress 56506 // implementedContract is never null at this point
throw DiagnosticUtility . ExceptionUtility . ThrowHelperError ( new InvalidOperationException ( SR . GetString ( SR . SfxServiceContractAttributeNotFound , implementedContract . FullName ) ) ) ;
}
if ( ! reflectedAndBehaviorContracts . Contains ( implementedContract ) )
{
if ( implementedContract = = typeof ( IMetadataExchange ) )
#pragma warning suppress 56506 // ServiceType is never null at this point
throw DiagnosticUtility . ExceptionUtility . ThrowHelperError ( new InvalidOperationException ( SR . GetString ( SR . SfxReflectedContractKeyNotFoundIMetadataExchange , this . serviceType . FullName ) ) ) ;
else
#pragma warning suppress 56506 // implementedContract and ServiceType are never null at this point
throw DiagnosticUtility . ExceptionUtility . ThrowHelperError ( new InvalidOperationException ( SR . GetString ( SR . SfxReflectedContractKeyNotFound2 , implementedContract . FullName , this . serviceType . FullName ) ) ) ;
}
}
public ServiceEndpoint AddServiceEndpoint ( Type implementedContract , Binding binding , Uri address , Uri listenUri )
{
if ( implementedContract = = null )
{
throw DiagnosticUtility . ExceptionUtility . ThrowHelperError ( new ArgumentNullException ( "implementedContract" ) ) ;
}
if ( this . reflectedContracts = = null )
{
throw DiagnosticUtility . ExceptionUtility . ThrowHelperError ( new InvalidOperationException ( SR . GetString ( SR . SfxReflectedContractsNotInitialized1 , implementedContract . FullName ) ) ) ;
}
ReflectedAndBehaviorContractCollection reflectedAndBehaviorContracts = new ReflectedAndBehaviorContractCollection ( this . reflectedContracts , this . Description . Behaviors ) ;
ValidateContractType ( implementedContract , reflectedAndBehaviorContracts ) ;
ServiceEndpoint endpoint = AddServiceEndpoint ( reflectedAndBehaviorContracts . GetConfigKey ( implementedContract ) , binding , address ) ;
if ( listenUri ! = null )
{
listenUri = MakeAbsoluteUri ( listenUri , binding ) ;
endpoint . ListenUri = listenUri ;
}
return endpoint ;
}
internal override void AddDefaultEndpoints ( Binding defaultBinding , List < ServiceEndpoint > defaultEndpoints )
{
// don't generate endpoints for contracts that serve as the base type for other reflected contracts
List < ContractDescription > mostSpecificContracts = new List < ContractDescription > ( ) ;
for ( int i = 0 ; i < this . reflectedContracts . Count ; i + + )
{
bool addContractEndpoint = true ;
ContractDescription contract = this . reflectedContracts [ i ] ;
Type contractType = contract . ContractType ;
if ( contractType ! = null )
{
for ( int j = 0 ; j < this . reflectedContracts . Count ; j + + )
{
ContractDescription otherContract = this . reflectedContracts [ j ] ;
Type otherContractType = otherContract . ContractType ;
if ( i = = j | | otherContractType = = null )
{
continue ;
}
if ( contractType . IsAssignableFrom ( otherContractType ) )
{
addContractEndpoint = false ;
break ;
}
}
}
if ( addContractEndpoint )
{
mostSpecificContracts . Add ( contract ) ;
}
}
foreach ( ContractDescription contract in mostSpecificContracts )
{
ServiceEndpoint endpoint = AddServiceEndpoint ( contract . ConfigurationName , defaultBinding , string . Empty ) ;
ConfigLoader . LoadDefaultEndpointBehaviors ( endpoint ) ;
defaultEndpoints . Add ( endpoint ) ;
}
}
// Run static Configure method on service type if it exists, else load configuration from Web.config/App.config
protected override void ApplyConfiguration ( )
{
// Load from static Configure method if it exists with the right signature
Type serviceType = this . Description . ServiceType ;
if ( serviceType ! = null )
{
MethodInfo configure = GetConfigureMethod ( serviceType ) ;
if ( configure ! = null )
{
// load <host> config
ConfigLoader configLoader = new ConfigLoader ( GetContractResolver ( this . ImplementedContracts ) ) ;
LoadHostConfigurationInternal ( configLoader , this . Description , this . Description . ConfigurationName ) ;
// Invoke configure method for service
ServiceConfiguration configuration = new ServiceConfiguration ( this ) ;
InvokeConfigure ( configure , configuration ) ;
return ;
}
}
// else just load from Web.config/App.config
base . ApplyConfiguration ( ) ;
}
// Find the Configure method with the required signature, closest to serviceType in the type hierarchy
static MethodInfo GetConfigureMethod ( Type serviceType )
{
// Use recursion instead of BindingFlags.FlattenHierarchy because we require return type to be void
// base case: all Types are rooted in object eventually
if ( serviceType = = typeof ( object ) )
{
return null ;
}
// signature: "public static void Configure(ServiceConfiguration)"
MethodInfo configure = serviceType . GetMethod ( "Configure" , BindingFlags . Static | BindingFlags . Public , null , new [ ] { typeof ( ServiceConfiguration ) } , null ) ;
if ( configure ! = null & & configure . ReturnType = = typeof ( void ) )
{
return configure ;
}
else
{
return GetConfigureMethod ( serviceType . BaseType ) ;
}
}
static void InvokeConfigure ( MethodInfo configureMethod , ServiceConfiguration configuration )
{
Action < ServiceConfiguration > call = Delegate . CreateDelegate ( typeof ( Action < ServiceConfiguration > ) , configureMethod ) as Action < ServiceConfiguration > ;
call ( configuration ) ;
}
// called from ServiceConfiguration.LoadFromConfiguration()
internal void LoadFromConfiguration ( )
{
if ( this . Description = = null )
{
throw DiagnosticUtility . ExceptionUtility . ThrowHelperError ( new InvalidOperationException ( SR . GetString ( SR . SFxServiceHostBaseCannotApplyConfigurationWithoutDescription ) ) ) ;
}
ConfigLoader configLoader = new ConfigLoader ( GetContractResolver ( this . ImplementedContracts ) ) ;
// Call the overload of LoadConfigurationSectionInternal which looks up the serviceElement from ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None)
LoadConfigurationSectionExceptHostInternal ( configLoader , this . Description , this . Description . ConfigurationName ) ;
EnsureAuthenticationAuthorizationDebug ( this . Description ) ;
}
// called from ServiceConfiguration.LoadFromConfiguration(configuration)
internal void LoadFromConfiguration ( System . Configuration . Configuration configuration )
{
if ( this . Description = = null )
{
throw DiagnosticUtility . ExceptionUtility . ThrowHelperError ( new InvalidOperationException ( SR . GetString ( SR . SFxServiceHostBaseCannotApplyConfigurationWithoutDescription ) ) ) ;
}
ConfigLoader configLoader = new ConfigLoader ( GetContractResolver ( this . ImplementedContracts ) ) ;
// Look up the serviceElement explicitly on configuration, then call the overload of LoadConfigurationSectionInternal that loads the rest of the config from the same configuration as serviceElement
ServicesSection servicesSection = ( ServicesSection ) configuration . GetSection ( ConfigurationStrings . ServicesSectionPath ) ;
ServiceElement serviceElement = configLoader . LookupService ( this . Description . ConfigurationName , servicesSection ) ;
configLoader . LoadServiceDescription ( this , this . Description , serviceElement , this . LoadConfigurationSectionHelper , skipHost : true ) ;
EnsureAuthenticationAuthorizationDebug ( this . Description ) ;
}
// Load only "host" section within "service" tag
[ Fx . Tag . SecurityNote ( Critical = "Calls LookupService which is critical." ,
Safe = "Doesn't leak ServiceElement out of SecurityCritical code." ) ]
[SecuritySafeCritical]
void LoadHostConfigurationInternal ( ConfigLoader configLoader , ServiceDescription description , string configurationName )
{
ServiceElement serviceSection = configLoader . LookupService ( configurationName ) ;
if ( serviceSection ! = null )
{
configLoader . LoadHostConfig ( serviceSection , this , ( addr = > this . InternalBaseAddresses . Add ( addr ) ) ) ;
}
}
// Load service description for service from config, but skip "host" section within "service" tag
[ Fx . Tag . SecurityNote ( Critical = "Calls LookupService which is critical." ,
Safe = "Doesn't leak ServiceElement out of SecurityCritical code." ) ]
[SecuritySafeCritical]
void LoadConfigurationSectionExceptHostInternal ( ConfigLoader configLoader , ServiceDescription description , string configurationName )
{
ServiceElement serviceSection = configLoader . LookupService ( configurationName ) ;
configLoader . LoadServiceDescription ( this , description , serviceSection , this . LoadConfigurationSectionHelper , skipHost : true ) ;
}
internal override string CloseActivityName
{
get { return SR . GetString ( SR . ActivityCloseServiceHost , this . serviceType . FullName ) ; }
}
internal override string OpenActivityName
{
get { return SR . GetString ( SR . ActivityOpenServiceHost , this . serviceType . FullName ) ; }
}
protected override ServiceDescription CreateDescription ( out IDictionary < string , ContractDescription > implementedContracts )
{
if ( this . serviceType = = null )
{
throw DiagnosticUtility . ExceptionUtility . ThrowHelperError ( new InvalidOperationException ( SR . GetString ( SR . SFxServiceHostCannotCreateDescriptionWithoutServiceType ) ) ) ;
}
ServiceDescription description ;
if ( this . SingletonInstance ! = null )
{
description = ServiceDescription . GetService ( this . SingletonInstance ) ;
}
else
{
description = ServiceDescription . GetService ( this . serviceType ) ;
}
ServiceBehaviorAttribute serviceBehavior = description . Behaviors . Find < ServiceBehaviorAttribute > ( ) ;
object serviceInstanceUsedAsABehavior = serviceBehavior . GetWellKnownSingleton ( ) ;
if ( serviceInstanceUsedAsABehavior = = null )
{
serviceInstanceUsedAsABehavior = serviceBehavior . GetHiddenSingleton ( ) ;
this . disposableInstance = serviceInstanceUsedAsABehavior as IDisposable ;
}
if ( ( typeof ( IServiceBehavior ) . IsAssignableFrom ( this . serviceType ) | | typeof ( IContractBehavior ) . IsAssignableFrom ( this . serviceType ) )
& & serviceInstanceUsedAsABehavior = = null )
{
serviceInstanceUsedAsABehavior = ServiceDescription . CreateImplementation ( this . serviceType ) ;
this . disposableInstance = serviceInstanceUsedAsABehavior as IDisposable ;
}
if ( this . SingletonInstance = = null )
{
if ( serviceInstanceUsedAsABehavior is IServiceBehavior )
{
description . Behaviors . Add ( ( IServiceBehavior ) serviceInstanceUsedAsABehavior ) ;
}
}
ReflectedContractCollection reflectedContracts = new ReflectedContractCollection ( ) ;
List < Type > interfaces = ServiceReflector . GetInterfaces ( this . serviceType ) ;
for ( int i = 0 ; i < interfaces . Count ; i + + )
{
Type contractType = interfaces [ i ] ;
if ( ! reflectedContracts . Contains ( contractType ) )
{
ContractDescription contract = null ;
if ( serviceInstanceUsedAsABehavior ! = null )
{
contract = ContractDescription . GetContract ( contractType , serviceInstanceUsedAsABehavior ) ;
}
else
{
contract = ContractDescription . GetContract ( contractType , this . serviceType ) ;
}
reflectedContracts . Add ( contract ) ;
Collection < ContractDescription > inheritedContracts = contract . GetInheritedContracts ( ) ;
for ( int j = 0 ; j < inheritedContracts . Count ; j + + )
{
ContractDescription inheritedContract = inheritedContracts [ j ] ;
if ( ! reflectedContracts . Contains ( inheritedContract . ContractType ) )
{
reflectedContracts . Add ( inheritedContract ) ;
}
}
}
}
this . reflectedContracts = reflectedContracts ;
implementedContracts = reflectedContracts . ToImplementedContracts ( ) ;
return description ;
}
protected void InitializeDescription ( object singletonInstance , UriSchemeKeyedCollection baseAddresses )
{
if ( singletonInstance = = null )
{
throw new ArgumentNullException ( "singletonInstance" ) ;
}
this . singletonInstance = singletonInstance ;
InitializeDescription ( singletonInstance . GetType ( ) , baseAddresses ) ;
}
protected void InitializeDescription ( Type serviceType , UriSchemeKeyedCollection baseAddresses )
{
if ( serviceType = = null )
{
throw DiagnosticUtility . ExceptionUtility . ThrowHelperError ( new ArgumentNullException ( "serviceType" ) ) ;
}
this . serviceType = serviceType ;
base . InitializeDescription ( baseAddresses ) ;
}
protected override void OnClosed ( )
{
base . OnClosed ( ) ;
if ( this . disposableInstance ! = null )
{
this . disposableInstance . Dispose ( ) ;
}
}
class ReflectedContractCollection : KeyedCollection < Type , ContractDescription >
{
public ReflectedContractCollection ( )
: base ( null , 4 )
{
}
protected override Type GetKeyForItem ( ContractDescription item )
{
if ( item = = null )
throw DiagnosticUtility . ExceptionUtility . ThrowHelperArgumentNull ( "item" ) ;
return item . ContractType ;
}
public IDictionary < string , ContractDescription > ToImplementedContracts ( )
{
Dictionary < string , ContractDescription > implementedContracts = new Dictionary < string , ContractDescription > ( ) ;
foreach ( ContractDescription contract in this . Items )
{
implementedContracts . Add ( GetConfigKey ( contract ) , contract ) ;
}
return implementedContracts ;
}
internal static string GetConfigKey ( ContractDescription contract )
{
return contract . ConfigurationName ;
}
}
class ReflectedAndBehaviorContractCollection
{
ReflectedContractCollection reflectedContracts ;
KeyedByTypeCollection < IServiceBehavior > behaviors ;
public ReflectedAndBehaviorContractCollection ( ReflectedContractCollection reflectedContracts , KeyedByTypeCollection < IServiceBehavior > behaviors )
{
this . reflectedContracts = reflectedContracts ;
this . behaviors = behaviors ;
}
internal bool Contains ( Type implementedContract )
{
if ( this . reflectedContracts . Contains ( implementedContract ) )
{
return true ;
}
if ( this . behaviors . Contains ( typeof ( ServiceMetadataBehavior ) ) & & ServiceMetadataBehavior . IsMetadataImplementedType ( implementedContract ) )
{
return true ;
}
return false ;
}
internal string GetConfigKey ( Type implementedContract )
{
if ( this . reflectedContracts . Contains ( implementedContract ) )
{
return ReflectedContractCollection . GetConfigKey ( reflectedContracts [ implementedContract ] ) ;
}
if ( this . behaviors . Contains ( typeof ( ServiceMetadataBehavior ) ) & & ServiceMetadataBehavior . IsMetadataImplementedType ( implementedContract ) )
{
return ServiceMetadataBehavior . MexContractName ;
}
Fx . Assert ( "Calls to GetConfigKey are preceeded by calls to Contains." ) ;
#pragma warning suppress 56506 // implementedContract is never null at this point
throw DiagnosticUtility . ExceptionUtility . ThrowHelperError ( new InvalidOperationException ( SR . GetString ( SR . SfxReflectedContractKeyNotFound2 , implementedContract . FullName , string . Empty ) ) ) ;
}
}
}
}