Merge pull request #3389 from lambdageek/bug-43099
[mono.git] / mcs / class / referencesource / System.ServiceModel / System / ServiceModel / ServiceHost.cs
1 //-----------------------------------------------------------------------------
2 // Copyright (c) Microsoft Corporation.  All rights reserved.
3 //-----------------------------------------------------------------------------
4
5 namespace System.ServiceModel
6 {
7     using System;
8     using System.Collections.Generic;
9     using System.Collections.ObjectModel;
10     using System.ComponentModel;
11     using System.Diagnostics;
12     using System.Globalization;
13     using System.Net;
14     using System.Runtime;
15     using System.Security;
16     using System.ServiceModel.Administration;
17     using System.ServiceModel.Channels;
18     using System.ServiceModel.Configuration;
19     using System.ServiceModel.Description;
20     using System.ServiceModel.Diagnostics;
21     using System.ServiceModel.Dispatcher;
22     using System.Text;
23     using System.Runtime.Diagnostics;
24     using System.Threading;
25     using System.ServiceModel.Activation;
26     using System.ServiceModel.Diagnostics.Application;
27     using System.Reflection;
28     using System.Linq.Expressions;
29
30     public abstract class ServiceHostBase : CommunicationObject, IExtensibleObject<ServiceHostBase>, IDisposable
31     {
32         internal static readonly Uri EmptyUri = new Uri(string.Empty, UriKind.RelativeOrAbsolute);
33
34         bool initializeDescriptionHasFinished;
35         UriSchemeKeyedCollection baseAddresses;
36         ChannelDispatcherCollection channelDispatchers;
37         TimeSpan closeTimeout = ServiceDefaults.ServiceHostCloseTimeout;
38         ServiceDescription description;
39         ExtensionCollection<ServiceHostBase> extensions;
40         ReadOnlyCollection<Uri> externalBaseAddresses;
41         IDictionary<string, ContractDescription> implementedContracts;
42         IInstanceContextManager instances;
43         TimeSpan openTimeout = ServiceDefaults.OpenTimeout;
44         ServicePerformanceCountersBase servicePerformanceCounters;
45         DefaultPerformanceCounters defaultPerformanceCounters;
46         ServiceThrottle serviceThrottle;
47         ServiceCredentials readOnlyCredentials;
48         ServiceAuthorizationBehavior readOnlyAuthorization;
49         ServiceAuthenticationBehavior readOnlyAuthentication;
50         Dictionary<DispatcherBuilder.ListenUriInfo, Collection<ServiceEndpoint>> endpointsByListenUriInfo;
51         int busyCount;
52         EventTraceActivity eventTraceActivity;
53
54         internal event EventHandler BusyCountIncremented;
55
56         public event EventHandler<UnknownMessageReceivedEventArgs> UnknownMessageReceived;
57
58         protected ServiceHostBase()
59         {
60             TraceUtility.SetEtwProviderId();
61             this.baseAddresses = new UriSchemeKeyedCollection(this.ThisLock);
62             this.channelDispatchers = new ChannelDispatcherCollection(this, this.ThisLock);
63             this.extensions = new ExtensionCollection<ServiceHostBase>(this, this.ThisLock);
64             this.instances = new InstanceContextManager(this.ThisLock);
65             this.serviceThrottle = new ServiceThrottle(this);
66             this.TraceOpenAndClose = true;
67             this.Faulted += new EventHandler(OnServiceHostFaulted);
68         }
69
70
71         internal EventTraceActivity EventTraceActivity
72         {
73             get 
74             {
75                 if (this.eventTraceActivity == null)
76                 {
77                     this.eventTraceActivity = new EventTraceActivity();
78                 }
79
80                 return eventTraceActivity; 
81             }            
82         }
83
84         public ServiceAuthorizationBehavior Authorization
85         {
86             get
87             {
88                 if (this.Description == null)
89                 {
90                     return null;
91                 }
92                 else if (this.State == CommunicationState.Created || this.State == CommunicationState.Opening)
93                 {
94                     return EnsureAuthorization(this.Description);
95                 }
96                 else
97                 {
98                     return this.readOnlyAuthorization;
99                 }
100             }
101         }
102
103         public ServiceAuthenticationBehavior Authentication
104         {
105             get
106             {
107                 if (this.Description == null)
108                 {
109                     return null;
110                 }
111                 else if (this.State == CommunicationState.Created || this.State == CommunicationState.Opening)
112                 {
113                     return EnsureAuthentication(this.Description);
114                 }
115                 else
116                 {
117                     return this.readOnlyAuthentication;
118                 }
119             }
120         }
121
122         public ReadOnlyCollection<Uri> BaseAddresses
123         {
124             get
125             {
126                 externalBaseAddresses = new ReadOnlyCollection<Uri>(new List<Uri>(this.baseAddresses));
127                 return externalBaseAddresses;
128             }
129         }
130
131         public ChannelDispatcherCollection ChannelDispatchers
132         {
133             get { return this.channelDispatchers; }
134         }
135
136         public TimeSpan CloseTimeout
137         {
138             get { return this.closeTimeout; }
139             set
140             {
141                 if (value < TimeSpan.Zero)
142                 {
143                     string message = SR.GetString(SR.SFxTimeoutOutOfRange0);
144                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("value", message));
145                 }
146                 if (TimeoutHelper.IsTooLarge(value))
147                 {
148                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("value", SR.GetString(SR.SFxTimeoutOutOfRangeTooBig)));
149                 }
150
151                 lock (this.ThisLock)
152                 {
153                     this.ThrowIfClosedOrOpened();
154                     this.closeTimeout = value;
155                 }
156             }
157         }
158
159         internal ServicePerformanceCountersBase Counters
160         {
161             get
162             {
163                 return this.servicePerformanceCounters;
164             }
165             set
166             {
167                 this.servicePerformanceCounters = value;
168                 this.serviceThrottle.SetServicePerformanceCounters(this.servicePerformanceCounters);
169             }
170         }
171
172         internal DefaultPerformanceCounters DefaultCounters
173         {
174             get
175             {
176                 return this.defaultPerformanceCounters;
177             }
178             set
179             {
180                 this.defaultPerformanceCounters = value;
181             }
182         }
183
184         public ServiceCredentials Credentials
185         {
186             get
187             {
188                 if (this.Description == null)
189                 {
190                     return null;
191                 }
192                 else if (this.State == CommunicationState.Created || this.State == CommunicationState.Opening)
193                 {
194                     return EnsureCredentials(this.Description);
195                 }
196                 else
197                 {
198                     return this.readOnlyCredentials;
199                 }
200             }
201         }
202
203         protected override TimeSpan DefaultCloseTimeout
204         {
205             get { return this.CloseTimeout; }
206         }
207
208         protected override TimeSpan DefaultOpenTimeout
209         {
210             get { return this.OpenTimeout; }
211         }
212
213         public ServiceDescription Description
214         {
215             get { return this.description; }
216         }
217
218         public IExtensionCollection<ServiceHostBase> Extensions
219         {
220             get { return this.extensions; }
221         }
222
223         protected internal IDictionary<string, ContractDescription> ImplementedContracts
224         {
225             get { return this.implementedContracts; }
226         }
227
228         internal UriSchemeKeyedCollection InternalBaseAddresses
229         {
230             get { return this.baseAddresses; }
231         }
232
233         public int ManualFlowControlLimit
234         {
235             get { return this.ServiceThrottle.ManualFlowControlLimit; }
236             set { this.ServiceThrottle.ManualFlowControlLimit = value; }
237         }
238
239         public TimeSpan OpenTimeout
240         {
241             get { return this.openTimeout; }
242             set
243             {
244                 if (value < TimeSpan.Zero)
245                 {
246                     string message = SR.GetString(SR.SFxTimeoutOutOfRange0);
247                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("value", message));
248                 }
249                 if (TimeoutHelper.IsTooLarge(value))
250                 {
251                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("value", SR.GetString(SR.SFxTimeoutOutOfRangeTooBig)));
252                 }
253
254                 lock (this.ThisLock)
255                 {
256                     this.ThrowIfClosedOrOpened();
257                     this.openTimeout = value;
258                 }
259             }
260         }
261
262         internal ServiceThrottle ServiceThrottle
263         {
264             get
265             {
266                 return this.serviceThrottle;
267             }
268         }
269
270         internal virtual object DisposableInstance
271         {
272             get
273             {
274                 return null;
275             }
276         }
277
278         internal Dictionary<DispatcherBuilder.ListenUriInfo, Collection<ServiceEndpoint>> EndpointsByListenUriInfo
279         {
280             get
281             {
282                 if (this.endpointsByListenUriInfo == null)
283                 {
284                     this.endpointsByListenUriInfo = this.GetEndpointsByListenUriInfo();
285                 }
286                 return this.endpointsByListenUriInfo;
287             }
288         }
289
290         Dictionary<DispatcherBuilder.ListenUriInfo, Collection<ServiceEndpoint>> GetEndpointsByListenUriInfo()
291         {
292             Dictionary<DispatcherBuilder.ListenUriInfo, Collection<ServiceEndpoint>> endpointDictionary = new Dictionary<DispatcherBuilder.ListenUriInfo, Collection<ServiceEndpoint>>();
293             foreach (ServiceEndpoint endpoint in this.Description.Endpoints)
294             {
295                 DispatcherBuilder.ListenUriInfo listenUriInfo = DispatcherBuilder.GetListenUriInfoForEndpoint(this, endpoint);
296                 if (!endpointDictionary.ContainsKey(listenUriInfo))
297                 {
298                     endpointDictionary.Add(listenUriInfo, new Collection<ServiceEndpoint>());
299                 }
300                 endpointDictionary[listenUriInfo].Add(endpoint);
301             }
302             return endpointDictionary;
303         }
304
305         protected void AddBaseAddress(Uri baseAddress)
306         {
307             if (this.initializeDescriptionHasFinished)
308             {
309                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(
310                     SR.GetString(SR.SFxCannotCallAddBaseAddress)));
311             }
312             this.baseAddresses.Add(baseAddress);
313         }
314
315         public ServiceEndpoint AddServiceEndpoint(string implementedContract, Binding binding, string address)
316         {
317             return this.AddServiceEndpoint(implementedContract, binding, address, (Uri)null);
318         }
319
320         public ServiceEndpoint AddServiceEndpoint(string implementedContract, Binding binding, string address, Uri listenUri)
321         {
322             if (address == null)
323             {
324                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("address"));
325             }
326
327             ServiceEndpoint endpoint = this.AddServiceEndpoint(implementedContract, binding, new Uri(address, UriKind.RelativeOrAbsolute));
328             if (listenUri != null)
329             {
330                 endpoint.UnresolvedListenUri = listenUri;
331                 listenUri = MakeAbsoluteUri(listenUri, binding);
332                 endpoint.ListenUri = listenUri;
333             }
334             return endpoint;
335         }
336
337         public ServiceEndpoint AddServiceEndpoint(string implementedContract, Binding binding, Uri address)
338         {
339             return this.AddServiceEndpoint(implementedContract, binding, address, (Uri)null);
340         }
341
342         public ServiceEndpoint AddServiceEndpoint(string implementedContract, Binding binding, Uri address, Uri listenUri)
343         {
344             if (address == null)
345             {
346                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("address"));
347             }
348
349             if (binding == null)
350             {
351                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("binding"));
352             }
353
354             if (implementedContract == null)
355             {
356                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("implementedContract"));
357             }
358
359             if (this.State != CommunicationState.Created && this.State != CommunicationState.Opening)
360             {
361                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.SFxServiceHostBaseCannotAddEndpointAfterOpen)));
362             }
363
364             if (this.Description == null)
365             {
366                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.SFxServiceHostBaseCannotAddEndpointWithoutDescription)));
367             }
368
369             Uri via = this.MakeAbsoluteUri(address, binding);
370
371             ConfigLoader configLoader = new ConfigLoader(GetContractResolver(this.implementedContracts));
372             ContractDescription contract = configLoader.LookupContract(implementedContract, this.Description.Name);
373
374             ServiceEndpoint serviceEndpoint = new ServiceEndpoint(contract, binding, new EndpointAddress(via));
375             this.Description.Endpoints.Add(serviceEndpoint);
376             serviceEndpoint.UnresolvedAddress = address;
377
378             if (listenUri != null)
379             {
380                 serviceEndpoint.UnresolvedListenUri = listenUri;
381                 listenUri = MakeAbsoluteUri(listenUri, binding);
382                 serviceEndpoint.ListenUri = listenUri;
383             }
384             return serviceEndpoint;
385         }
386
387         public virtual void AddServiceEndpoint(ServiceEndpoint endpoint)
388         {
389             if (endpoint == null)
390             {
391                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("endpoint");
392             }
393             if (this.State != CommunicationState.Created && this.State != CommunicationState.Opening)
394             {
395                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.SFxServiceHostBaseCannotAddEndpointAfterOpen)));
396             }
397             if (this.Description == null)
398             {
399                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.SFxServiceHostBaseCannotAddEndpointWithoutDescription)));
400             }
401             if (endpoint.Address == null)
402             {
403                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgument(SR.GetString(SR.SFxEndpointAddressNotSpecified));
404             }
405             if (endpoint.Contract == null)
406             {
407                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgument(SR.GetString(SR.SFxEndpointContractNotSpecified));
408             }
409             if (endpoint.Binding == null)
410             {
411                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgument(SR.GetString(SR.SFxEndpointBindingNotSpecified));
412             }
413             if (!endpoint.IsSystemEndpoint || endpoint.Contract.ContractType == typeof(IMetadataExchange))
414             {
415                 ConfigLoader loader = new ConfigLoader(GetContractResolver(this.implementedContracts));
416                 loader.LookupContract(endpoint.Contract.ConfigurationName, this.Description.Name);
417             }
418             this.Description.Endpoints.Add(endpoint);
419         }
420
421         public void SetEndpointAddress(ServiceEndpoint endpoint, string relativeAddress)
422         {
423             if (endpoint == null)
424             {
425                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("endpoint");
426             }
427             if (relativeAddress == null)
428             {
429                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("relativeAddress");
430             }
431             if (endpoint.Binding == null)
432             {
433                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgument(SR.GetString(SR.SFxEndpointBindingNotSpecified));
434             }
435             Uri absoluteUri = MakeAbsoluteUri(new Uri(relativeAddress, UriKind.Relative), endpoint.Binding);
436             endpoint.Address = new EndpointAddress(absoluteUri);
437         }
438
439         internal Uri MakeAbsoluteUri(Uri relativeOrAbsoluteUri, Binding binding)
440         {
441             return MakeAbsoluteUri(relativeOrAbsoluteUri, binding, this.InternalBaseAddresses);
442         }
443
444         internal static Uri MakeAbsoluteUri(Uri relativeOrAbsoluteUri, Binding binding, UriSchemeKeyedCollection baseAddresses)
445         {
446             Uri result = relativeOrAbsoluteUri;
447             if (!result.IsAbsoluteUri)
448             {
449                 if (binding.Scheme == string.Empty)
450                 {
451                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.SFxCustomBindingWithoutTransport)));
452                 }
453                 result = GetVia(binding.Scheme, result, baseAddresses);
454                 if (result == null)
455                 {
456                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.SFxEndpointNoMatchingScheme, binding.Scheme, binding.Name, GetBaseAddressSchemes(baseAddresses))));
457                 }
458             }
459             return result;
460         }
461
462         protected virtual void ApplyConfiguration()
463         {
464             if (this.Description == null)
465             {
466                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.SFxServiceHostBaseCannotApplyConfigurationWithoutDescription)));
467             }
468
469             ConfigLoader configLoader = new ConfigLoader(GetContractResolver(implementedContracts));
470
471             // Call the overload of LoadConfigurationSectionInternal which looks up the serviceElement from ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None)
472             LoadConfigurationSectionInternal(configLoader, this.Description, this.Description.ConfigurationName);
473
474             EnsureAuthenticationAuthorizationDebug(this.Description);
475         }
476
477         internal void EnsureAuthenticationAuthorizationDebug(ServiceDescription description)
478         {
479             EnsureAuthentication(description);
480             EnsureAuthorization(description);
481             EnsureDebug(description);
482         }
483
484         public virtual ReadOnlyCollection<ServiceEndpoint> AddDefaultEndpoints()
485         {
486             List<ServiceEndpoint> defaultEndpoints = new List<ServiceEndpoint>();
487             foreach (Uri baseAddress in this.InternalBaseAddresses)
488             {
489                 ProtocolMappingItem protocolMappingItem = ConfigLoader.LookupProtocolMapping(baseAddress.Scheme);
490                 if (protocolMappingItem != null)
491                 {
492                     Binding defaultBinding = ConfigLoader.LookupBinding(protocolMappingItem.Binding, protocolMappingItem.BindingConfiguration);
493                     if (defaultBinding != null)
494                     {
495                         AddDefaultEndpoints(defaultBinding, defaultEndpoints);
496                     }
497                     else
498                     {
499                         throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new Exception(SR.GetString(SR.BindingProtocolMappingNotDefined, baseAddress.Scheme)));
500                     }
501                 }
502             }
503             if (DiagnosticUtility.ShouldTraceInformation && defaultEndpoints.Count > 0)
504             {
505                 Dictionary<string, string> dictionary = new Dictionary<string, string>();
506                 dictionary["ServiceConfigurationName"] = this.description.ConfigurationName;
507                 TraceUtility.TraceEvent(TraceEventType.Information, TraceCode.DefaultEndpointsAdded, SR.GetString(SR.TraceCodeDefaultEndpointsAdded), new DictionaryTraceRecord(dictionary));
508             }
509             return new ReadOnlyCollection<ServiceEndpoint>(defaultEndpoints);
510         }
511
512         internal virtual void AddDefaultEndpoints(Binding defaultBinding, List<ServiceEndpoint> defaultEndpoints)
513         {
514         }
515
516         internal virtual void BindInstance(InstanceContext instance)
517         {
518             this.instances.Add(instance);
519             if (null != this.servicePerformanceCounters)
520             {
521                 lock (this.ThisLock)
522                 {
523                     if (null != this.servicePerformanceCounters)
524                     {
525                         this.servicePerformanceCounters.ServiceInstanceCreated();
526                     }
527                 }
528             }
529         }
530
531         void IDisposable.Dispose()
532         {
533             Close();
534         }
535
536         protected abstract ServiceDescription CreateDescription(out IDictionary<string, ContractDescription> implementedContracts);
537
538         protected virtual void InitializeRuntime()
539         {
540             if (this.Description == null)
541             {
542                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.SFxServiceHostBaseCannotInitializeRuntimeWithoutDescription)));
543             }
544
545             if (this.Description.Endpoints.Count == 0)
546             {
547                 this.AddDefaultEndpoints();
548             }
549
550             this.EnsureAuthenticationSchemes();
551
552             DispatcherBuilder dispatcherBuilder = new DispatcherBuilder();
553             dispatcherBuilder.InitializeServiceHost(description, this);
554
555             SecurityValidationBehavior.Instance.AfterBuildTimeValidation(description);
556         }
557
558         internal virtual void AfterInitializeRuntime(TimeSpan timeout)
559         {
560         }
561
562         internal virtual IAsyncResult BeginAfterInitializeRuntime(TimeSpan timeout, AsyncCallback callback, object state)
563         {
564             return new CompletedAsyncResult(callback, state);
565         }
566
567         internal virtual void EndAfterInitializeRuntime(IAsyncResult result)
568         {
569             CompletedAsyncResult.End(result);
570         }
571
572         ServiceAuthorizationBehavior EnsureAuthorization(ServiceDescription description)
573         {
574             Fx.Assert(this.State == CommunicationState.Created || this.State == CommunicationState.Opening, "");
575             ServiceAuthorizationBehavior a = description.Behaviors.Find<ServiceAuthorizationBehavior>();
576
577             if (a == null)
578             {
579                 a = new ServiceAuthorizationBehavior();
580                 description.Behaviors.Add(a);
581             }
582
583             return a;
584         }
585
586         ServiceAuthenticationBehavior EnsureAuthentication(ServiceDescription description)
587         {
588             Fx.Assert(this.State == CommunicationState.Created || this.State == CommunicationState.Opening, "");
589             ServiceAuthenticationBehavior a = description.Behaviors.Find<ServiceAuthenticationBehavior>();
590
591             if (a == null)
592             {
593                 a = new ServiceAuthenticationBehavior();
594                 description.Behaviors.Add(a);
595             }
596             return a;
597         }
598
599         ServiceDebugBehavior EnsureDebug(ServiceDescription description)
600         {
601             Fx.Assert(this.State == CommunicationState.Created || this.State == CommunicationState.Opening, "");
602             ServiceDebugBehavior m = description.Behaviors.Find<ServiceDebugBehavior>();
603
604             if (m == null)
605             {
606                 m = new ServiceDebugBehavior();
607                 description.Behaviors.Add(m);
608             }
609
610             return m;
611         }
612
613         ServiceCredentials EnsureCredentials(ServiceDescription description)
614         {
615             Fx.Assert(this.State == CommunicationState.Created || this.State == CommunicationState.Opening, "");
616             ServiceCredentials c = description.Behaviors.Find<ServiceCredentials>();
617
618             if (c == null)
619             {
620                 c = new ServiceCredentials();
621                 description.Behaviors.Add(c);
622             }
623
624             return c;
625         }
626
627         internal void FaultInternal()
628         {
629             this.Fault();
630         }
631
632         internal string GetBaseAddressSchemes()
633         {
634             return GetBaseAddressSchemes(baseAddresses);
635         }
636
637         internal static String GetBaseAddressSchemes(UriSchemeKeyedCollection uriSchemeKeyedCollection)
638         {
639             StringBuilder buffer = new StringBuilder();
640             bool firstScheme = true;
641             foreach (Uri address in uriSchemeKeyedCollection)
642             {
643                 if (firstScheme)
644                 {
645                     buffer.Append(address.Scheme);
646                     firstScheme = false;
647                 }
648                 else
649                 {
650                     buffer.Append(CultureInfo.CurrentCulture.TextInfo.ListSeparator).Append(address.Scheme);
651                 }
652             }
653             return buffer.ToString();
654         }
655
656         internal BindingParameterCollection GetBindingParameters()
657         {
658             return DispatcherBuilder.GetBindingParameters(this, new Collection<ServiceEndpoint>());
659         }
660
661         internal BindingParameterCollection GetBindingParameters(ServiceEndpoint inputEndpoint)
662         {
663             Collection<ServiceEndpoint> endpoints;
664             if (inputEndpoint == null)
665             {
666                 endpoints = new Collection<ServiceEndpoint>();
667             }
668             else if (!this.EndpointsByListenUriInfo.TryGetValue(DispatcherBuilder.GetListenUriInfoForEndpoint(this, inputEndpoint), out endpoints) || !endpoints.Contains(inputEndpoint))
669             {
670                 endpoints = new Collection<ServiceEndpoint>();
671                 endpoints.Add(inputEndpoint);
672             }
673
674             return DispatcherBuilder.GetBindingParameters(this, endpoints);
675         }
676
677         internal BindingParameterCollection GetBindingParameters(Collection<ServiceEndpoint> endpoints)
678         {
679             return DispatcherBuilder.GetBindingParameters(this, endpoints);
680         }
681
682         internal ReadOnlyCollection<InstanceContext> GetInstanceContexts()
683         {
684             return Array.AsReadOnly<InstanceContext>(this.instances.ToArray());
685         }
686
687         internal virtual IContractResolver GetContractResolver(IDictionary<string, ContractDescription> implementedContracts)
688         {
689             ServiceAndBehaviorsContractResolver resolver = new ServiceAndBehaviorsContractResolver(new ImplementedContractsContractResolver(implementedContracts));
690             resolver.AddBehaviorContractsToResolver(this.description == null ? null : this.description.Behaviors);
691             return resolver;
692         }
693
694         internal static Uri GetUri(Uri baseUri, Uri relativeUri)
695         {
696             return GetUri(baseUri, relativeUri.OriginalString);
697         }
698
699         internal static Uri GetUri(Uri baseUri, string path)
700         {
701             if (path.StartsWith("/", StringComparison.Ordinal) || path.StartsWith("\\", StringComparison.Ordinal))
702             {
703                 int i = 1;
704                 for (; i < path.Length; ++i)
705                 {
706                     if (path[i] != '/' && path[i] != '\\')
707                     {
708                         break;
709                     }
710                 }
711                 path = path.Substring(i);
712             }
713
714             // VSWhidbey#541152: new Uri(Uri, string.Empty) is broken
715             if (path.Length == 0)
716                 return baseUri;
717
718             if (!baseUri.AbsoluteUri.EndsWith("/", StringComparison.Ordinal))
719             {
720                 baseUri = new Uri(baseUri.AbsoluteUri + "/");
721             }
722             return new Uri(baseUri, path);
723         }
724
725         internal Uri GetVia(string scheme, Uri address)
726         {
727             return ServiceHost.GetVia(scheme, address, InternalBaseAddresses);
728         }
729
730         internal static Uri GetVia(string scheme, Uri address, UriSchemeKeyedCollection baseAddresses)
731         {
732             Uri via = address;
733             if (!via.IsAbsoluteUri)
734             {
735                 if (!baseAddresses.Contains(scheme))
736                 {
737                     return null;
738                 }
739
740                 via = GetUri(baseAddresses[scheme], address);
741             }
742             return via;
743         }
744
745         public int IncrementManualFlowControlLimit(int incrementBy)
746         {
747             return this.ServiceThrottle.IncrementManualFlowControlLimit(incrementBy);
748         }
749
750         protected void InitializeDescription(UriSchemeKeyedCollection baseAddresses)
751         {
752             foreach (Uri baseAddress in baseAddresses)
753             {
754                 this.baseAddresses.Add(baseAddress);
755             }
756             IDictionary<string, ContractDescription> implementedContracts = null;
757             ServiceDescription description = CreateDescription(out implementedContracts);
758             this.description = description;
759             this.implementedContracts = implementedContracts;
760
761             ApplyConfiguration();
762             this.initializeDescriptionHasFinished = true;
763         }
764
765         protected void LoadConfigurationSection(ServiceElement serviceSection)
766         {
767             if (serviceSection == null)
768             {
769                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("serviceSection");
770             }
771             if (this.Description == null)
772             {
773                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.SFxServiceHostBaseCannotLoadConfigurationSectionWithoutDescription)));
774             }
775
776             ConfigLoader configLoader = new ConfigLoader(GetContractResolver(this.ImplementedContracts));
777             LoadConfigurationSectionInternal(configLoader, this.Description, serviceSection);
778         }
779
780         internal void LoadConfigurationSectionHelper(Uri baseAddress)
781         {
782             this.AddBaseAddress(baseAddress);
783         }
784
785         [Fx.Tag.SecurityNote(Critical = "Calls LookupService which is critical.",
786             Safe = "Doesn't leak ServiceElement out of SecurityCritical code.")]
787         [SecuritySafeCritical]
788         void LoadConfigurationSectionInternal(ConfigLoader configLoader, ServiceDescription description, string configurationName)
789         {
790             ServiceElement serviceSection = configLoader.LookupService(configurationName);
791             LoadConfigurationSectionInternal(configLoader, description, serviceSection);
792         }
793
794         [Fx.Tag.SecurityNote(Critical = "Handles a ServiceElement, which should not be leaked out of SecurityCritical code.",
795             Safe = "Doesn't leak ServiceElement out of SecurityCritical code.")]
796         [SecuritySafeCritical]
797         void LoadConfigurationSectionInternal(ConfigLoader configLoader, ServiceDescription description, ServiceElement serviceSection)
798         {
799             // caller must validate arguments before calling
800             configLoader.LoadServiceDescription(this, description, serviceSection, this.LoadConfigurationSectionHelper);
801         }
802
803         protected override void OnAbort()
804         {
805             this.instances.Abort();
806
807             foreach (ChannelDispatcherBase dispatcher in this.ChannelDispatchers)
808             {
809                 if (dispatcher.Listener != null)
810                 {
811                     dispatcher.Listener.Abort();
812                 }
813                 dispatcher.Abort();
814             }
815             ThreadTrace.StopTracing();
816         }
817
818         internal void OnAddChannelDispatcher(ChannelDispatcherBase channelDispatcher)
819         {
820             lock (this.ThisLock)
821             {
822                 this.ThrowIfClosedOrOpened();
823                 channelDispatcher.AttachInternal(this);
824                 channelDispatcher.Faulted += new EventHandler(OnChannelDispatcherFaulted);
825             }
826         }
827        
828         protected override IAsyncResult OnBeginClose(TimeSpan timeout, AsyncCallback callback, object state)
829         {
830             return new CloseAsyncResult(timeout, callback, state, this);
831         }
832
833         void OnBeginOpen()
834         {
835             this.TraceServiceHostOpenStart();
836             this.TraceBaseAddresses();
837             MessageLogger.EnsureInitialized(); //force config validation instead of waiting for the first message exchange
838             InitializeRuntime();
839         }
840
841         protected override IAsyncResult OnBeginOpen(TimeSpan timeout, AsyncCallback callback, object state)
842         {
843             this.OnBeginOpen();
844             return new OpenAsyncResult(this, timeout, callback, state);
845         }
846
847         IAsyncResult BeginOpenChannelDispatchers(TimeSpan timeout, AsyncCallback callback, object state)
848         {
849             return new OpenCollectionAsyncResult(timeout, callback, state, this.SnapshotChannelDispatchers());
850         }
851
852         protected override void OnClose(TimeSpan timeout)
853         {
854             try
855             {
856                 TimeoutHelper timeoutHelper = new TimeoutHelper(timeout);
857
858                 if (ManagementExtension.IsEnabled && null != this.Description)
859                 {
860                     ManagementExtension.OnServiceClosing(this);
861                 }
862
863                 for (int i = 0; i < this.ChannelDispatchers.Count; i++)
864                 {
865                     ChannelDispatcherBase dispatcher = this.ChannelDispatchers[i];
866                     if (dispatcher.Listener != null)
867                     {
868                         dispatcher.Listener.Close(timeoutHelper.RemainingTime());
869                     }
870                 }
871
872                 for (int i = 0; i < this.ChannelDispatchers.Count; i++)
873                 {
874                     ChannelDispatcherBase dispatcher = this.ChannelDispatchers[i];
875                     dispatcher.CloseInput(timeoutHelper.RemainingTime());
876                 }
877
878                 // Wait for existing work to complete
879                 this.instances.CloseInput(timeoutHelper.RemainingTime());
880
881                 // Close instances (closes contexts/channels)
882                 this.instances.Close(timeoutHelper.RemainingTime());
883
884                 // Close dispatchers
885                 for (int i = 0; i < this.ChannelDispatchers.Count; i++)
886                 {
887                     ChannelDispatcherBase dispatcher = this.ChannelDispatchers[i];
888                     dispatcher.Close(timeoutHelper.RemainingTime());
889                 }
890
891                 this.ReleasePerformanceCounters();
892
893                 this.TraceBaseAddresses();
894                 ThreadTrace.StopTracing();
895             }
896             catch (TimeoutException e)
897             {
898                 if (TD.CloseTimeoutIsEnabled())
899                 {
900                     TD.CloseTimeout(SR.GetString(SR.TraceCodeServiceHostTimeoutOnClose));
901                 }
902                 if (DiagnosticUtility.ShouldTraceWarning)
903                 {
904                     TraceUtility.TraceEvent(TraceEventType.Warning, TraceCode.ServiceHostTimeoutOnClose, SR.GetString(SR.TraceCodeServiceHostTimeoutOnClose), this, e);
905                 }
906                 this.Abort();
907             }
908
909         }
910
911         protected override void OnClosed()
912         {
913             try
914             {
915                 for (int i = 0; i < this.ChannelDispatchers.Count; i++)
916                 {
917                     ChannelDispatcher dispatcher = this.ChannelDispatchers[i] as ChannelDispatcher;
918                     if (dispatcher != null)
919                     {
920                         dispatcher.ReleasePerformanceCounters();
921                     }
922                 }
923             }
924             finally
925             {
926                 base.OnClosed();
927             }
928         }
929
930         void TraceBaseAddresses()
931         {
932             if (DiagnosticUtility.ShouldTraceInformation && this.baseAddresses != null
933                 && this.baseAddresses.Count > 0)
934             {
935                 TraceUtility.TraceEvent(TraceEventType.Information,
936                     TraceCode.ServiceHostBaseAddresses,
937                     SR.GetString(SR.TraceCodeServiceHostBaseAddresses),
938                     new CollectionTraceRecord("BaseAddresses", "Address", this.baseAddresses),
939                     this, null);
940             }
941         }
942
943         void TraceServiceHostOpenStart()
944         {
945             if (TD.ServiceHostOpenStartIsEnabled())
946             {
947                 TD.ServiceHostOpenStart(this.EventTraceActivity);
948             }
949         }
950
951         protected override void OnEndClose(IAsyncResult result)
952         {
953             try
954             {
955                 CloseAsyncResult.End(result);
956                 this.TraceBaseAddresses();
957                 ThreadTrace.StopTracing();
958             }
959             catch (TimeoutException e)
960             {
961                 if (TD.CloseTimeoutIsEnabled())
962                 {
963                     TD.CloseTimeout(SR.GetString(SR.TraceCodeServiceHostTimeoutOnClose));
964                 }
965                 if (DiagnosticUtility.ShouldTraceWarning)
966                 {
967                     TraceUtility.TraceEvent(TraceEventType.Warning, TraceCode.ServiceHostTimeoutOnClose,
968                         SR.GetString(SR.TraceCodeServiceHostTimeoutOnClose), this, e);
969                 }
970                 this.Abort();
971             }
972         }
973
974         protected override void OnEndOpen(IAsyncResult result)
975         {
976             OpenAsyncResult.End(result);
977         }
978
979         void EndOpenChannelDispatchers(IAsyncResult result)
980         {
981             OpenCollectionAsyncResult.End(result);
982         }
983
984         void EnsureAuthenticationSchemes()
985         {
986             if (this.Authentication == null)
987             {
988                 return;
989             }
990
991             //Exit immediately when not hosted in IIS or if VirtualPathExtension is not set. VirtualPathExtension is used as a flag to indicate whether a ServiceHost
992             // is webhosted (WsDualHttpBinding-ChannelFactory is using HttpListener instead of IIS even when running in IIS)
993             if (!AspNetEnvironment.Enabled ||
994                 this.Extensions.Find<VirtualPathExtension>() == null)
995             {
996                 return;
997             }
998
999             foreach (ServiceEndpoint serviceEndpoint in this.Description.Endpoints)
1000             {
1001                 if (serviceEndpoint.Binding != null &&
1002                     serviceEndpoint.ListenUri != null &&
1003                     ("http".Equals(serviceEndpoint.ListenUri.Scheme, StringComparison.OrdinalIgnoreCase) || "https".Equals(serviceEndpoint.ListenUri.Scheme, StringComparison.OrdinalIgnoreCase)) &&
1004                     this.baseAddresses.Contains(serviceEndpoint.ListenUri.Scheme))
1005                 {
1006                     HttpTransportBindingElement httpTransportBindingElement = serviceEndpoint.Binding.CreateBindingElements().Find<HttpTransportBindingElement>();
1007
1008                     if (httpTransportBindingElement != null)
1009                     {
1010                         AuthenticationSchemes hostSupportedAuthenticationSchemes = AspNetEnvironment.Current.GetAuthenticationSchemes(this.baseAddresses[serviceEndpoint.ListenUri.Scheme]);
1011
1012                         if (hostSupportedAuthenticationSchemes != AuthenticationSchemes.None)
1013                         {
1014                             //If no authentication schemes are explicitly defined for the ServiceHost...
1015                             if (this.Authentication.AuthenticationSchemes == AuthenticationSchemes.None)
1016                             {
1017                                 //Inherit authentication schemes from IIS
1018                                 this.Authentication.AuthenticationSchemes = hostSupportedAuthenticationSchemes;
1019                             }
1020                             else
1021                             {
1022                                 // Build intersection between authenticationSchemes on the ServiceHost and in IIS
1023                                 this.Authentication.AuthenticationSchemes &= hostSupportedAuthenticationSchemes;
1024                             }
1025                         }
1026                     }
1027
1028                     break;
1029                 }
1030             }
1031         }
1032
1033         protected override void OnOpen(TimeSpan timeout)
1034         {
1035             TimeoutHelper timeoutHelper = new TimeoutHelper(timeout);
1036             this.OnBeginOpen();
1037
1038             AfterInitializeRuntime(timeoutHelper.RemainingTime());
1039
1040             for (int i = 0; i < this.ChannelDispatchers.Count; i++)
1041             {
1042                 ChannelDispatcherBase dispatcher = this.ChannelDispatchers[i];
1043                 dispatcher.Open(timeoutHelper.RemainingTime());
1044             }
1045         }
1046
1047         protected override void OnOpened()
1048         {
1049             if (this.Description != null)
1050             {
1051                 ServiceCredentials c = description.Behaviors.Find<ServiceCredentials>();
1052                 if (c != null)
1053                 {
1054                     ServiceCredentials credentialsCopy = c.Clone();
1055                     credentialsCopy.MakeReadOnly();
1056                     this.readOnlyCredentials = credentialsCopy;
1057                 }
1058
1059                 ServiceAuthorizationBehavior authorization = description.Behaviors.Find<ServiceAuthorizationBehavior>();
1060                 if (authorization != null)
1061                 {
1062                     ServiceAuthorizationBehavior authorizationCopy = authorization.Clone();
1063                     authorizationCopy.MakeReadOnly();
1064                     this.readOnlyAuthorization = authorizationCopy;
1065                 }
1066
1067                 ServiceAuthenticationBehavior authentication = description.Behaviors.Find<ServiceAuthenticationBehavior>();
1068                 if (authentication != null)
1069                 {
1070                     ServiceAuthenticationBehavior authenticationCopy = authentication.Clone();
1071                     authentication.MakeReadOnly();
1072                     this.readOnlyAuthentication = authenticationCopy;
1073                 }
1074
1075                 if (ManagementExtension.IsEnabled)
1076                 {
1077                     ManagementExtension.OnServiceOpened(this);
1078                 }
1079
1080                 // log telemetry data for the current WCF service.
1081                 TelemetryTraceLogging.LogSeriveKPIData(this.Description);
1082             }
1083             base.OnOpened();
1084
1085             if (TD.ServiceHostOpenStopIsEnabled())
1086             {
1087                 TD.ServiceHostOpenStop(this.EventTraceActivity);
1088             }
1089         }
1090
1091         internal void OnRemoveChannelDispatcher(ChannelDispatcherBase channelDispatcher)
1092         {
1093             lock (this.ThisLock)
1094             {
1095                 this.ThrowIfClosedOrOpened();
1096                 channelDispatcher.DetachInternal(this);
1097             }
1098         }
1099
1100         void OnChannelDispatcherFaulted(object sender, EventArgs e)
1101         {
1102             this.Fault();
1103         }
1104
1105         void OnServiceHostFaulted(object sender, EventArgs args)
1106         {
1107             if (TD.ServiceHostFaultedIsEnabled())
1108             {
1109                 TD.ServiceHostFaulted(this.EventTraceActivity, this);
1110             }
1111
1112             if (DiagnosticUtility.ShouldTraceWarning)
1113             {
1114                 TraceUtility.TraceEvent(TraceEventType.Warning, TraceCode.ServiceHostFaulted,
1115                     SR.GetString(SR.TraceCodeServiceHostFaulted), this);
1116             }
1117
1118             foreach (ICommunicationObject channelDispatcher in this.SnapshotChannelDispatchers())
1119             {
1120                 if (channelDispatcher.State == CommunicationState.Opened)
1121                 {
1122                     channelDispatcher.Abort();
1123                 }
1124             }
1125         }
1126
1127         internal void RaiseUnknownMessageReceived(Message message)
1128         {
1129             try
1130             {
1131                 EventHandler<UnknownMessageReceivedEventArgs> handler = UnknownMessageReceived;
1132                 if (handler != null)
1133                 {
1134                     handler(this, new UnknownMessageReceivedEventArgs(message));
1135                 }
1136             }
1137             catch (Exception e)
1138             {
1139                 if (Fx.IsFatal(e))
1140                     throw;
1141
1142                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperCallback(e);
1143             }
1144         }
1145
1146         protected void ReleasePerformanceCounters()
1147         {
1148             if (this.servicePerformanceCounters != null)
1149             {
1150                 lock (this.ThisLock)
1151                 {
1152                     if (this.servicePerformanceCounters != null)
1153                     {
1154                         this.servicePerformanceCounters.Dispose();
1155                         this.servicePerformanceCounters = null;
1156                     }
1157                 }
1158             }
1159             if (this.defaultPerformanceCounters != null)
1160             {
1161                 lock (this.ThisLock)
1162                 {
1163                     if (this.defaultPerformanceCounters != null)
1164                     {
1165                         this.defaultPerformanceCounters.Dispose();
1166                         this.defaultPerformanceCounters = null;
1167                     }
1168                 }
1169             }
1170         }
1171
1172         ICommunicationObject[] SnapshotChannelDispatchers()
1173         {
1174             lock (this.ThisLock)
1175             {
1176                 ICommunicationObject[] array = new ICommunicationObject[this.ChannelDispatchers.Count];
1177                 for (int i = 0; i < array.Length; i++)
1178                 {
1179                     array[i] = this.ChannelDispatchers[i];
1180                 }
1181                 return array;
1182             }
1183         }
1184
1185         internal virtual void UnbindInstance(InstanceContext instance)
1186         {
1187             this.instances.Remove(instance);
1188             if (null != this.servicePerformanceCounters)
1189             {
1190                 lock (this.ThisLock)
1191                 {
1192                     if (null != this.servicePerformanceCounters)
1193                     {
1194                         this.servicePerformanceCounters.ServiceInstanceRemoved();
1195                     }
1196                 }
1197             }
1198         }
1199
1200         internal void IncrementBusyCount()
1201         {
1202             if (AspNetEnvironment.Enabled)
1203             {
1204                 AspNetEnvironment.Current.IncrementBusyCount();
1205                 Interlocked.Increment(ref this.busyCount);
1206             }
1207
1208             EventHandler handler = this.BusyCountIncremented;
1209             if (handler != null)
1210             {
1211                 try
1212                 {
1213                     handler(this, EventArgs.Empty);
1214                 }
1215                 catch (Exception exception)
1216                 {
1217                     if (Fx.IsFatal(exception))
1218                         throw;
1219
1220                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperCallback(exception);
1221                 }
1222             }
1223         }
1224
1225         internal void DecrementBusyCount()
1226         {
1227             if (AspNetEnvironment.Enabled)
1228             {
1229                 Interlocked.Decrement(ref this.busyCount);
1230                 AspNetEnvironment.Current.DecrementBusyCount();
1231             }
1232         }
1233
1234         internal int BusyCount
1235         {
1236             get
1237             {
1238                 return this.busyCount;
1239             }
1240         }
1241
1242         class OpenAsyncResult : AsyncResult
1243         {
1244             static AsyncCompletion handleEndAfterInitializeRuntime = new AsyncCompletion(HandleEndAfterInitializeRuntime);
1245             static AsyncCompletion handleEndOpenChannelDispatchers = new AsyncCompletion(HandleEndOpenChannelDispatchers);
1246
1247             TimeoutHelper timeoutHelper;
1248             ServiceHostBase host;
1249
1250             public OpenAsyncResult(ServiceHostBase host, TimeSpan timeout, AsyncCallback callback, object state)
1251                 : base(callback, state)
1252             {
1253                 this.timeoutHelper = new TimeoutHelper(timeout);
1254                 this.host = host;
1255
1256                 if (ProcessAfterInitializeRuntime())
1257                 {
1258                     Complete(true);
1259                 }
1260             }
1261
1262             bool ProcessAfterInitializeRuntime()
1263             {
1264                 IAsyncResult result = this.host.BeginAfterInitializeRuntime(
1265                     this.timeoutHelper.RemainingTime(), PrepareAsyncCompletion(handleEndAfterInitializeRuntime), this);
1266
1267                 return SyncContinue(result);
1268             }
1269
1270             static bool HandleEndAfterInitializeRuntime(IAsyncResult result)
1271             {
1272                 OpenAsyncResult thisPtr = (OpenAsyncResult)result.AsyncState;
1273                 thisPtr.host.EndAfterInitializeRuntime(result);
1274
1275                 return thisPtr.ProcessOpenChannelDispatchers();
1276             }
1277
1278             bool ProcessOpenChannelDispatchers()
1279             {
1280                 IAsyncResult result = this.host.BeginOpenChannelDispatchers(
1281                     this.timeoutHelper.RemainingTime(), PrepareAsyncCompletion(handleEndOpenChannelDispatchers), this);
1282
1283                 return SyncContinue(result);
1284             }
1285
1286             static bool HandleEndOpenChannelDispatchers(IAsyncResult result)
1287             {
1288                 OpenAsyncResult thisPtr = (OpenAsyncResult)result.AsyncState;
1289                 thisPtr.host.EndOpenChannelDispatchers(result);
1290
1291                 return true;
1292             }
1293
1294             public static void End(IAsyncResult result)
1295             {
1296                 AsyncResult.End<OpenAsyncResult>(result);
1297             }
1298         }
1299
1300         class CloseAsyncResult : AsyncResult
1301         {
1302             ServiceHostBase serviceHost;
1303             TimeoutHelper timeoutHelper;
1304
1305             public CloseAsyncResult(TimeSpan timeout, AsyncCallback callback, object state, ServiceHostBase serviceHost)
1306                 : base(callback, state)
1307             {
1308                 this.timeoutHelper = new TimeoutHelper(timeout);
1309                 this.serviceHost = serviceHost;
1310
1311                 if (ManagementExtension.IsEnabled && null != serviceHost.Description)
1312                 {
1313                     ManagementExtension.OnServiceClosing(serviceHost);
1314                 }
1315
1316                 this.CloseListeners(true);
1317             }
1318
1319             void CloseListeners(bool completedSynchronously)
1320             {
1321                 List<ICommunicationObject> listeners = new List<ICommunicationObject>();
1322                 for (int i = 0; i < this.serviceHost.ChannelDispatchers.Count; i++)
1323                 {
1324                     if (this.serviceHost.ChannelDispatchers[i].Listener != null)
1325                     {
1326                         listeners.Add(this.serviceHost.ChannelDispatchers[i].Listener);
1327                     }
1328                 }
1329
1330                 AsyncCallback callback = Fx.ThunkCallback(this.CloseListenersCallback);
1331                 TimeSpan timeout = this.timeoutHelper.RemainingTime();
1332                 Exception exception = null;
1333                 IAsyncResult result = null;
1334                 try
1335                 {
1336                     result = new CloseCollectionAsyncResult(timeout, callback, this, listeners);
1337                 }
1338                 catch (Exception e)
1339                 {
1340                     if (Fx.IsFatal(e) || completedSynchronously)
1341                     {
1342                         throw;
1343                     }
1344                     exception = e;
1345                 }
1346
1347                 if (exception != null)
1348                 {
1349                     this.CallComplete(completedSynchronously, exception);
1350                 }
1351                 else if (result.CompletedSynchronously)
1352                 {
1353                     this.FinishCloseListeners(result, completedSynchronously);
1354                 }
1355             }
1356
1357             void CloseListenersCallback(IAsyncResult result)
1358             {
1359                 if (!result.CompletedSynchronously)
1360                 {
1361                     ((CloseAsyncResult)result.AsyncState).FinishCloseListeners(result, false);
1362                 }
1363             }
1364
1365             void FinishCloseListeners(IAsyncResult result, bool completedSynchronously)
1366             {
1367                 Exception exception = null;
1368                 try
1369                 {
1370                     CloseCollectionAsyncResult.End(result);
1371                 }
1372                 catch (Exception e)
1373                 {
1374                     if (Fx.IsFatal(e) || completedSynchronously)
1375                     {
1376                         throw;
1377                     }
1378                     exception = e;
1379                 }
1380
1381                 if (exception != null)
1382                 {
1383                     this.CallComplete(completedSynchronously, exception);
1384                 }
1385                 else
1386                 {
1387                     this.CloseInput(completedSynchronously);
1388                 }
1389             }
1390
1391             // Wait for existing work to complete
1392             void CloseInput(bool completedSynchronously)
1393             {
1394                 AsyncCallback callback = Fx.ThunkCallback(this.CloseInputCallback);
1395                 Exception exception = null;
1396                 IAsyncResult result = null;
1397
1398                 try
1399                 {
1400                     for (int i = 0; i < this.serviceHost.ChannelDispatchers.Count; i++)
1401                     {
1402                         ChannelDispatcherBase dispatcher = this.serviceHost.ChannelDispatchers[i];
1403                         dispatcher.CloseInput(this.timeoutHelper.RemainingTime());
1404                     }
1405
1406                     result = this.serviceHost.instances.BeginCloseInput(this.timeoutHelper.RemainingTime(), callback, this);
1407                 }
1408                 catch (Exception e)
1409                 {
1410                     if (Fx.IsFatal(e) || completedSynchronously)
1411                     {
1412                         throw;
1413                     }
1414
1415                     exception = e;
1416                 }
1417
1418                 if (exception != null)
1419                 {
1420                     // Any exception during async processing causes this
1421                     // async callback to report the error and then relies on
1422                     // Abort to cleanup any unclosed channels or instance contexts.
1423                     FxTrace.Exception.AsWarning(exception);
1424                     this.CallComplete(completedSynchronously, exception);
1425                 }
1426                 else if (result.CompletedSynchronously)
1427                 {
1428                     this.FinishCloseInput(result, completedSynchronously);
1429                 }
1430             }
1431
1432             void CloseInputCallback(IAsyncResult result)
1433             {
1434                 if (!result.CompletedSynchronously)
1435                 {
1436                     ((CloseAsyncResult)result.AsyncState).FinishCloseInput(result, false);
1437                 }
1438             }
1439
1440             void FinishCloseInput(IAsyncResult result, bool completedSynchronously)
1441             {
1442                 Exception exception = null;
1443                 try
1444                 {
1445                     serviceHost.instances.EndCloseInput(result);
1446                 }
1447                 catch (Exception e)
1448                 {
1449                     if (Fx.IsFatal(e) || completedSynchronously)
1450                     {
1451                         throw;
1452                     }
1453                     exception = e;
1454                 }
1455
1456                 if (exception != null)
1457                 {
1458                     this.CallComplete(completedSynchronously, exception);
1459                 }
1460                 else
1461                 {
1462                     this.CloseInstances(completedSynchronously);
1463                 }
1464             }
1465
1466             // Close instances (closes contexts/channels)
1467             void CloseInstances(bool completedSynchronously)
1468             {
1469                 AsyncCallback callback = Fx.ThunkCallback(this.CloseInstancesCallback);
1470                 TimeSpan timeout = this.timeoutHelper.RemainingTime();
1471                 Exception exception = null;
1472                 IAsyncResult result = null;
1473
1474                 try
1475                 {
1476                     result = this.serviceHost.instances.BeginClose(timeout, callback, this);
1477                 }
1478                 catch (Exception e)
1479                 {
1480                     if (Fx.IsFatal(e) || completedSynchronously)
1481                     {
1482                         throw;
1483                     }
1484                     exception = e;
1485                 }
1486
1487                 if (exception != null)
1488                 {
1489                     this.CallComplete(completedSynchronously, exception);
1490                 }
1491                 else if (result.CompletedSynchronously)
1492                 {
1493                     this.FinishCloseInstances(result, completedSynchronously);
1494                 }
1495             }
1496
1497             void CloseInstancesCallback(IAsyncResult result)
1498             {
1499                 if (!result.CompletedSynchronously)
1500                 {
1501                     ((CloseAsyncResult)result.AsyncState).FinishCloseInstances(result, false);
1502                 }
1503             }
1504
1505             void FinishCloseInstances(IAsyncResult result, bool completedSynchronously)
1506             {
1507                 Exception exception = null;
1508                 try
1509                 {
1510                     this.serviceHost.instances.EndClose(result);
1511                 }
1512                 catch (Exception e)
1513                 {
1514                     if (Fx.IsFatal(e) || completedSynchronously)
1515                     {
1516                         throw;
1517                     }
1518                     exception = e;
1519                 }
1520
1521                 if (exception != null)
1522                 {
1523                     this.CallComplete(completedSynchronously, exception);
1524                 }
1525                 else
1526                 {
1527                     this.CloseChannelDispatchers(completedSynchronously);
1528                 }
1529             }
1530
1531             void CloseChannelDispatchers(bool completedSynchronously)
1532             {
1533                 IList<ICommunicationObject> channelDispatchers = this.serviceHost.SnapshotChannelDispatchers();
1534                 AsyncCallback callback = Fx.ThunkCallback(this.CloseChannelDispatchersCallback);
1535                 TimeSpan timeout = this.timeoutHelper.RemainingTime();
1536                 Exception exception = null;
1537                 IAsyncResult result = null;
1538                 try
1539                 {
1540                     result = new CloseCollectionAsyncResult(timeout, callback, this, channelDispatchers);
1541                 }
1542                 catch (Exception e)
1543                 {
1544                     if (Fx.IsFatal(e) || completedSynchronously)
1545                     {
1546                         throw;
1547                     }
1548                     exception = e;
1549                 }
1550
1551                 if (exception != null)
1552                 {
1553                     this.CallComplete(completedSynchronously, exception);
1554                 }
1555                 else if (result.CompletedSynchronously)
1556                 {
1557                     this.FinishCloseChannelDispatchers(result, completedSynchronously);
1558                 }
1559             }
1560
1561             void CloseChannelDispatchersCallback(IAsyncResult result)
1562             {
1563                 if (!result.CompletedSynchronously)
1564                 {
1565                     ((CloseAsyncResult)result.AsyncState).FinishCloseChannelDispatchers(result, false);
1566                 }
1567             }
1568
1569             void FinishCloseChannelDispatchers(IAsyncResult result, bool completedSynchronously)
1570             {
1571                 Exception exception = null;
1572                 try
1573                 {
1574                     CloseCollectionAsyncResult.End(result);
1575                 }
1576                 catch (Exception e)
1577                 {
1578                     if (Fx.IsFatal(e) || completedSynchronously)
1579                     {
1580                         throw;
1581                     }
1582                     exception = e;
1583                 }
1584
1585                 this.CallComplete(completedSynchronously, exception);
1586             }
1587
1588             void CallComplete(bool completedSynchronously, Exception exception)
1589             {
1590                 this.Complete(completedSynchronously, exception);
1591             }
1592
1593             public static void End(IAsyncResult result)
1594             {
1595                 AsyncResult.End<CloseAsyncResult>(result);
1596             }
1597         }
1598
1599         class ImplementedContractsContractResolver : IContractResolver
1600         {
1601             IDictionary<string, ContractDescription> implementedContracts;
1602
1603             public ImplementedContractsContractResolver(IDictionary<string, ContractDescription> implementedContracts)
1604             {
1605                 this.implementedContracts = implementedContracts;
1606             }
1607
1608             public ContractDescription ResolveContract(string contractName)
1609             {
1610                 return this.implementedContracts != null && this.implementedContracts.ContainsKey(contractName) ? this.implementedContracts[contractName] : null;
1611             }
1612         }
1613
1614         internal class ServiceAndBehaviorsContractResolver : IContractResolver
1615         {
1616             IContractResolver serviceResolver;
1617             Dictionary<string, ContractDescription> behaviorContracts;
1618
1619             public Dictionary<string, ContractDescription> BehaviorContracts
1620             {
1621                 get { return behaviorContracts; }
1622             }
1623
1624             public ServiceAndBehaviorsContractResolver(IContractResolver serviceResolver)
1625             {
1626                 this.serviceResolver = serviceResolver;
1627                 behaviorContracts = new Dictionary<string, ContractDescription>();
1628             }
1629
1630             public ContractDescription ResolveContract(string contractName)
1631             {
1632                 ContractDescription contract = serviceResolver.ResolveContract(contractName);
1633
1634                 if (contract == null)
1635                 {
1636                     contract = this.behaviorContracts.ContainsKey(contractName) ? this.behaviorContracts[contractName] : null;
1637                 }
1638
1639                 return contract;
1640             }
1641
1642             public void AddBehaviorContractsToResolver(KeyedByTypeCollection<IServiceBehavior> behaviors)
1643             {
1644                 // It would be nice to make this loop over all Behaviors... someday.
1645                 if (behaviors != null && behaviors.Contains(typeof(ServiceMetadataBehavior)))
1646                 {
1647                     behaviors.Find<ServiceMetadataBehavior>().AddImplementedContracts(this);
1648                 }
1649             }
1650         }
1651     }
1652
1653     public class ServiceHost : ServiceHostBase
1654     {
1655         object singletonInstance;
1656         Type serviceType;
1657         ReflectedContractCollection reflectedContracts;
1658         IDisposable disposableInstance;
1659
1660         protected ServiceHost()
1661         {
1662         }
1663
1664         public ServiceHost(Type serviceType, params Uri[] baseAddresses)
1665         {
1666             if (serviceType == null)
1667             {
1668                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("serviceType"));
1669             }
1670
1671             this.serviceType = serviceType;
1672             using (ServiceModelActivity activity = DiagnosticUtility.ShouldUseActivity ? ServiceModelActivity.CreateBoundedActivity() : null)
1673             {
1674                 if (DiagnosticUtility.ShouldUseActivity)
1675                 {
1676                     ServiceModelActivity.Start(activity, SR.GetString(SR.ActivityConstructServiceHost, serviceType.FullName), ActivityType.Construct);
1677                 }
1678
1679                 InitializeDescription(serviceType, new UriSchemeKeyedCollection(baseAddresses));
1680             }
1681         }
1682
1683         public ServiceHost(object singletonInstance, params Uri[] baseAddresses)
1684         {
1685             if (singletonInstance == null)
1686             {
1687                 throw new ArgumentNullException("singletonInstance");
1688             }
1689
1690             this.singletonInstance = singletonInstance;
1691             this.serviceType = singletonInstance.GetType();
1692             using (ServiceModelActivity activity = DiagnosticUtility.ShouldUseActivity ? ServiceModelActivity.CreateBoundedActivity() : null)
1693             {
1694                 if (DiagnosticUtility.ShouldUseActivity)
1695                 {
1696                     ServiceModelActivity.Start(activity, SR.GetString(SR.ActivityConstructServiceHost, serviceType.FullName), ActivityType.Construct);
1697                 }
1698
1699                 InitializeDescription(singletonInstance, new UriSchemeKeyedCollection(baseAddresses));
1700             }
1701         }
1702
1703         public object SingletonInstance
1704         {
1705             get
1706             {
1707                 return this.singletonInstance;
1708             }
1709         }
1710
1711         internal override object DisposableInstance
1712         {
1713             get
1714             {
1715                 return this.disposableInstance;
1716             }
1717         }
1718
1719         public ServiceEndpoint AddServiceEndpoint(Type implementedContract, Binding binding, string address)
1720         {
1721             return this.AddServiceEndpoint(implementedContract, binding, address, (Uri)null);
1722         }
1723
1724         public ServiceEndpoint AddServiceEndpoint(Type implementedContract, Binding binding, string address, Uri listenUri)
1725         {
1726             if (address == null)
1727             {
1728                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("address"));
1729             }
1730
1731             ServiceEndpoint endpoint = this.AddServiceEndpoint(implementedContract, binding, new Uri(address, UriKind.RelativeOrAbsolute));
1732             if (listenUri != null)
1733             {
1734                 listenUri = MakeAbsoluteUri(listenUri, binding);
1735                 endpoint.ListenUri = listenUri;
1736             }
1737             return endpoint;
1738         }
1739
1740         public ServiceEndpoint AddServiceEndpoint(Type implementedContract, Binding binding, Uri address)
1741         {
1742             return this.AddServiceEndpoint(implementedContract, binding, address, (Uri)null);
1743         }
1744
1745         void ValidateContractType(Type implementedContract, ReflectedAndBehaviorContractCollection reflectedAndBehaviorContracts)
1746         {
1747             if (!implementedContract.IsDefined(typeof(ServiceContractAttribute), false))
1748             {
1749 #pragma warning suppress 56506 // implementedContract is never null at this point
1750                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.SfxServiceContractAttributeNotFound, implementedContract.FullName)));
1751             }
1752             if (!reflectedAndBehaviorContracts.Contains(implementedContract))
1753             {
1754                 if (implementedContract == typeof(IMetadataExchange))
1755 #pragma warning suppress 56506 // ServiceType is never null at this point
1756                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.SfxReflectedContractKeyNotFoundIMetadataExchange, this.serviceType.FullName)));
1757                 else
1758 #pragma warning suppress 56506 // implementedContract and ServiceType are never null at this point
1759                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.SfxReflectedContractKeyNotFound2, implementedContract.FullName, this.serviceType.FullName)));
1760             }
1761         }
1762
1763         public ServiceEndpoint AddServiceEndpoint(Type implementedContract, Binding binding, Uri address, Uri listenUri)
1764         {
1765             if (implementedContract == null)
1766             {
1767                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("implementedContract"));
1768             }
1769             if (this.reflectedContracts == null)
1770             {
1771                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.SfxReflectedContractsNotInitialized1, implementedContract.FullName)));
1772             }
1773             ReflectedAndBehaviorContractCollection reflectedAndBehaviorContracts = new ReflectedAndBehaviorContractCollection(this.reflectedContracts, this.Description.Behaviors);
1774             ValidateContractType(implementedContract, reflectedAndBehaviorContracts);
1775             ServiceEndpoint endpoint = AddServiceEndpoint(reflectedAndBehaviorContracts.GetConfigKey(implementedContract), binding, address);
1776             if (listenUri != null)
1777             {
1778                 listenUri = MakeAbsoluteUri(listenUri, binding);
1779                 endpoint.ListenUri = listenUri;
1780             }
1781             return endpoint;
1782         }
1783
1784         internal override void AddDefaultEndpoints(Binding defaultBinding, List<ServiceEndpoint> defaultEndpoints)
1785         {
1786             // don't generate endpoints for contracts that serve as the base type for other reflected contracts
1787             List<ContractDescription> mostSpecificContracts = new List<ContractDescription>();
1788             for (int i = 0; i < this.reflectedContracts.Count; i++)
1789             {
1790                 bool addContractEndpoint = true;
1791                 ContractDescription contract = this.reflectedContracts[i];
1792                 Type contractType = contract.ContractType;
1793                 if (contractType != null)
1794                 {
1795                     for (int j = 0; j < this.reflectedContracts.Count; j++)
1796                     {
1797                         ContractDescription otherContract = this.reflectedContracts[j];
1798                         Type otherContractType = otherContract.ContractType;
1799                         if (i == j || otherContractType == null)
1800                         {
1801                             continue;
1802                         }
1803                         if (contractType.IsAssignableFrom(otherContractType))
1804                         {
1805                             addContractEndpoint = false;
1806                             break;
1807                         }
1808                     }
1809                 }
1810                 if (addContractEndpoint)
1811                 {
1812                     mostSpecificContracts.Add(contract);
1813                 }
1814             }
1815
1816             foreach (ContractDescription contract in mostSpecificContracts)
1817             {
1818                 ServiceEndpoint endpoint = AddServiceEndpoint(contract.ConfigurationName, defaultBinding, string.Empty);
1819                 ConfigLoader.LoadDefaultEndpointBehaviors(endpoint);
1820                 defaultEndpoints.Add(endpoint);
1821             }
1822         }
1823
1824         // Run static Configure method on service type if it exists, else load configuration from Web.config/App.config
1825         protected override void ApplyConfiguration()
1826         {
1827             // Load from static Configure method if it exists with the right signature
1828             Type serviceType = this.Description.ServiceType;
1829             if (serviceType != null)
1830             {
1831                 MethodInfo configure = GetConfigureMethod(serviceType);
1832                 if (configure != null)
1833                 {
1834                     // load <host> config
1835                     ConfigLoader configLoader = new ConfigLoader(GetContractResolver(this.ImplementedContracts));
1836                     LoadHostConfigurationInternal(configLoader, this.Description, this.Description.ConfigurationName);
1837
1838                     // Invoke configure method for service
1839                     ServiceConfiguration configuration = new ServiceConfiguration(this);
1840                     InvokeConfigure(configure, configuration);
1841
1842                     return;
1843                 }
1844             }
1845
1846             // else just load from Web.config/App.config
1847             base.ApplyConfiguration();
1848         }
1849
1850         // Find the Configure method with the required signature, closest to serviceType in the type hierarchy
1851         static MethodInfo GetConfigureMethod(Type serviceType)
1852         {
1853             // Use recursion instead of BindingFlags.FlattenHierarchy because we require return type to be void
1854             
1855             // base case: all Types are rooted in object eventually
1856             if (serviceType == typeof(object))
1857             {
1858                 return null;
1859             }
1860
1861             // signature: "public static void Configure(ServiceConfiguration)"
1862             MethodInfo configure = serviceType.GetMethod("Configure", BindingFlags.Static | BindingFlags.Public, null, new[] { typeof(ServiceConfiguration) }, null);
1863
1864             if (configure != null && configure.ReturnType == typeof(void))
1865             {
1866                 return configure;
1867             }
1868             else
1869             {
1870                 return GetConfigureMethod(serviceType.BaseType);
1871             }
1872         }
1873
1874         static void InvokeConfigure(MethodInfo configureMethod, ServiceConfiguration configuration)
1875         {
1876             Action<ServiceConfiguration> call = Delegate.CreateDelegate(typeof(Action<ServiceConfiguration>), configureMethod) as Action<ServiceConfiguration>;
1877             call(configuration);
1878         }
1879
1880         // called from ServiceConfiguration.LoadFromConfiguration()
1881         internal void LoadFromConfiguration()
1882         {
1883             if (this.Description == null)
1884             {
1885                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.SFxServiceHostBaseCannotApplyConfigurationWithoutDescription)));
1886             }
1887
1888             ConfigLoader configLoader = new ConfigLoader(GetContractResolver(this.ImplementedContracts));
1889
1890             // Call the overload of LoadConfigurationSectionInternal which looks up the serviceElement from ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None)
1891             LoadConfigurationSectionExceptHostInternal(configLoader, this.Description, this.Description.ConfigurationName);
1892             EnsureAuthenticationAuthorizationDebug(this.Description);
1893         }
1894
1895         // called from ServiceConfiguration.LoadFromConfiguration(configuration)
1896         internal void LoadFromConfiguration(System.Configuration.Configuration configuration)
1897         {
1898             if (this.Description == null)
1899             {
1900                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.SFxServiceHostBaseCannotApplyConfigurationWithoutDescription)));
1901             }
1902
1903             ConfigLoader configLoader = new ConfigLoader(GetContractResolver(this.ImplementedContracts));
1904
1905             // 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
1906             ServicesSection servicesSection = (ServicesSection)configuration.GetSection(ConfigurationStrings.ServicesSectionPath);
1907             ServiceElement serviceElement = configLoader.LookupService(this.Description.ConfigurationName, servicesSection);
1908             configLoader.LoadServiceDescription(this, this.Description, serviceElement, this.LoadConfigurationSectionHelper, skipHost: true);
1909
1910             EnsureAuthenticationAuthorizationDebug(this.Description);
1911         }
1912
1913         // Load only "host" section within "service" tag
1914         [Fx.Tag.SecurityNote(Critical = "Calls LookupService which is critical.",
1915             Safe = "Doesn't leak ServiceElement out of SecurityCritical code.")]
1916         [SecuritySafeCritical]
1917         void LoadHostConfigurationInternal(ConfigLoader configLoader, ServiceDescription description, string configurationName)
1918         {
1919             ServiceElement serviceSection = configLoader.LookupService(configurationName);
1920             if (serviceSection != null)
1921             {
1922                 configLoader.LoadHostConfig(serviceSection, this, (addr => this.InternalBaseAddresses.Add(addr)));
1923             }
1924         }
1925
1926         // Load service description for service from config, but skip "host" section within "service" tag
1927         [Fx.Tag.SecurityNote(Critical = "Calls LookupService which is critical.",
1928             Safe = "Doesn't leak ServiceElement out of SecurityCritical code.")]
1929         [SecuritySafeCritical]
1930         void LoadConfigurationSectionExceptHostInternal(ConfigLoader configLoader, ServiceDescription description, string configurationName)
1931         {
1932             ServiceElement serviceSection = configLoader.LookupService(configurationName);
1933             configLoader.LoadServiceDescription(this, description, serviceSection, this.LoadConfigurationSectionHelper, skipHost: true);
1934         }
1935         
1936         internal override string CloseActivityName
1937         {
1938             get { return SR.GetString(SR.ActivityCloseServiceHost, this.serviceType.FullName); }
1939         }
1940
1941         internal override string OpenActivityName
1942         {
1943             get { return SR.GetString(SR.ActivityOpenServiceHost, this.serviceType.FullName); }
1944         }
1945
1946         protected override ServiceDescription CreateDescription(out IDictionary<string, ContractDescription> implementedContracts)
1947         {
1948             if (this.serviceType == null)
1949             {
1950                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.SFxServiceHostCannotCreateDescriptionWithoutServiceType)));
1951             }
1952
1953             ServiceDescription description;
1954             if (this.SingletonInstance != null)
1955             {
1956                 description = ServiceDescription.GetService(this.SingletonInstance);
1957             }
1958             else
1959             {
1960                 description = ServiceDescription.GetService(this.serviceType);
1961             }
1962             ServiceBehaviorAttribute serviceBehavior = description.Behaviors.Find<ServiceBehaviorAttribute>();
1963             object serviceInstanceUsedAsABehavior = serviceBehavior.GetWellKnownSingleton();
1964             if (serviceInstanceUsedAsABehavior == null)
1965             {
1966                 serviceInstanceUsedAsABehavior = serviceBehavior.GetHiddenSingleton();
1967                 this.disposableInstance = serviceInstanceUsedAsABehavior as IDisposable;
1968             }
1969
1970             if ((typeof(IServiceBehavior).IsAssignableFrom(this.serviceType) || typeof(IContractBehavior).IsAssignableFrom(this.serviceType))
1971                 && serviceInstanceUsedAsABehavior == null)
1972             {
1973                 serviceInstanceUsedAsABehavior = ServiceDescription.CreateImplementation(this.serviceType);
1974                 this.disposableInstance = serviceInstanceUsedAsABehavior as IDisposable;
1975             }
1976
1977             if (this.SingletonInstance == null)
1978             {
1979                 if (serviceInstanceUsedAsABehavior is IServiceBehavior)
1980                 {
1981                     description.Behaviors.Add((IServiceBehavior)serviceInstanceUsedAsABehavior);
1982                 }
1983             }
1984
1985             ReflectedContractCollection reflectedContracts = new ReflectedContractCollection();
1986             List<Type> interfaces = ServiceReflector.GetInterfaces(this.serviceType);
1987             for (int i = 0; i < interfaces.Count; i++)
1988             {
1989                 Type contractType = interfaces[i];
1990                 if (!reflectedContracts.Contains(contractType))
1991                 {
1992                     ContractDescription contract = null;
1993                     if (serviceInstanceUsedAsABehavior != null)
1994                     {
1995                         contract = ContractDescription.GetContract(contractType, serviceInstanceUsedAsABehavior);
1996                     }
1997                     else
1998                     {
1999                         contract = ContractDescription.GetContract(contractType, this.serviceType);
2000                     }
2001
2002                     reflectedContracts.Add(contract);
2003                     Collection<ContractDescription> inheritedContracts = contract.GetInheritedContracts();
2004                     for (int j = 0; j < inheritedContracts.Count; j++)
2005                     {
2006                         ContractDescription inheritedContract = inheritedContracts[j];
2007                         if (!reflectedContracts.Contains(inheritedContract.ContractType))
2008                         {
2009                             reflectedContracts.Add(inheritedContract);
2010                         }
2011                     }
2012                 }
2013             }
2014             this.reflectedContracts = reflectedContracts;
2015
2016             implementedContracts = reflectedContracts.ToImplementedContracts();
2017             return description;
2018         }
2019
2020         protected void InitializeDescription(object singletonInstance, UriSchemeKeyedCollection baseAddresses)
2021         {
2022             if (singletonInstance == null)
2023             {
2024                 throw new ArgumentNullException("singletonInstance");
2025             }
2026
2027             this.singletonInstance = singletonInstance;
2028             InitializeDescription(singletonInstance.GetType(), baseAddresses);
2029         }
2030
2031         protected void InitializeDescription(Type serviceType, UriSchemeKeyedCollection baseAddresses)
2032         {
2033             if (serviceType == null)
2034             {
2035                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("serviceType"));
2036             }
2037
2038             this.serviceType = serviceType;
2039
2040             base.InitializeDescription(baseAddresses);
2041         }
2042
2043         protected override void OnClosed()
2044         {
2045             base.OnClosed();
2046             if (this.disposableInstance != null)
2047             {
2048                 this.disposableInstance.Dispose();
2049             }
2050         }
2051
2052         class ReflectedContractCollection : KeyedCollection<Type, ContractDescription>
2053         {
2054             public ReflectedContractCollection()
2055                 : base(null, 4)
2056             {
2057             }
2058
2059             protected override Type GetKeyForItem(ContractDescription item)
2060             {
2061                 if (item == null)
2062                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("item");
2063
2064                 return item.ContractType;
2065             }
2066
2067             public IDictionary<string, ContractDescription> ToImplementedContracts()
2068             {
2069                 Dictionary<string, ContractDescription> implementedContracts = new Dictionary<string, ContractDescription>();
2070                 foreach (ContractDescription contract in this.Items)
2071                 {
2072                     implementedContracts.Add(GetConfigKey(contract), contract);
2073                 }
2074                 return implementedContracts;
2075             }
2076
2077             internal static string GetConfigKey(ContractDescription contract)
2078             {
2079                 return contract.ConfigurationName;
2080             }
2081         }
2082
2083         class ReflectedAndBehaviorContractCollection
2084         {
2085             ReflectedContractCollection reflectedContracts;
2086             KeyedByTypeCollection<IServiceBehavior> behaviors;
2087             public ReflectedAndBehaviorContractCollection(ReflectedContractCollection reflectedContracts, KeyedByTypeCollection<IServiceBehavior> behaviors)
2088             {
2089                 this.reflectedContracts = reflectedContracts;
2090                 this.behaviors = behaviors;
2091             }
2092
2093             internal bool Contains(Type implementedContract)
2094             {
2095                 if (this.reflectedContracts.Contains(implementedContract))
2096                 {
2097                     return true;
2098                 }
2099
2100                 if (this.behaviors.Contains(typeof(ServiceMetadataBehavior)) && ServiceMetadataBehavior.IsMetadataImplementedType(implementedContract))
2101                 {
2102                     return true;
2103                 }
2104
2105                 return false;
2106             }
2107
2108             internal string GetConfigKey(Type implementedContract)
2109             {
2110                 if (this.reflectedContracts.Contains(implementedContract))
2111                 {
2112                     return ReflectedContractCollection.GetConfigKey(reflectedContracts[implementedContract]);
2113                 }
2114
2115                 if (this.behaviors.Contains(typeof(ServiceMetadataBehavior)) && ServiceMetadataBehavior.IsMetadataImplementedType(implementedContract))
2116                 {
2117                     return ServiceMetadataBehavior.MexContractName;
2118                 }
2119
2120                 Fx.Assert("Calls to GetConfigKey are preceeded by calls to Contains.");
2121 #pragma warning suppress 56506 // implementedContract is never null at this point
2122                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.SfxReflectedContractKeyNotFound2, implementedContract.FullName, string.Empty)));
2123
2124             }
2125         }
2126     }
2127 }