[coop] Temporarily restore MonoThreadInfo when TLS destructor runs. Fixes #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             base.OnOpened();
1081
1082             if (TD.ServiceHostOpenStopIsEnabled())
1083             {
1084                 TD.ServiceHostOpenStop(this.EventTraceActivity);
1085             }
1086         }
1087
1088         internal void OnRemoveChannelDispatcher(ChannelDispatcherBase channelDispatcher)
1089         {
1090             lock (this.ThisLock)
1091             {
1092                 this.ThrowIfClosedOrOpened();
1093                 channelDispatcher.DetachInternal(this);
1094             }
1095         }
1096
1097         void OnChannelDispatcherFaulted(object sender, EventArgs e)
1098         {
1099             this.Fault();
1100         }
1101
1102         void OnServiceHostFaulted(object sender, EventArgs args)
1103         {
1104             if (TD.ServiceHostFaultedIsEnabled())
1105             {
1106                 TD.ServiceHostFaulted(this.EventTraceActivity, this);
1107             }
1108
1109             if (DiagnosticUtility.ShouldTraceWarning)
1110             {
1111                 TraceUtility.TraceEvent(TraceEventType.Warning, TraceCode.ServiceHostFaulted,
1112                     SR.GetString(SR.TraceCodeServiceHostFaulted), this);
1113             }
1114
1115             foreach (ICommunicationObject channelDispatcher in this.SnapshotChannelDispatchers())
1116             {
1117                 if (channelDispatcher.State == CommunicationState.Opened)
1118                 {
1119                     channelDispatcher.Abort();
1120                 }
1121             }
1122         }
1123
1124         internal void RaiseUnknownMessageReceived(Message message)
1125         {
1126             try
1127             {
1128                 EventHandler<UnknownMessageReceivedEventArgs> handler = UnknownMessageReceived;
1129                 if (handler != null)
1130                 {
1131                     handler(this, new UnknownMessageReceivedEventArgs(message));
1132                 }
1133             }
1134             catch (Exception e)
1135             {
1136                 if (Fx.IsFatal(e))
1137                     throw;
1138
1139                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperCallback(e);
1140             }
1141         }
1142
1143         protected void ReleasePerformanceCounters()
1144         {
1145             if (this.servicePerformanceCounters != null)
1146             {
1147                 lock (this.ThisLock)
1148                 {
1149                     if (this.servicePerformanceCounters != null)
1150                     {
1151                         this.servicePerformanceCounters.Dispose();
1152                         this.servicePerformanceCounters = null;
1153                     }
1154                 }
1155             }
1156             if (this.defaultPerformanceCounters != null)
1157             {
1158                 lock (this.ThisLock)
1159                 {
1160                     if (this.defaultPerformanceCounters != null)
1161                     {
1162                         this.defaultPerformanceCounters.Dispose();
1163                         this.defaultPerformanceCounters = null;
1164                     }
1165                 }
1166             }
1167         }
1168
1169         ICommunicationObject[] SnapshotChannelDispatchers()
1170         {
1171             lock (this.ThisLock)
1172             {
1173                 ICommunicationObject[] array = new ICommunicationObject[this.ChannelDispatchers.Count];
1174                 for (int i = 0; i < array.Length; i++)
1175                 {
1176                     array[i] = this.ChannelDispatchers[i];
1177                 }
1178                 return array;
1179             }
1180         }
1181
1182         internal virtual void UnbindInstance(InstanceContext instance)
1183         {
1184             this.instances.Remove(instance);
1185             if (null != this.servicePerformanceCounters)
1186             {
1187                 lock (this.ThisLock)
1188                 {
1189                     if (null != this.servicePerformanceCounters)
1190                     {
1191                         this.servicePerformanceCounters.ServiceInstanceRemoved();
1192                     }
1193                 }
1194             }
1195         }
1196
1197         internal void IncrementBusyCount()
1198         {
1199             if (AspNetEnvironment.Enabled)
1200             {
1201                 AspNetEnvironment.Current.IncrementBusyCount();
1202                 Interlocked.Increment(ref this.busyCount);
1203             }
1204
1205             EventHandler handler = this.BusyCountIncremented;
1206             if (handler != null)
1207             {
1208                 try
1209                 {
1210                     handler(this, EventArgs.Empty);
1211                 }
1212                 catch (Exception exception)
1213                 {
1214                     if (Fx.IsFatal(exception))
1215                         throw;
1216
1217                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperCallback(exception);
1218                 }
1219             }
1220         }
1221
1222         internal void DecrementBusyCount()
1223         {
1224             if (AspNetEnvironment.Enabled)
1225             {
1226                 Interlocked.Decrement(ref this.busyCount);
1227                 AspNetEnvironment.Current.DecrementBusyCount();
1228             }
1229         }
1230
1231         internal int BusyCount
1232         {
1233             get
1234             {
1235                 return this.busyCount;
1236             }
1237         }
1238
1239         class OpenAsyncResult : AsyncResult
1240         {
1241             static AsyncCompletion handleEndAfterInitializeRuntime = new AsyncCompletion(HandleEndAfterInitializeRuntime);
1242             static AsyncCompletion handleEndOpenChannelDispatchers = new AsyncCompletion(HandleEndOpenChannelDispatchers);
1243
1244             TimeoutHelper timeoutHelper;
1245             ServiceHostBase host;
1246
1247             public OpenAsyncResult(ServiceHostBase host, TimeSpan timeout, AsyncCallback callback, object state)
1248                 : base(callback, state)
1249             {
1250                 this.timeoutHelper = new TimeoutHelper(timeout);
1251                 this.host = host;
1252
1253                 if (ProcessAfterInitializeRuntime())
1254                 {
1255                     Complete(true);
1256                 }
1257             }
1258
1259             bool ProcessAfterInitializeRuntime()
1260             {
1261                 IAsyncResult result = this.host.BeginAfterInitializeRuntime(
1262                     this.timeoutHelper.RemainingTime(), PrepareAsyncCompletion(handleEndAfterInitializeRuntime), this);
1263
1264                 return SyncContinue(result);
1265             }
1266
1267             static bool HandleEndAfterInitializeRuntime(IAsyncResult result)
1268             {
1269                 OpenAsyncResult thisPtr = (OpenAsyncResult)result.AsyncState;
1270                 thisPtr.host.EndAfterInitializeRuntime(result);
1271
1272                 return thisPtr.ProcessOpenChannelDispatchers();
1273             }
1274
1275             bool ProcessOpenChannelDispatchers()
1276             {
1277                 IAsyncResult result = this.host.BeginOpenChannelDispatchers(
1278                     this.timeoutHelper.RemainingTime(), PrepareAsyncCompletion(handleEndOpenChannelDispatchers), this);
1279
1280                 return SyncContinue(result);
1281             }
1282
1283             static bool HandleEndOpenChannelDispatchers(IAsyncResult result)
1284             {
1285                 OpenAsyncResult thisPtr = (OpenAsyncResult)result.AsyncState;
1286                 thisPtr.host.EndOpenChannelDispatchers(result);
1287
1288                 return true;
1289             }
1290
1291             public static void End(IAsyncResult result)
1292             {
1293                 AsyncResult.End<OpenAsyncResult>(result);
1294             }
1295         }
1296
1297         class CloseAsyncResult : AsyncResult
1298         {
1299             ServiceHostBase serviceHost;
1300             TimeoutHelper timeoutHelper;
1301
1302             public CloseAsyncResult(TimeSpan timeout, AsyncCallback callback, object state, ServiceHostBase serviceHost)
1303                 : base(callback, state)
1304             {
1305                 this.timeoutHelper = new TimeoutHelper(timeout);
1306                 this.serviceHost = serviceHost;
1307
1308                 if (ManagementExtension.IsEnabled && null != serviceHost.Description)
1309                 {
1310                     ManagementExtension.OnServiceClosing(serviceHost);
1311                 }
1312
1313                 this.CloseListeners(true);
1314             }
1315
1316             void CloseListeners(bool completedSynchronously)
1317             {
1318                 List<ICommunicationObject> listeners = new List<ICommunicationObject>();
1319                 for (int i = 0; i < this.serviceHost.ChannelDispatchers.Count; i++)
1320                 {
1321                     if (this.serviceHost.ChannelDispatchers[i].Listener != null)
1322                     {
1323                         listeners.Add(this.serviceHost.ChannelDispatchers[i].Listener);
1324                     }
1325                 }
1326
1327                 AsyncCallback callback = Fx.ThunkCallback(this.CloseListenersCallback);
1328                 TimeSpan timeout = this.timeoutHelper.RemainingTime();
1329                 Exception exception = null;
1330                 IAsyncResult result = null;
1331                 try
1332                 {
1333                     result = new CloseCollectionAsyncResult(timeout, callback, this, listeners);
1334                 }
1335                 catch (Exception e)
1336                 {
1337                     if (Fx.IsFatal(e) || completedSynchronously)
1338                     {
1339                         throw;
1340                     }
1341                     exception = e;
1342                 }
1343
1344                 if (exception != null)
1345                 {
1346                     this.CallComplete(completedSynchronously, exception);
1347                 }
1348                 else if (result.CompletedSynchronously)
1349                 {
1350                     this.FinishCloseListeners(result, completedSynchronously);
1351                 }
1352             }
1353
1354             void CloseListenersCallback(IAsyncResult result)
1355             {
1356                 if (!result.CompletedSynchronously)
1357                 {
1358                     ((CloseAsyncResult)result.AsyncState).FinishCloseListeners(result, false);
1359                 }
1360             }
1361
1362             void FinishCloseListeners(IAsyncResult result, bool completedSynchronously)
1363             {
1364                 Exception exception = null;
1365                 try
1366                 {
1367                     CloseCollectionAsyncResult.End(result);
1368                 }
1369                 catch (Exception e)
1370                 {
1371                     if (Fx.IsFatal(e) || completedSynchronously)
1372                     {
1373                         throw;
1374                     }
1375                     exception = e;
1376                 }
1377
1378                 if (exception != null)
1379                 {
1380                     this.CallComplete(completedSynchronously, exception);
1381                 }
1382                 else
1383                 {
1384                     this.CloseInput(completedSynchronously);
1385                 }
1386             }
1387
1388             // Wait for existing work to complete
1389             void CloseInput(bool completedSynchronously)
1390             {
1391                 AsyncCallback callback = Fx.ThunkCallback(this.CloseInputCallback);
1392                 Exception exception = null;
1393                 IAsyncResult result = null;
1394
1395                 try
1396                 {
1397                     for (int i = 0; i < this.serviceHost.ChannelDispatchers.Count; i++)
1398                     {
1399                         ChannelDispatcherBase dispatcher = this.serviceHost.ChannelDispatchers[i];
1400                         dispatcher.CloseInput(this.timeoutHelper.RemainingTime());
1401                     }
1402
1403                     result = this.serviceHost.instances.BeginCloseInput(this.timeoutHelper.RemainingTime(), callback, this);
1404                 }
1405                 catch (Exception e)
1406                 {
1407                     if (Fx.IsFatal(e) || completedSynchronously)
1408                     {
1409                         throw;
1410                     }
1411
1412                     exception = e;
1413                 }
1414
1415                 if (exception != null)
1416                 {
1417                     // Any exception during async processing causes this
1418                     // async callback to report the error and then relies on
1419                     // Abort to cleanup any unclosed channels or instance contexts.
1420                     FxTrace.Exception.AsWarning(exception);
1421                     this.CallComplete(completedSynchronously, exception);
1422                 }
1423                 else if (result.CompletedSynchronously)
1424                 {
1425                     this.FinishCloseInput(result, completedSynchronously);
1426                 }
1427             }
1428
1429             void CloseInputCallback(IAsyncResult result)
1430             {
1431                 if (!result.CompletedSynchronously)
1432                 {
1433                     ((CloseAsyncResult)result.AsyncState).FinishCloseInput(result, false);
1434                 }
1435             }
1436
1437             void FinishCloseInput(IAsyncResult result, bool completedSynchronously)
1438             {
1439                 Exception exception = null;
1440                 try
1441                 {
1442                     serviceHost.instances.EndCloseInput(result);
1443                 }
1444                 catch (Exception e)
1445                 {
1446                     if (Fx.IsFatal(e) || completedSynchronously)
1447                     {
1448                         throw;
1449                     }
1450                     exception = e;
1451                 }
1452
1453                 if (exception != null)
1454                 {
1455                     this.CallComplete(completedSynchronously, exception);
1456                 }
1457                 else
1458                 {
1459                     this.CloseInstances(completedSynchronously);
1460                 }
1461             }
1462
1463             // Close instances (closes contexts/channels)
1464             void CloseInstances(bool completedSynchronously)
1465             {
1466                 AsyncCallback callback = Fx.ThunkCallback(this.CloseInstancesCallback);
1467                 TimeSpan timeout = this.timeoutHelper.RemainingTime();
1468                 Exception exception = null;
1469                 IAsyncResult result = null;
1470
1471                 try
1472                 {
1473                     result = this.serviceHost.instances.BeginClose(timeout, callback, this);
1474                 }
1475                 catch (Exception e)
1476                 {
1477                     if (Fx.IsFatal(e) || completedSynchronously)
1478                     {
1479                         throw;
1480                     }
1481                     exception = e;
1482                 }
1483
1484                 if (exception != null)
1485                 {
1486                     this.CallComplete(completedSynchronously, exception);
1487                 }
1488                 else if (result.CompletedSynchronously)
1489                 {
1490                     this.FinishCloseInstances(result, completedSynchronously);
1491                 }
1492             }
1493
1494             void CloseInstancesCallback(IAsyncResult result)
1495             {
1496                 if (!result.CompletedSynchronously)
1497                 {
1498                     ((CloseAsyncResult)result.AsyncState).FinishCloseInstances(result, false);
1499                 }
1500             }
1501
1502             void FinishCloseInstances(IAsyncResult result, bool completedSynchronously)
1503             {
1504                 Exception exception = null;
1505                 try
1506                 {
1507                     this.serviceHost.instances.EndClose(result);
1508                 }
1509                 catch (Exception e)
1510                 {
1511                     if (Fx.IsFatal(e) || completedSynchronously)
1512                     {
1513                         throw;
1514                     }
1515                     exception = e;
1516                 }
1517
1518                 if (exception != null)
1519                 {
1520                     this.CallComplete(completedSynchronously, exception);
1521                 }
1522                 else
1523                 {
1524                     this.CloseChannelDispatchers(completedSynchronously);
1525                 }
1526             }
1527
1528             void CloseChannelDispatchers(bool completedSynchronously)
1529             {
1530                 IList<ICommunicationObject> channelDispatchers = this.serviceHost.SnapshotChannelDispatchers();
1531                 AsyncCallback callback = Fx.ThunkCallback(this.CloseChannelDispatchersCallback);
1532                 TimeSpan timeout = this.timeoutHelper.RemainingTime();
1533                 Exception exception = null;
1534                 IAsyncResult result = null;
1535                 try
1536                 {
1537                     result = new CloseCollectionAsyncResult(timeout, callback, this, channelDispatchers);
1538                 }
1539                 catch (Exception e)
1540                 {
1541                     if (Fx.IsFatal(e) || completedSynchronously)
1542                     {
1543                         throw;
1544                     }
1545                     exception = e;
1546                 }
1547
1548                 if (exception != null)
1549                 {
1550                     this.CallComplete(completedSynchronously, exception);
1551                 }
1552                 else if (result.CompletedSynchronously)
1553                 {
1554                     this.FinishCloseChannelDispatchers(result, completedSynchronously);
1555                 }
1556             }
1557
1558             void CloseChannelDispatchersCallback(IAsyncResult result)
1559             {
1560                 if (!result.CompletedSynchronously)
1561                 {
1562                     ((CloseAsyncResult)result.AsyncState).FinishCloseChannelDispatchers(result, false);
1563                 }
1564             }
1565
1566             void FinishCloseChannelDispatchers(IAsyncResult result, bool completedSynchronously)
1567             {
1568                 Exception exception = null;
1569                 try
1570                 {
1571                     CloseCollectionAsyncResult.End(result);
1572                 }
1573                 catch (Exception e)
1574                 {
1575                     if (Fx.IsFatal(e) || completedSynchronously)
1576                     {
1577                         throw;
1578                     }
1579                     exception = e;
1580                 }
1581
1582                 this.CallComplete(completedSynchronously, exception);
1583             }
1584
1585             void CallComplete(bool completedSynchronously, Exception exception)
1586             {
1587                 this.Complete(completedSynchronously, exception);
1588             }
1589
1590             public static void End(IAsyncResult result)
1591             {
1592                 AsyncResult.End<CloseAsyncResult>(result);
1593             }
1594         }
1595
1596         class ImplementedContractsContractResolver : IContractResolver
1597         {
1598             IDictionary<string, ContractDescription> implementedContracts;
1599
1600             public ImplementedContractsContractResolver(IDictionary<string, ContractDescription> implementedContracts)
1601             {
1602                 this.implementedContracts = implementedContracts;
1603             }
1604
1605             public ContractDescription ResolveContract(string contractName)
1606             {
1607                 return this.implementedContracts != null && this.implementedContracts.ContainsKey(contractName) ? this.implementedContracts[contractName] : null;
1608             }
1609         }
1610
1611         internal class ServiceAndBehaviorsContractResolver : IContractResolver
1612         {
1613             IContractResolver serviceResolver;
1614             Dictionary<string, ContractDescription> behaviorContracts;
1615
1616             public Dictionary<string, ContractDescription> BehaviorContracts
1617             {
1618                 get { return behaviorContracts; }
1619             }
1620
1621             public ServiceAndBehaviorsContractResolver(IContractResolver serviceResolver)
1622             {
1623                 this.serviceResolver = serviceResolver;
1624                 behaviorContracts = new Dictionary<string, ContractDescription>();
1625             }
1626
1627             public ContractDescription ResolveContract(string contractName)
1628             {
1629                 ContractDescription contract = serviceResolver.ResolveContract(contractName);
1630
1631                 if (contract == null)
1632                 {
1633                     contract = this.behaviorContracts.ContainsKey(contractName) ? this.behaviorContracts[contractName] : null;
1634                 }
1635
1636                 return contract;
1637             }
1638
1639             public void AddBehaviorContractsToResolver(KeyedByTypeCollection<IServiceBehavior> behaviors)
1640             {
1641                 // It would be nice to make this loop over all Behaviors... someday.
1642                 if (behaviors != null && behaviors.Contains(typeof(ServiceMetadataBehavior)))
1643                 {
1644                     behaviors.Find<ServiceMetadataBehavior>().AddImplementedContracts(this);
1645                 }
1646             }
1647         }
1648     }
1649
1650     public class ServiceHost : ServiceHostBase
1651     {
1652         object singletonInstance;
1653         Type serviceType;
1654         ReflectedContractCollection reflectedContracts;
1655         IDisposable disposableInstance;
1656
1657         protected ServiceHost()
1658         {
1659         }
1660
1661         public ServiceHost(Type serviceType, params Uri[] baseAddresses)
1662         {
1663             if (serviceType == null)
1664             {
1665                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("serviceType"));
1666             }
1667
1668             this.serviceType = serviceType;
1669             using (ServiceModelActivity activity = DiagnosticUtility.ShouldUseActivity ? ServiceModelActivity.CreateBoundedActivity() : null)
1670             {
1671                 if (DiagnosticUtility.ShouldUseActivity)
1672                 {
1673                     ServiceModelActivity.Start(activity, SR.GetString(SR.ActivityConstructServiceHost, serviceType.FullName), ActivityType.Construct);
1674                 }
1675
1676                 InitializeDescription(serviceType, new UriSchemeKeyedCollection(baseAddresses));
1677             }
1678         }
1679
1680         public ServiceHost(object singletonInstance, params Uri[] baseAddresses)
1681         {
1682             if (singletonInstance == null)
1683             {
1684                 throw new ArgumentNullException("singletonInstance");
1685             }
1686
1687             this.singletonInstance = singletonInstance;
1688             this.serviceType = singletonInstance.GetType();
1689             using (ServiceModelActivity activity = DiagnosticUtility.ShouldUseActivity ? ServiceModelActivity.CreateBoundedActivity() : null)
1690             {
1691                 if (DiagnosticUtility.ShouldUseActivity)
1692                 {
1693                     ServiceModelActivity.Start(activity, SR.GetString(SR.ActivityConstructServiceHost, serviceType.FullName), ActivityType.Construct);
1694                 }
1695
1696                 InitializeDescription(singletonInstance, new UriSchemeKeyedCollection(baseAddresses));
1697             }
1698         }
1699
1700         public object SingletonInstance
1701         {
1702             get
1703             {
1704                 return this.singletonInstance;
1705             }
1706         }
1707
1708         internal override object DisposableInstance
1709         {
1710             get
1711             {
1712                 return this.disposableInstance;
1713             }
1714         }
1715
1716         public ServiceEndpoint AddServiceEndpoint(Type implementedContract, Binding binding, string address)
1717         {
1718             return this.AddServiceEndpoint(implementedContract, binding, address, (Uri)null);
1719         }
1720
1721         public ServiceEndpoint AddServiceEndpoint(Type implementedContract, Binding binding, string address, Uri listenUri)
1722         {
1723             if (address == null)
1724             {
1725                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("address"));
1726             }
1727
1728             ServiceEndpoint endpoint = this.AddServiceEndpoint(implementedContract, binding, new Uri(address, UriKind.RelativeOrAbsolute));
1729             if (listenUri != null)
1730             {
1731                 listenUri = MakeAbsoluteUri(listenUri, binding);
1732                 endpoint.ListenUri = listenUri;
1733             }
1734             return endpoint;
1735         }
1736
1737         public ServiceEndpoint AddServiceEndpoint(Type implementedContract, Binding binding, Uri address)
1738         {
1739             return this.AddServiceEndpoint(implementedContract, binding, address, (Uri)null);
1740         }
1741
1742         void ValidateContractType(Type implementedContract, ReflectedAndBehaviorContractCollection reflectedAndBehaviorContracts)
1743         {
1744             if (!implementedContract.IsDefined(typeof(ServiceContractAttribute), false))
1745             {
1746 #pragma warning suppress 56506 // implementedContract is never null at this point
1747                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.SfxServiceContractAttributeNotFound, implementedContract.FullName)));
1748             }
1749             if (!reflectedAndBehaviorContracts.Contains(implementedContract))
1750             {
1751                 if (implementedContract == typeof(IMetadataExchange))
1752 #pragma warning suppress 56506 // ServiceType is never null at this point
1753                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.SfxReflectedContractKeyNotFoundIMetadataExchange, this.serviceType.FullName)));
1754                 else
1755 #pragma warning suppress 56506 // implementedContract and ServiceType are never null at this point
1756                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.SfxReflectedContractKeyNotFound2, implementedContract.FullName, this.serviceType.FullName)));
1757             }
1758         }
1759
1760         public ServiceEndpoint AddServiceEndpoint(Type implementedContract, Binding binding, Uri address, Uri listenUri)
1761         {
1762             if (implementedContract == null)
1763             {
1764                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("implementedContract"));
1765             }
1766             if (this.reflectedContracts == null)
1767             {
1768                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.SfxReflectedContractsNotInitialized1, implementedContract.FullName)));
1769             }
1770             ReflectedAndBehaviorContractCollection reflectedAndBehaviorContracts = new ReflectedAndBehaviorContractCollection(this.reflectedContracts, this.Description.Behaviors);
1771             ValidateContractType(implementedContract, reflectedAndBehaviorContracts);
1772             ServiceEndpoint endpoint = AddServiceEndpoint(reflectedAndBehaviorContracts.GetConfigKey(implementedContract), binding, address);
1773             if (listenUri != null)
1774             {
1775                 listenUri = MakeAbsoluteUri(listenUri, binding);
1776                 endpoint.ListenUri = listenUri;
1777             }
1778             return endpoint;
1779         }
1780
1781         internal override void AddDefaultEndpoints(Binding defaultBinding, List<ServiceEndpoint> defaultEndpoints)
1782         {
1783             // don't generate endpoints for contracts that serve as the base type for other reflected contracts
1784             List<ContractDescription> mostSpecificContracts = new List<ContractDescription>();
1785             for (int i = 0; i < this.reflectedContracts.Count; i++)
1786             {
1787                 bool addContractEndpoint = true;
1788                 ContractDescription contract = this.reflectedContracts[i];
1789                 Type contractType = contract.ContractType;
1790                 if (contractType != null)
1791                 {
1792                     for (int j = 0; j < this.reflectedContracts.Count; j++)
1793                     {
1794                         ContractDescription otherContract = this.reflectedContracts[j];
1795                         Type otherContractType = otherContract.ContractType;
1796                         if (i == j || otherContractType == null)
1797                         {
1798                             continue;
1799                         }
1800                         if (contractType.IsAssignableFrom(otherContractType))
1801                         {
1802                             addContractEndpoint = false;
1803                             break;
1804                         }
1805                     }
1806                 }
1807                 if (addContractEndpoint)
1808                 {
1809                     mostSpecificContracts.Add(contract);
1810                 }
1811             }
1812
1813             foreach (ContractDescription contract in mostSpecificContracts)
1814             {
1815                 ServiceEndpoint endpoint = AddServiceEndpoint(contract.ConfigurationName, defaultBinding, string.Empty);
1816                 ConfigLoader.LoadDefaultEndpointBehaviors(endpoint);
1817                 defaultEndpoints.Add(endpoint);
1818             }
1819         }
1820
1821         // Run static Configure method on service type if it exists, else load configuration from Web.config/App.config
1822         protected override void ApplyConfiguration()
1823         {
1824             // Load from static Configure method if it exists with the right signature
1825             Type serviceType = this.Description.ServiceType;
1826             if (serviceType != null)
1827             {
1828                 MethodInfo configure = GetConfigureMethod(serviceType);
1829                 if (configure != null)
1830                 {
1831                     // load <host> config
1832                     ConfigLoader configLoader = new ConfigLoader(GetContractResolver(this.ImplementedContracts));
1833                     LoadHostConfigurationInternal(configLoader, this.Description, this.Description.ConfigurationName);
1834
1835                     // Invoke configure method for service
1836                     ServiceConfiguration configuration = new ServiceConfiguration(this);
1837                     InvokeConfigure(configure, configuration);
1838
1839                     return;
1840                 }
1841             }
1842
1843             // else just load from Web.config/App.config
1844             base.ApplyConfiguration();
1845         }
1846
1847         // Find the Configure method with the required signature, closest to serviceType in the type hierarchy
1848         static MethodInfo GetConfigureMethod(Type serviceType)
1849         {
1850             // Use recursion instead of BindingFlags.FlattenHierarchy because we require return type to be void
1851             
1852             // base case: all Types are rooted in object eventually
1853             if (serviceType == typeof(object))
1854             {
1855                 return null;
1856             }
1857
1858             // signature: "public static void Configure(ServiceConfiguration)"
1859             MethodInfo configure = serviceType.GetMethod("Configure", BindingFlags.Static | BindingFlags.Public, null, new[] { typeof(ServiceConfiguration) }, null);
1860
1861             if (configure != null && configure.ReturnType == typeof(void))
1862             {
1863                 return configure;
1864             }
1865             else
1866             {
1867                 return GetConfigureMethod(serviceType.BaseType);
1868             }
1869         }
1870
1871         static void InvokeConfigure(MethodInfo configureMethod, ServiceConfiguration configuration)
1872         {
1873             Action<ServiceConfiguration> call = Delegate.CreateDelegate(typeof(Action<ServiceConfiguration>), configureMethod) as Action<ServiceConfiguration>;
1874             call(configuration);
1875         }
1876
1877         // called from ServiceConfiguration.LoadFromConfiguration()
1878         internal void LoadFromConfiguration()
1879         {
1880             if (this.Description == null)
1881             {
1882                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.SFxServiceHostBaseCannotApplyConfigurationWithoutDescription)));
1883             }
1884
1885             ConfigLoader configLoader = new ConfigLoader(GetContractResolver(this.ImplementedContracts));
1886
1887             // Call the overload of LoadConfigurationSectionInternal which looks up the serviceElement from ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None)
1888             LoadConfigurationSectionExceptHostInternal(configLoader, this.Description, this.Description.ConfigurationName);
1889             EnsureAuthenticationAuthorizationDebug(this.Description);
1890         }
1891
1892         // called from ServiceConfiguration.LoadFromConfiguration(configuration)
1893         internal void LoadFromConfiguration(System.Configuration.Configuration configuration)
1894         {
1895             if (this.Description == null)
1896             {
1897                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.SFxServiceHostBaseCannotApplyConfigurationWithoutDescription)));
1898             }
1899
1900             ConfigLoader configLoader = new ConfigLoader(GetContractResolver(this.ImplementedContracts));
1901
1902             // 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
1903             ServicesSection servicesSection = (ServicesSection)configuration.GetSection(ConfigurationStrings.ServicesSectionPath);
1904             ServiceElement serviceElement = configLoader.LookupService(this.Description.ConfigurationName, servicesSection);
1905             configLoader.LoadServiceDescription(this, this.Description, serviceElement, this.LoadConfigurationSectionHelper, skipHost: true);
1906
1907             EnsureAuthenticationAuthorizationDebug(this.Description);
1908         }
1909
1910         // Load only "host" section within "service" tag
1911         [Fx.Tag.SecurityNote(Critical = "Calls LookupService which is critical.",
1912             Safe = "Doesn't leak ServiceElement out of SecurityCritical code.")]
1913         [SecuritySafeCritical]
1914         void LoadHostConfigurationInternal(ConfigLoader configLoader, ServiceDescription description, string configurationName)
1915         {
1916             ServiceElement serviceSection = configLoader.LookupService(configurationName);
1917             if (serviceSection != null)
1918             {
1919                 configLoader.LoadHostConfig(serviceSection, this, (addr => this.InternalBaseAddresses.Add(addr)));
1920             }
1921         }
1922
1923         // Load service description for service from config, but skip "host" section within "service" tag
1924         [Fx.Tag.SecurityNote(Critical = "Calls LookupService which is critical.",
1925             Safe = "Doesn't leak ServiceElement out of SecurityCritical code.")]
1926         [SecuritySafeCritical]
1927         void LoadConfigurationSectionExceptHostInternal(ConfigLoader configLoader, ServiceDescription description, string configurationName)
1928         {
1929             ServiceElement serviceSection = configLoader.LookupService(configurationName);
1930             configLoader.LoadServiceDescription(this, description, serviceSection, this.LoadConfigurationSectionHelper, skipHost: true);
1931         }
1932         
1933         internal override string CloseActivityName
1934         {
1935             get { return SR.GetString(SR.ActivityCloseServiceHost, this.serviceType.FullName); }
1936         }
1937
1938         internal override string OpenActivityName
1939         {
1940             get { return SR.GetString(SR.ActivityOpenServiceHost, this.serviceType.FullName); }
1941         }
1942
1943         protected override ServiceDescription CreateDescription(out IDictionary<string, ContractDescription> implementedContracts)
1944         {
1945             if (this.serviceType == null)
1946             {
1947                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.SFxServiceHostCannotCreateDescriptionWithoutServiceType)));
1948             }
1949
1950             ServiceDescription description;
1951             if (this.SingletonInstance != null)
1952             {
1953                 description = ServiceDescription.GetService(this.SingletonInstance);
1954             }
1955             else
1956             {
1957                 description = ServiceDescription.GetService(this.serviceType);
1958             }
1959             ServiceBehaviorAttribute serviceBehavior = description.Behaviors.Find<ServiceBehaviorAttribute>();
1960             object serviceInstanceUsedAsABehavior = serviceBehavior.GetWellKnownSingleton();
1961             if (serviceInstanceUsedAsABehavior == null)
1962             {
1963                 serviceInstanceUsedAsABehavior = serviceBehavior.GetHiddenSingleton();
1964                 this.disposableInstance = serviceInstanceUsedAsABehavior as IDisposable;
1965             }
1966
1967             if ((typeof(IServiceBehavior).IsAssignableFrom(this.serviceType) || typeof(IContractBehavior).IsAssignableFrom(this.serviceType))
1968                 && serviceInstanceUsedAsABehavior == null)
1969             {
1970                 serviceInstanceUsedAsABehavior = ServiceDescription.CreateImplementation(this.serviceType);
1971                 this.disposableInstance = serviceInstanceUsedAsABehavior as IDisposable;
1972             }
1973
1974             if (this.SingletonInstance == null)
1975             {
1976                 if (serviceInstanceUsedAsABehavior is IServiceBehavior)
1977                 {
1978                     description.Behaviors.Add((IServiceBehavior)serviceInstanceUsedAsABehavior);
1979                 }
1980             }
1981
1982             ReflectedContractCollection reflectedContracts = new ReflectedContractCollection();
1983             List<Type> interfaces = ServiceReflector.GetInterfaces(this.serviceType);
1984             for (int i = 0; i < interfaces.Count; i++)
1985             {
1986                 Type contractType = interfaces[i];
1987                 if (!reflectedContracts.Contains(contractType))
1988                 {
1989                     ContractDescription contract = null;
1990                     if (serviceInstanceUsedAsABehavior != null)
1991                     {
1992                         contract = ContractDescription.GetContract(contractType, serviceInstanceUsedAsABehavior);
1993                     }
1994                     else
1995                     {
1996                         contract = ContractDescription.GetContract(contractType, this.serviceType);
1997                     }
1998
1999                     reflectedContracts.Add(contract);
2000                     Collection<ContractDescription> inheritedContracts = contract.GetInheritedContracts();
2001                     for (int j = 0; j < inheritedContracts.Count; j++)
2002                     {
2003                         ContractDescription inheritedContract = inheritedContracts[j];
2004                         if (!reflectedContracts.Contains(inheritedContract.ContractType))
2005                         {
2006                             reflectedContracts.Add(inheritedContract);
2007                         }
2008                     }
2009                 }
2010             }
2011             this.reflectedContracts = reflectedContracts;
2012
2013             implementedContracts = reflectedContracts.ToImplementedContracts();
2014             return description;
2015         }
2016
2017         protected void InitializeDescription(object singletonInstance, UriSchemeKeyedCollection baseAddresses)
2018         {
2019             if (singletonInstance == null)
2020             {
2021                 throw new ArgumentNullException("singletonInstance");
2022             }
2023
2024             this.singletonInstance = singletonInstance;
2025             InitializeDescription(singletonInstance.GetType(), baseAddresses);
2026         }
2027
2028         protected void InitializeDescription(Type serviceType, UriSchemeKeyedCollection baseAddresses)
2029         {
2030             if (serviceType == null)
2031             {
2032                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("serviceType"));
2033             }
2034
2035             this.serviceType = serviceType;
2036
2037             base.InitializeDescription(baseAddresses);
2038         }
2039
2040         protected override void OnClosed()
2041         {
2042             base.OnClosed();
2043             if (this.disposableInstance != null)
2044             {
2045                 this.disposableInstance.Dispose();
2046             }
2047         }
2048
2049         class ReflectedContractCollection : KeyedCollection<Type, ContractDescription>
2050         {
2051             public ReflectedContractCollection()
2052                 : base(null, 4)
2053             {
2054             }
2055
2056             protected override Type GetKeyForItem(ContractDescription item)
2057             {
2058                 if (item == null)
2059                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("item");
2060
2061                 return item.ContractType;
2062             }
2063
2064             public IDictionary<string, ContractDescription> ToImplementedContracts()
2065             {
2066                 Dictionary<string, ContractDescription> implementedContracts = new Dictionary<string, ContractDescription>();
2067                 foreach (ContractDescription contract in this.Items)
2068                 {
2069                     implementedContracts.Add(GetConfigKey(contract), contract);
2070                 }
2071                 return implementedContracts;
2072             }
2073
2074             internal static string GetConfigKey(ContractDescription contract)
2075             {
2076                 return contract.ConfigurationName;
2077             }
2078         }
2079
2080         class ReflectedAndBehaviorContractCollection
2081         {
2082             ReflectedContractCollection reflectedContracts;
2083             KeyedByTypeCollection<IServiceBehavior> behaviors;
2084             public ReflectedAndBehaviorContractCollection(ReflectedContractCollection reflectedContracts, KeyedByTypeCollection<IServiceBehavior> behaviors)
2085             {
2086                 this.reflectedContracts = reflectedContracts;
2087                 this.behaviors = behaviors;
2088             }
2089
2090             internal bool Contains(Type implementedContract)
2091             {
2092                 if (this.reflectedContracts.Contains(implementedContract))
2093                 {
2094                     return true;
2095                 }
2096
2097                 if (this.behaviors.Contains(typeof(ServiceMetadataBehavior)) && ServiceMetadataBehavior.IsMetadataImplementedType(implementedContract))
2098                 {
2099                     return true;
2100                 }
2101
2102                 return false;
2103             }
2104
2105             internal string GetConfigKey(Type implementedContract)
2106             {
2107                 if (this.reflectedContracts.Contains(implementedContract))
2108                 {
2109                     return ReflectedContractCollection.GetConfigKey(reflectedContracts[implementedContract]);
2110                 }
2111
2112                 if (this.behaviors.Contains(typeof(ServiceMetadataBehavior)) && ServiceMetadataBehavior.IsMetadataImplementedType(implementedContract))
2113                 {
2114                     return ServiceMetadataBehavior.MexContractName;
2115                 }
2116
2117                 Fx.Assert("Calls to GetConfigKey are preceeded by calls to Contains.");
2118 #pragma warning suppress 56506 // implementedContract is never null at this point
2119                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.SfxReflectedContractKeyNotFound2, implementedContract.FullName, string.Empty)));
2120
2121             }
2122         }
2123     }
2124 }