copied mono-api-diff.cs from mono-2-2 branch so new patch can be applied and history...
[mono.git] / mcs / class / System.ServiceModel / System.ServiceModel / ServiceHostBase.cs
1 //
2 // ServiceHostBase.cs
3 //
4 // Author:
5 //      Atsushi Enomoto <atsushi@ximian.com>
6 //
7 // Copyright (C) 2005-2006 Novell, Inc.  http://www.novell.com
8 //
9 // Permission is hereby granted, free of charge, to any person obtaining
10 // a copy of this software and associated documentation files (the
11 // "Software"), to deal in the Software without restriction, including
12 // without limitation the rights to use, copy, modify, merge, publish,
13 // distribute, sublicense, and/or sell copies of the Software, and to
14 // permit persons to whom the Software is furnished to do so, subject to
15 // the following conditions:
16 // 
17 // The above copyright notice and this permission notice shall be
18 // included in all copies or substantial portions of the Software.
19 // 
20 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
24 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
25 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27 //
28 using System;
29 using System.Collections.Generic;
30 using System.Collections.ObjectModel;
31 using System.Linq;
32 using System.ServiceModel.Channels;
33 using System.ServiceModel.Configuration;
34 using System.ServiceModel.Description;
35 using System.ServiceModel.Dispatcher;
36 using System.ServiceModel.Security;
37 using System.Reflection;
38
39 namespace System.ServiceModel
40 {
41         public abstract partial class ServiceHostBase
42                 : CommunicationObject, IExtensibleObject<ServiceHostBase>, IDisposable
43         {
44                 ServiceCredentials credentials;
45                 ServiceDescription description;
46                 UriSchemeKeyedCollection base_addresses;
47                 TimeSpan open_timeout, close_timeout, instance_idle_timeout;
48                 ServiceThrottle throttle;
49                 List<InstanceContext> contexts;
50                 ReadOnlyCollection<InstanceContext> exposed_contexts;
51                 ChannelDispatcherCollection channel_dispatchers;
52                 IDictionary<string,ContractDescription> contracts;
53                 int flow_limit = int.MaxValue;
54                 IExtensionCollection<ServiceHostBase> extensions;
55
56                 protected ServiceHostBase ()
57                 {
58                         open_timeout = DefaultOpenTimeout;
59                         close_timeout = DefaultCloseTimeout;
60
61                         credentials = new ServiceCredentials ();
62                         throttle = new ServiceThrottle ();
63                         contexts = new List<InstanceContext> ();
64                         exposed_contexts = new ReadOnlyCollection<InstanceContext> (contexts);
65                         channel_dispatchers = new ChannelDispatcherCollection (this);
66                 }
67
68                 public event EventHandler<UnknownMessageReceivedEventArgs>
69                         UnknownMessageReceived;
70
71                 internal void OnUnknownMessageReceived (Message message)
72                 {
73                         if (UnknownMessageReceived != null)
74                                 UnknownMessageReceived (this, new UnknownMessageReceivedEventArgs (message));
75                         else
76                                 // FIXME: better be logged
77                                 throw new EndpointNotFoundException (String.Format ("The request message has the target '{0}' with action '{1}' which is not reachable in this service contract", message.Headers.To, message.Headers.Action));
78                 }
79
80                 public ReadOnlyCollection<Uri> BaseAddresses {
81                         get {
82                                 if (base_addresses == null)
83                                         base_addresses = new UriSchemeKeyedCollection ();
84                                 return new ReadOnlyCollection<Uri> (base_addresses.InternalItems);
85                         }
86                 }
87
88                 internal Uri CreateUri (string scheme, Uri relativeUri)
89                 {
90                         Uri baseUri = base_addresses.Contains (scheme) ? base_addresses [scheme] : null;
91
92                         if (relativeUri == null)
93                                 return baseUri;
94                         if (relativeUri.IsAbsoluteUri)
95                                 return relativeUri;
96                         if (baseUri == null)
97                                 return null;
98                         var s = relativeUri.ToString ();
99                         if (s.Length == 0)
100                                 return baseUri;
101                         var l = baseUri.LocalPath;
102                         var r = relativeUri.ToString ();
103
104                         if (l.Length > 0 && l [l.Length - 1] != '/' && r [0] != '/')
105                                 return new Uri (String.Concat (baseUri.ToString (), "/", r));
106                         else
107                                 return new Uri (String.Concat (baseUri.ToString (), r));
108                 }
109
110                 public ChannelDispatcherCollection ChannelDispatchers {
111                         get { return channel_dispatchers; }
112                 }
113
114                 public ServiceAuthorizationBehavior Authorization {
115                         get;
116                         private set;
117                 }
118
119                 [MonoTODO]
120                 public ServiceCredentials Credentials {
121                         get { return credentials; }
122                 }
123
124                 public ServiceDescription Description {
125                         get { return description; }
126                 }
127
128                 protected IDictionary<string,ContractDescription> ImplementedContracts {
129                         get { return contracts; }
130                 }
131
132                 [MonoTODO]
133                 public IExtensionCollection<ServiceHostBase> Extensions {
134                         get {
135                                 if (extensions == null)
136                                         extensions = new ExtensionCollection<ServiceHostBase> (this);
137                                 return extensions;
138                         }
139                 }
140
141                 protected internal override TimeSpan DefaultCloseTimeout {
142                         get { return DefaultCommunicationTimeouts.Instance.CloseTimeout; }
143                 }
144
145                 protected internal override TimeSpan DefaultOpenTimeout {
146                         get { return DefaultCommunicationTimeouts.Instance.OpenTimeout; }
147                 }
148
149                 public TimeSpan CloseTimeout {
150                         get { return close_timeout; }
151                         set { close_timeout = value; }
152                 }
153
154                 public TimeSpan OpenTimeout {
155                         get { return open_timeout; }
156                         set { open_timeout = value; }
157                 }
158
159                 public int ManualFlowControlLimit {
160                         get { return flow_limit; }
161                         set { flow_limit = value; }
162                 }
163
164                 protected void AddBaseAddress (Uri baseAddress)
165                 {
166                         if (base_addresses == null)
167                                 throw new InvalidOperationException ("Base addresses must be added before the service description is initialized");
168                         base_addresses.Add (baseAddress);
169                 }
170
171                 public ServiceEndpoint AddServiceEndpoint (
172                         string implementedContract, Binding binding, string address)
173                 {
174                         return AddServiceEndpoint (implementedContract,
175                                 binding,
176                                 new Uri (address, UriKind.RelativeOrAbsolute));
177                 }
178
179                 public ServiceEndpoint AddServiceEndpoint (
180                         string implementedContract, Binding binding,
181                         string address, Uri listenUri)
182                 {
183                         Uri uri = new Uri (address, UriKind.RelativeOrAbsolute);
184                         return AddServiceEndpoint (
185                                 implementedContract, binding, uri, listenUri);
186                 }
187
188                 public ServiceEndpoint AddServiceEndpoint (
189                         string implementedContract, Binding binding,
190                         Uri address)
191                 {
192                         return AddServiceEndpoint (implementedContract, binding, address, address);
193                 }
194
195                 public ServiceEndpoint AddServiceEndpoint (
196                         string implementedContract, Binding binding,
197                         Uri address, Uri listenUri)
198                 {
199                         EndpointAddress ea = BuildEndpointAddress (address, binding);
200                         ContractDescription cd = GetContract (implementedContract, binding.Namespace == "http://schemas.microsoft.com/ws/2005/02/mex/bindings");
201                         if (cd == null)
202                                 throw new InvalidOperationException (String.Format ("Contract '{0}' was not found in the implemented contracts in this service host.", implementedContract));
203                         return AddServiceEndpointCore (cd, binding, ea, listenUri);
204                 }
205
206                 Type PopulateType (string typeName)
207                 {
208                         Type type = Type.GetType (typeName);
209                         if (type != null)
210                                 return type;
211                         foreach (ContractDescription cd in ImplementedContracts.Values) {
212                                 type = cd.ContractType.Assembly.GetType (typeName);
213                                 if (type != null)
214                                         return type;
215                         }
216                         return null;
217                 }
218
219                 ContractDescription mex_contract, help_page_contract;
220
221                 ContractDescription GetContract (string name, bool mexBinding)
222                 {
223                         // FIXME: not sure if they should really be special cases.
224                         switch (name) {
225                         case "IHttpGetHelpPageAndMetadataContract":
226                                 if (help_page_contract == null)
227                                         help_page_contract = ContractDescription.GetContract (typeof (IHttpGetHelpPageAndMetadataContract));
228                                 return help_page_contract;
229                         case "IMetadataExchange":
230                                 // this is certainly looking special (or we may 
231                                 // be missing something around ServiceMetadataExtension).
232                                 // It seems .NET WCF has some "infrastructure"
233                                 // endpoints. .NET ServiceHost fails to Open()
234                                 // if it was added only IMetadataExchange 
235                                 // endpoint (and you'll see the word
236                                 // "infrastructure" in the exception message).
237                                 if (mexBinding && Description.Behaviors.Find<ServiceMetadataBehavior> () == null)
238                                         break;
239                                 if (mex_contract == null)
240                                         mex_contract = ContractDescription.GetContract (typeof (IMetadataExchange));
241                                 return mex_contract;
242                         }
243
244                         Type type = PopulateType (name);
245                         if (type == null)
246                                 return null;
247
248                         foreach (ContractDescription cd in ImplementedContracts.Values) {
249                                 // This check is a negative side effect of the above match-by-name design.
250                                 if (cd.ContractType == typeof (IMetadataExchange))
251                                         continue;
252
253                                 if (cd.ContractType == type ||
254                                     cd.ContractType.IsSubclassOf (type) ||
255                                     type.IsInterface && cd.ContractType.GetInterface (type.FullName) == type)
256                                         return cd;
257                         }
258                         return null;
259                 }
260
261                 internal EndpointAddress BuildEndpointAddress (Uri address, Binding binding)
262                 {
263                         if (!address.IsAbsoluteUri) {
264                                 // Find a Base address with matching scheme,
265                                 // and build new absolute address
266                                 if (!base_addresses.Contains (binding.Scheme))
267                                         throw new InvalidOperationException (String.Format ("Could not find base address that matches Scheme {0} for endpoint {1}", binding.Scheme, binding.Name));
268
269                                 Uri baseaddr = base_addresses [binding.Scheme];
270
271                                 if (!baseaddr.AbsoluteUri.EndsWith ("/") && address.OriginalString.Length > 0) // with empty URI it should not add '/' to possible file name of the absolute URI
272                                         baseaddr = new Uri (baseaddr.AbsoluteUri + "/");
273                                 address = new Uri (baseaddr, address);
274                         }
275                         return new EndpointAddress (address);
276                 }
277
278                 internal ServiceEndpoint AddServiceEndpointCore (
279                         ContractDescription cd, Binding binding, EndpointAddress address, Uri listenUri)
280                 {
281                         foreach (ServiceEndpoint e in Description.Endpoints)
282                                 if (e.Contract == cd && e.Binding == binding && e.Address == address && e.ListenUri.Equals (listenUri))
283                                         return e;
284                         ServiceEndpoint se = new ServiceEndpoint (cd, binding, address);
285                         se.ListenUri = listenUri.IsAbsoluteUri ? listenUri : new Uri (address.Uri, listenUri);
286                         Description.Endpoints.Add (se);
287                         return se;
288                 }
289
290                 protected virtual void ApplyConfiguration ()
291                 {
292                         if (Description == null)
293                                 throw new InvalidOperationException ("ApplyConfiguration requires that the Description property be initialized. Either provide a valid ServiceDescription in the CreateDescription method or override the ApplyConfiguration method to provide an alternative implementation");
294
295                         ServiceElement service = GetServiceElement ();
296
297                         //TODO: Should we call here LoadServiceElement ?
298                         if (service != null) {
299                                 
300                                 //base addresses
301                                 HostElement host = service.Host;
302                                 foreach (BaseAddressElement baseAddress in host.BaseAddresses) {
303                                         AddBaseAddress (new Uri (baseAddress.BaseAddress));
304                                 }
305
306                                 // behaviors
307                                 // TODO: use EvaluationContext of ServiceElement.
308                                 ServiceBehaviorElement behavior = ConfigUtil.BehaviorsSection.ServiceBehaviors [service.BehaviorConfiguration];
309                                 if (behavior != null) {
310                                         foreach (var bxe in behavior) {
311                                                 IServiceBehavior b = (IServiceBehavior) bxe.CreateBehavior ();
312                                                 Description.Behaviors.Add (b);
313                                         }
314                                 }
315
316                                 // services
317                                 foreach (ServiceEndpointElement endpoint in service.Endpoints) {
318                                         ServiceEndpoint se = AddServiceEndpoint (
319                                                 endpoint.Contract,
320                                                 ConfigUtil.CreateBinding (endpoint.Binding, endpoint.BindingConfiguration),
321                                                 endpoint.Address.ToString ());
322                                         // endpoint behaviors
323                                         EndpointBehaviorElement epbehavior = ConfigUtil.BehaviorsSection.EndpointBehaviors [endpoint.BehaviorConfiguration];
324                                         if (epbehavior != null)
325                                                 foreach (var bxe in epbehavior) {
326                                                         IEndpointBehavior b = (IEndpointBehavior) bxe.CreateBehavior ();
327                                                         se.Behaviors.Add (b);
328                                         }
329                                 }
330                         }
331                         // TODO: consider commonBehaviors here
332
333                         // ensure ServiceAuthorizationBehavior
334                         Authorization = Description.Behaviors.Find<ServiceAuthorizationBehavior> ();
335                         if (Authorization == null) {
336                                 Authorization = new ServiceAuthorizationBehavior ();
337                                 Description.Behaviors.Add (Authorization);
338                         }
339
340                         // ensure ServiceDebugBehavior
341                         ServiceDebugBehavior debugBehavior = Description.Behaviors.Find<ServiceDebugBehavior> ();
342                         if (debugBehavior == null) {
343                                 debugBehavior = new ServiceDebugBehavior ();
344                                 Description.Behaviors.Add (debugBehavior);
345                         }
346                 }
347
348                 private ServiceElement GetServiceElement() {
349                         Type serviceType = Description.ServiceType;
350                         if (serviceType == null)
351                                 return null;
352
353                         return ConfigUtil.ServicesSection.Services [serviceType.FullName];                      
354                 }
355
356                 protected abstract ServiceDescription CreateDescription (
357                         out IDictionary<string,ContractDescription> implementedContracts);
358
359                 protected void InitializeDescription (UriSchemeKeyedCollection baseAddresses)
360                 {
361                         this.base_addresses = baseAddresses;
362                         IDictionary<string,ContractDescription> retContracts;
363                         description = CreateDescription (out retContracts);
364                         contracts = retContracts;
365
366                         ApplyConfiguration ();
367                 }
368
369                 protected virtual void InitializeRuntime ()
370                 {
371                         //First validate the description, which should call all behaviors
372                         //'Validate' method.
373                         ValidateDescription ();
374                         
375                         //Build all ChannelDispatchers, one dispatcher per user configured EndPoint.
376                         //We must keep thet ServiceEndpoints as a seperate collection, since the user
377                         //can change the collection in the description during the behaviors events.
378                         ServiceEndpoint[] endPoints = new ServiceEndpoint[Description.Endpoints.Count];
379                         Description.Endpoints.CopyTo (endPoints, 0);
380                         var builder = new DispatcherBuilder ();
381                         foreach (ServiceEndpoint se in endPoints) {
382
383                                 var commonParams = new BindingParameterCollection ();
384                                 foreach (IServiceBehavior b in Description.Behaviors)
385                                         b.AddBindingParameters (Description, this, Description.Endpoints, commonParams);
386
387                                 var channel = builder.BuildChannelDispatcher (Description.ServiceType, se, commonParams);
388                                 if (!ChannelDispatchers.Contains (channel))
389                                         ChannelDispatchers.Add (channel);
390                         }
391
392                         //After the ChannelDispatchers are created, and attached to the service host
393                         //Apply dispatching behaviors.
394                         foreach (IServiceBehavior b in Description.Behaviors)
395                                 b.ApplyDispatchBehavior (Description, this);
396
397                         builder.ApplyDispatchBehaviors ();
398                 }
399
400                 private void ValidateDescription ()
401                 {
402                         foreach (IServiceBehavior b in Description.Behaviors)
403                                 b.Validate (Description, this);
404                         foreach (ServiceEndpoint endPoint in Description.Endpoints)
405                                 endPoint.Validate ();
406
407                         if (Description.Endpoints.FirstOrDefault (e => e.Contract != mex_contract) == null)
408                                 throw new InvalidOperationException ("The ServiceHost must have at least one application endpoint (that does not include metadata exchange contract) defined by either configuration, behaviors or call to AddServiceEndpoint methods.");
409                 }
410
411                 [MonoTODO]
412                 protected void LoadConfigurationSection (ServiceElement element)
413                 {
414                         ServicesSection services = ConfigUtil.ServicesSection;
415                 }
416
417                 [MonoTODO]
418                 protected override sealed void OnAbort ()
419                 {
420                 }
421
422                 Action<TimeSpan> close_delegate;
423                 Action<TimeSpan> open_delegate;
424
425                 protected override sealed IAsyncResult OnBeginClose (
426                         TimeSpan timeout, AsyncCallback callback, object state)
427                 {
428                         if (close_delegate != null)
429                                 close_delegate = new Action<TimeSpan> (OnClose);
430                         return close_delegate.BeginInvoke (timeout, callback, state);
431                 }
432
433                 protected override sealed IAsyncResult OnBeginOpen (
434                         TimeSpan timeout, AsyncCallback callback, object state)
435                 {
436                         if (open_delegate == null)
437                                 open_delegate = new Action<TimeSpan> (OnOpen);
438                         return open_delegate.BeginInvoke (timeout, callback, state);
439                 }
440
441                 protected override void OnClose (TimeSpan timeout)
442                 {
443                         DateTime start = DateTime.Now;
444                         ReleasePerformanceCounters ();
445                         List<ChannelDispatcherBase> l = new List<ChannelDispatcherBase> (ChannelDispatchers);
446                         foreach (ChannelDispatcherBase e in l) {
447                                 try {
448                                         TimeSpan ts = timeout - (DateTime.Now - start);
449                                         if (ts < TimeSpan.Zero)
450                                                 e.Abort ();
451                                         else
452                                                 e.Close (ts);
453                                 } catch (Exception ex) {
454                                         Console.WriteLine ("ServiceHostBase failed to close the channel dispatcher:");
455                                         Console.WriteLine (ex);
456                                 }
457                         }
458                 }
459
460                 protected override sealed void OnOpen (TimeSpan timeout)
461                 {
462                         DateTime start = DateTime.Now;
463                         InitializeRuntime ();
464                         foreach (var cd in ChannelDispatchers)
465                                 cd.Open (timeout - (DateTime.Now - start));
466
467                         // FIXME: remove this hack. It should make sure that each ChannelDispatcher's loop has started, using WaitHandle.WaitAll() or something similar.
468                         System.Threading.Thread.Sleep (300);
469                 }
470
471                 protected override void OnEndClose (IAsyncResult result)
472                 {
473                         if (close_delegate == null)
474                                 throw new InvalidOperationException ("Async close operation has not started");
475                         close_delegate.EndInvoke (result);
476                 }
477
478                 protected override sealed void OnEndOpen (IAsyncResult result)
479                 {
480                         if (open_delegate == null)
481                                 throw new InvalidOperationException ("Aync open operation has not started");
482                         open_delegate.EndInvoke (result);
483                 }
484
485                 protected override void OnOpened ()
486                 {
487                         base.OnOpened ();
488                 }
489
490                 [MonoTODO]
491                 protected void ReleasePerformanceCounters ()
492                 {
493                 }
494
495                 void IDisposable.Dispose ()
496                 {
497                         Close ();
498                 }
499
500                 /*
501                 class SyncMethodInvoker : IOperationInvoker
502                 {
503                         readonly MethodInfo _methodInfo;
504                         public SyncMethodInvoker (MethodInfo methodInfo) {
505                                 _methodInfo = methodInfo;
506                         }
507                         
508                         #region IOperationInvoker Members
509
510                         public bool IsSynchronous {
511                                 get { return true; }
512                         }
513
514                         public object [] AllocateParameters () {
515                                 return new object [_methodInfo.GetParameters ().Length];
516                         }
517
518                         public object Invoke (object instance, object [] parameters)
519             {
520                                 return _methodInfo.Invoke (instance, parameters);
521                         }
522
523                         public IAsyncResult InvokeBegin (object instance, object [] inputs, AsyncCallback callback, object state) {
524                                 throw new NotSupportedException ();
525                         }
526
527                         public object InvokeEnd (object instance, out object [] outputs, IAsyncResult result) {
528                                 throw new NotSupportedException ();
529                         }
530
531                         #endregion
532                 }
533
534                 class AsyncMethodInvoker : IOperationInvoker
535                 {
536                         readonly MethodInfo _beginMethodInfo, _endMethodInfo;
537                         public AsyncMethodInvoker (MethodInfo beginMethodInfo, MethodInfo endMethodInfo) {
538                                 _beginMethodInfo = beginMethodInfo;
539                                 _endMethodInfo = endMethodInfo;
540                         }
541
542                         #region IOperationInvoker Members
543
544                         public bool IsSynchronous {
545                                 get { return false; }
546                         }
547
548                         public object [] AllocateParameters () {
549                                 return new object [_beginMethodInfo.GetParameters ().Length - 2 + _endMethodInfo.GetParameters().Length-1];
550                         }
551
552                         public object Invoke (object instance, object [] parameters) {
553                                 throw new NotImplementedException ("Can't invoke async method synchronously");
554                                 //BUGBUG: need to differentiate between input and output parameters.
555                                 IAsyncResult asyncResult = InvokeBegin(instance, parameters, delegate(IAsyncResult ignore) { }, null);
556                                 asyncResult.AsyncWaitHandle.WaitOne();
557                                 return InvokeEnd(instance, out parameters, asyncResult);
558                         }
559
560                         public IAsyncResult InvokeBegin (object instance, object [] inputs, AsyncCallback callback, object state) {
561                                 if (inputs.Length + 2 != _beginMethodInfo.GetParameters ().Length)
562                                         throw new ArgumentException ("Wrong number of input parameters");
563                                 object [] fullargs = new object [_beginMethodInfo.GetParameters ().Length];
564                                 Array.Copy (inputs, fullargs, inputs.Length);
565                                 fullargs [inputs.Length] = callback;
566                                 fullargs [inputs.Length + 1] = state;
567                                 return (IAsyncResult) _beginMethodInfo.Invoke (instance, fullargs);
568                         }
569
570                         public object InvokeEnd (object instance, out object [] outputs, IAsyncResult asyncResult) {
571                                 outputs = new object [_endMethodInfo.GetParameters ().Length - 1];
572                                 object [] fullargs = new object [_endMethodInfo.GetParameters ().Length];
573                                 fullargs [outputs.Length] = asyncResult;
574                                 object result = _endMethodInfo.Invoke (instance, fullargs);
575                                 Array.Copy (fullargs, outputs, outputs.Length);
576                                 return result;
577                         }
578
579                         #endregion
580                 }
581                 */
582         }
583
584         /// <summary>
585         ///  Builds ChannelDispatchers as appropriate to service the service endpoints. 
586         /// </summary>
587         /// <remarks>Will re-use ChannelDispatchers when two endpoint uris are the same</remarks>
588         partial class DispatcherBuilder
589         {
590                 List<ChannelDispatcher> built_dispatchers = new List<ChannelDispatcher> ();
591                 Dictionary<ServiceEndpoint, EndpointDispatcher> ep_to_dispatcher_ep = new Dictionary<ServiceEndpoint, EndpointDispatcher> ();
592                 
593                 internal ChannelDispatcher BuildChannelDispatcher (Type serviceType, ServiceEndpoint se, BindingParameterCollection commonParams)
594                 {
595                         //Let all behaviors add their binding parameters
596                         AddBindingParameters (commonParams, se);
597                         
598                         // See if there's an existing channel that matches this endpoint
599                         ChannelDispatcher cd = FindExistingDispatcher (se);
600                         EndpointDispatcher ep;
601                         if (cd != null) {
602                                 ep = cd.InitializeServiceEndpoint (serviceType, se);
603                         } else {
604                                 // Use the binding parameters to build the channel listener and Dispatcher.
605                                 IChannelListener lf = BuildListener (se, commonParams);
606                                 cd = new ChannelDispatcher (
607                                         lf, se.Binding.Name);
608                                 ep = cd.InitializeServiceEndpoint (serviceType, se);
609                                 built_dispatchers.Add (cd);
610                         }
611                         ep_to_dispatcher_ep[se] = ep;
612                         return cd;
613                 }
614                 
615                 ChannelDispatcher FindExistingDispatcher (ServiceEndpoint se)
616                 {
617                         return built_dispatchers.FirstOrDefault ((ChannelDispatcher cd) => (cd.Listener.Uri.Equals (se.ListenUri)) && cd.MessageVersion.Equals (se.Binding.MessageVersion));
618                 }
619
620                 internal void ApplyDispatchBehaviors ()
621                 {
622                         foreach (KeyValuePair<ServiceEndpoint, EndpointDispatcher> val in ep_to_dispatcher_ep)
623                                 ApplyDispatchBehavior (val.Value, val.Key);
624                 }
625                 
626                 private void ApplyDispatchBehavior (EndpointDispatcher ed, ServiceEndpoint endPoint)
627                 {
628                         foreach (IContractBehavior b in endPoint.Contract.Behaviors)
629                                 b.ApplyDispatchBehavior (endPoint.Contract, endPoint, ed.DispatchRuntime);
630                         foreach (IEndpointBehavior b in endPoint.Behaviors)
631                                 b.ApplyDispatchBehavior (endPoint, ed);
632                         foreach (OperationDescription operation in endPoint.Contract.Operations) {
633                                 foreach (IOperationBehavior b in operation.Behaviors)
634                                         b.ApplyDispatchBehavior (operation, ed.DispatchRuntime.Operations [operation.Name]);
635                         }
636
637                 }
638
639                 private void AddBindingParameters (BindingParameterCollection commonParams, ServiceEndpoint endPoint) {
640
641                         commonParams.Add (ChannelProtectionRequirements.CreateFromContract (endPoint.Contract));
642
643                         foreach (IContractBehavior b in endPoint.Contract.Behaviors)
644                                 b.AddBindingParameters (endPoint.Contract, endPoint, commonParams);
645                         foreach (IEndpointBehavior b in endPoint.Behaviors)
646                                 b.AddBindingParameters (endPoint, commonParams);
647                         foreach (OperationDescription operation in endPoint.Contract.Operations) {
648                                 foreach (IOperationBehavior b in operation.Behaviors)
649                                         b.AddBindingParameters (operation, commonParams);
650                         }
651                 }
652
653                 static IChannelListener BuildListener (ServiceEndpoint se,
654                         BindingParameterCollection pl)
655                 {
656                         Binding b = se.Binding;
657                         if (b.CanBuildChannelListener<IReplySessionChannel> (pl))
658                                 return b.BuildChannelListener<IReplySessionChannel> (se.ListenUri, "", se.ListenUriMode, pl);
659                         if (b.CanBuildChannelListener<IReplyChannel> (pl))
660                                 return b.BuildChannelListener<IReplyChannel> (se.ListenUri, "", se.ListenUriMode, pl);
661                         if (b.CanBuildChannelListener<IInputSessionChannel> (pl))
662                                 return b.BuildChannelListener<IInputSessionChannel> (se.ListenUri, "", se.ListenUriMode, pl);
663                         if (b.CanBuildChannelListener<IInputChannel> (pl))
664                                 return b.BuildChannelListener<IInputChannel> (se.ListenUri, "", se.ListenUriMode, pl);
665
666                         if (b.CanBuildChannelListener<IDuplexChannel> (pl))
667                                 return b.BuildChannelListener<IDuplexChannel> (se.ListenUri, "", se.ListenUriMode, pl);
668                         if (b.CanBuildChannelListener<IDuplexSessionChannel> (pl))
669                                 return b.BuildChannelListener<IDuplexSessionChannel> (se.ListenUri, "", se.ListenUriMode, pl);
670                         throw new InvalidOperationException ("None of the listener channel types is supported");
671                 }
672         }
673 }