2009-10-07 Atsushi Enomoto <atsushi@ximian.com>
[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.ServiceModel.Channels;
32 using System.ServiceModel.Configuration;
33 using System.ServiceModel.Description;
34 using System.ServiceModel.Dispatcher;
35 using System.ServiceModel.Security;
36 using System.Reflection;
37
38 namespace System.ServiceModel
39 {
40         public abstract partial class ServiceHostBase
41                 : CommunicationObject, IExtensibleObject<ServiceHostBase>, IDisposable
42         {
43                 ServiceCredentials credentials;
44                 ServiceDescription description;
45                 UriSchemeKeyedCollection base_addresses;
46                 TimeSpan open_timeout, close_timeout, instance_idle_timeout;
47                 ServiceThrottle throttle;
48                 List<InstanceContext> contexts;
49                 ReadOnlyCollection<InstanceContext> exposed_contexts;
50                 ChannelDispatcherCollection channel_dispatchers;
51                 IDictionary<string,ContractDescription> contracts;
52                 int flow_limit = int.MaxValue;
53                 IExtensionCollection<ServiceHostBase> extensions;
54
55                 protected ServiceHostBase ()
56                 {
57                         open_timeout = DefaultOpenTimeout;
58                         close_timeout = DefaultCloseTimeout;
59
60                         credentials = new ServiceCredentials ();
61                         throttle = new ServiceThrottle ();
62                         contexts = new List<InstanceContext> ();
63                         exposed_contexts = new ReadOnlyCollection<InstanceContext> (contexts);
64                         channel_dispatchers = new ChannelDispatcherCollection (this);
65                 }
66
67                 public event EventHandler<UnknownMessageReceivedEventArgs>
68                         UnknownMessageReceived;
69
70                 internal void OnUnknownMessageReceived (Message message)
71                 {
72                         if (UnknownMessageReceived != null)
73                                 UnknownMessageReceived (this, new UnknownMessageReceivedEventArgs (message));
74                         else
75                                 // FIXME: better be logged
76                                 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));
77                 }
78
79                 public ReadOnlyCollection<Uri> BaseAddresses {
80                         get {
81                                 if (base_addresses == null)
82                                         base_addresses = new UriSchemeKeyedCollection ();
83                                 return new ReadOnlyCollection<Uri> (base_addresses.InternalItems);
84                         }
85                 }
86
87                 internal Uri CreateUri (string sheme, Uri relatieUri) {
88                         Uri baseUri = base_addresses.Contains (sheme) ? base_addresses [sheme] : null;
89
90                         if (relatieUri == null)
91                                 return baseUri;
92                         if (relatieUri.IsAbsoluteUri)
93                                 return relatieUri;
94                         if (baseUri == null)
95                                 return null;
96                         return new Uri (baseUri, relatieUri);
97                 }
98
99                 public ChannelDispatcherCollection ChannelDispatchers {
100                         get { return channel_dispatchers; }
101                 }
102
103                 public ServiceAuthorizationBehavior Authorization {
104                         get;
105                         private set;
106                 }
107
108                 [MonoTODO]
109                 public ServiceCredentials Credentials {
110                         get { return credentials; }
111                 }
112
113                 public ServiceDescription Description {
114                         get { return description; }
115                 }
116
117                 protected IDictionary<string,ContractDescription> ImplementedContracts {
118                         get { return contracts; }
119                 }
120
121                 [MonoTODO]
122                 public IExtensionCollection<ServiceHostBase> Extensions {
123                         get {
124                                 if (extensions == null)
125                                         extensions = new ExtensionCollection<ServiceHostBase> (this);
126                                 return extensions;
127                         }
128                 }
129
130                 protected internal override TimeSpan DefaultCloseTimeout {
131                         get { return DefaultCommunicationTimeouts.Instance.CloseTimeout; }
132                 }
133
134                 protected internal override TimeSpan DefaultOpenTimeout {
135                         get { return DefaultCommunicationTimeouts.Instance.OpenTimeout; }
136                 }
137
138                 public TimeSpan CloseTimeout {
139                         get { return close_timeout; }
140                         set { close_timeout = value; }
141                 }
142
143                 public TimeSpan OpenTimeout {
144                         get { return open_timeout; }
145                         set { open_timeout = value; }
146                 }
147
148                 public int ManualFlowControlLimit {
149                         get { return flow_limit; }
150                         set { flow_limit = value; }
151                 }
152
153                 protected void AddBaseAddress (Uri baseAddress)
154                 {
155                         if (Description != null)
156                                 throw new InvalidOperationException ("Base addresses must be added before the service description is initialized");
157                         base_addresses.Add (baseAddress);
158                 }
159
160                 public ServiceEndpoint AddServiceEndpoint (
161                         string implementedContract, Binding binding, string address)
162                 {
163                         return AddServiceEndpoint (implementedContract,
164                                 binding,
165                                 new Uri (address, UriKind.RelativeOrAbsolute));
166                 }
167
168                 public ServiceEndpoint AddServiceEndpoint (
169                         string implementedContract, Binding binding,
170                         string address, Uri listenUri)
171                 {
172                         Uri uri = new Uri (address, UriKind.RelativeOrAbsolute);
173                         return AddServiceEndpoint (
174                                 implementedContract, binding, uri, listenUri);
175                 }
176
177                 public ServiceEndpoint AddServiceEndpoint (
178                         string implementedContract, Binding binding,
179                         Uri address)
180                 {
181                         return AddServiceEndpoint (implementedContract, binding, address, address);
182                 }
183
184                 public ServiceEndpoint AddServiceEndpoint (
185                         string implementedContract, Binding binding,
186                         Uri address, Uri listenUri)
187                 {
188                         EndpointAddress ea = BuildEndpointAddress (address, binding);
189                         ContractDescription cd = GetContract (implementedContract);
190                         if (cd == null)
191                                 throw new InvalidOperationException (String.Format ("Contract '{0}' was not found in the implemented contracts in this service host.", implementedContract));
192                         return AddServiceEndpointCore (cd, binding, ea, listenUri);
193                 }
194
195                 Type PopulateType (string typeName)
196                 {
197                         Type type = Type.GetType (typeName);
198                         if (type != null)
199                                 return type;
200                         foreach (ContractDescription cd in ImplementedContracts.Values) {
201                                 type = cd.ContractType.Assembly.GetType (typeName);
202                                 if (type != null)
203                                         return type;
204                         }
205                         return null;
206                 }
207
208                 ContractDescription mex_contract, help_page_contract;
209
210                 ContractDescription GetContract (string name)
211                 {
212                         // FIXME: not sure if they should really be special cases.
213                         switch (name) {
214                         case "IHttpGetHelpPageAndMetadataContract":
215                                 if (help_page_contract == null)
216                                         help_page_contract = ContractDescription.GetContract (typeof (IHttpGetHelpPageAndMetadataContract));
217                                 return help_page_contract;
218                         case "IMetadataExchange":
219                                 // this is certainly looking special (or we may 
220                                 // be missing something around ServiceMetadataExtension)
221                                 if (Extensions.Find<ServiceMetadataExtension> () == null)
222                                         break;
223                                 if (mex_contract == null)
224                                         mex_contract = ContractDescription.GetContract (typeof (IMetadataExchange));
225                                 return mex_contract;
226                         }
227
228                         // FIXME: probably type-to-contract-name mapping is wrong. 
229                         // This "loopup by type name" incorrectly allows
230                         // "System.ServiceModel.Description.IMetadataExchange",
231                         // but disabling this results in couple of regressions.
232                         // So I keep enabling it so far. But it smells wrong.
233                         Type type = PopulateType (name);
234
235                         foreach (ContractDescription cd in ImplementedContracts.Values) {
236                                 if (type == null) {
237                                         if (cd.Name == name)
238                                                 return cd;
239                                         continue;
240                                 }
241
242                                 // FIXME: This check is a negative side effect 
243                                 // of the above hack. (but it should not still 
244                                 // skip name-based match). Seealso above FIXMEs.
245                                 if (cd.ContractType == typeof (IMetadataExchange))
246                                         continue;
247
248                                 if (cd.ContractType == type ||
249                                     cd.ContractType.IsSubclassOf (type) ||
250                                     type.IsInterface && cd.ContractType.GetInterface (type.FullName) == type)
251                                         return cd;
252                         }
253                         return null;
254                 }
255
256                 internal EndpointAddress BuildEndpointAddress (Uri address, Binding binding)
257                 {
258                         if (!address.IsAbsoluteUri) {
259                                 // Find a Base address with matching scheme,
260                                 // and build new absolute address
261                                 if (!base_addresses.Contains (binding.Scheme))
262                                         throw new InvalidOperationException (String.Format ("Could not find base address that matches Scheme {0} for endpoint {1}", binding.Scheme, binding.Name));
263
264                                 Uri baseaddr = base_addresses [binding.Scheme];
265
266                                 if (!baseaddr.AbsoluteUri.EndsWith ("/") && address.OriginalString.Length > 0) // with empty URI it should not add '/' to possible file name of the absolute URI
267                                         baseaddr = new Uri (baseaddr.AbsoluteUri + "/");
268                                 address = new Uri (baseaddr, address);
269                         }
270                         return new EndpointAddress (address);
271                 }
272
273                 internal ServiceEndpoint AddServiceEndpointCore (
274                         ContractDescription cd, Binding binding, EndpointAddress address, Uri listenUri)
275                 {
276                         foreach (ServiceEndpoint e in Description.Endpoints)
277                                 if (e.Contract == cd)
278                                         return e;
279                         ServiceEndpoint se = new ServiceEndpoint (cd, binding, address);
280                         se.ListenUri = listenUri.IsAbsoluteUri ? listenUri : new Uri (address.Uri, listenUri);
281                         Description.Endpoints.Add (se);
282                         return se;
283                 }
284
285                 [MonoTODO]
286                 protected virtual void ApplyConfiguration ()
287                 {
288                         if (Description == null)
289                                 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");
290
291                         ServiceElement service = GetServiceElement ();
292
293                         //TODO: Should we call here LoadServiceElement ?
294                         if (service != null) {
295                                 
296                                 //base addresses
297                                 HostElement host = service.Host;
298                                 foreach (BaseAddressElement baseAddress in host.BaseAddresses) {
299                                         AddBaseAddress (new Uri (baseAddress.BaseAddress));
300                                 }
301
302                                 // behaviors
303                                 // TODO: use EvaluationContext of ServiceElement.
304                                 ServiceBehaviorElement behavior = ConfigUtil.BehaviorsSection.ServiceBehaviors [service.BehaviorConfiguration];
305                                 if (behavior != null) {
306                                         foreach (var bxe in behavior) {
307                                                 IServiceBehavior b = (IServiceBehavior) bxe.CreateBehavior ();
308                                                 Description.Behaviors.Add (b);
309                                         }
310                                 }
311
312                                 // services
313                                 foreach (ServiceEndpointElement endpoint in service.Endpoints) {
314                                         // FIXME: consider BindingName as well
315                                         ServiceEndpoint se = AddServiceEndpoint (
316                                                 endpoint.Contract,
317                                                 ConfigUtil.CreateBinding (endpoint.Binding, endpoint.BindingConfiguration),
318                                                 endpoint.Address.ToString ());
319                                         // endpoint behaviors
320                                         EndpointBehaviorElement epbehavior = ConfigUtil.BehaviorsSection.EndpointBehaviors [endpoint.BehaviorConfiguration];
321                                         if (epbehavior != null)
322                                                 foreach (var bxe in epbehavior) {
323                                                         IEndpointBehavior b = (IEndpointBehavior) bxe.CreateBehavior ();
324                                                         se.Behaviors.Add (b);
325                                         }
326                                 }
327                         }
328                         // TODO: consider commonBehaviors here
329
330                         // ensure ServiceAuthorizationBehavior
331                         Authorization = Description.Behaviors.Find<ServiceAuthorizationBehavior> ();
332                         if (Authorization == null) {
333                                 Authorization = new ServiceAuthorizationBehavior ();
334                                 Description.Behaviors.Add (Authorization);
335                         }
336
337                         // ensure ServiceDebugBehavior
338                         ServiceDebugBehavior debugBehavior = Description.Behaviors.Find<ServiceDebugBehavior> ();
339                         if (debugBehavior == null) {
340                                 debugBehavior = new ServiceDebugBehavior ();
341                                 Description.Behaviors.Add (debugBehavior);
342                         }
343                 }
344
345                 private ServiceElement GetServiceElement() {
346                         Type serviceType = Description.ServiceType;
347                         if (serviceType == null)
348                                 return null;
349
350                         return ConfigUtil.ServicesSection.Services [serviceType.FullName];                      
351                 }
352
353                 protected abstract ServiceDescription CreateDescription (
354                         out IDictionary<string,ContractDescription> implementedContracts);
355
356                 protected void InitializeDescription (UriSchemeKeyedCollection baseAddresses)
357                 {
358                         this.base_addresses = baseAddresses;
359                         IDictionary<string,ContractDescription> retContracts;
360                         description = CreateDescription (out retContracts);
361                         contracts = retContracts;
362
363                         ApplyConfiguration ();
364                 }
365
366                 protected virtual void InitializeRuntime ()
367                 {
368                         //First validate the description, which should call all behaviors
369                         //'Validate' method.
370                         ValidateDescription ();
371                         
372                         //Build all ChannelDispatchers, one dispatcher per user configured EndPoint.
373                         //We must keep thet ServiceEndpoints as a seperate collection, since the user
374                         //can change the collection in the description during the behaviors events.
375                         Dictionary<ServiceEndpoint, ChannelDispatcher> endPointToDispatcher = new Dictionary<ServiceEndpoint,ChannelDispatcher>();
376                         ServiceEndpoint[] endPoints = new ServiceEndpoint[Description.Endpoints.Count];
377                         Description.Endpoints.CopyTo (endPoints, 0);
378                         foreach (ServiceEndpoint se in endPoints) {
379
380                                 var commonParams = new BindingParameterCollection ();
381                                 foreach (IServiceBehavior b in Description.Behaviors)
382                                         b.AddBindingParameters (Description, this, Description.Endpoints, commonParams);
383
384                                 ChannelDispatcher channel = BuildChannelDispatcher (se, commonParams);
385                                 ChannelDispatchers.Add (channel);
386                                 endPointToDispatcher[se] = channel;
387                         }
388
389                         //After the ChannelDispatchers are created, and attached to the service host
390                         //Apply dispatching behaviors.
391                         foreach (IServiceBehavior b in Description.Behaviors)
392                                 b.ApplyDispatchBehavior (Description, this);
393
394                         foreach(KeyValuePair<ServiceEndpoint, ChannelDispatcher> val in endPointToDispatcher)
395                                 foreach (var ed in val.Value.Endpoints)
396                                         ApplyDispatchBehavior (ed, val.Key);                    
397                 }
398
399                 private void ValidateDescription ()
400                 {
401                         foreach (IServiceBehavior b in Description.Behaviors)
402                                 b.Validate (Description, this);
403                         foreach (ServiceEndpoint endPoint in Description.Endpoints)
404                                 endPoint.Validate ();
405                 }               
406
407                 private void ApplyDispatchBehavior (EndpointDispatcher ed, ServiceEndpoint endPoint)
408                 {
409                         foreach (IContractBehavior b in endPoint.Contract.Behaviors)
410                                 b.ApplyDispatchBehavior (endPoint.Contract, endPoint, ed.DispatchRuntime);
411                         foreach (IEndpointBehavior b in endPoint.Behaviors)
412                                 b.ApplyDispatchBehavior (endPoint, ed);
413                         foreach (OperationDescription operation in endPoint.Contract.Operations) {
414                                 foreach (IOperationBehavior b in operation.Behaviors)
415                                         b.ApplyDispatchBehavior (operation, ed.DispatchRuntime.Operations [operation.Name]);
416                         }
417
418                 }
419
420                 internal ChannelDispatcher BuildChannelDispatcher (ServiceEndpoint se, BindingParameterCollection commonParams)
421                 {
422                         return new DispatcherBuilder ().BuildChannelDispatcher (Description.ServiceType, se, commonParams);
423                 }
424
425                 [MonoTODO]
426                 protected void LoadConfigurationSection (ServiceElement element)
427                 {
428                         ServicesSection services = ConfigUtil.ServicesSection;
429                 }
430
431                 void DoOpen (TimeSpan timeout)
432                 {
433                         foreach (var cd in ChannelDispatchers) {
434                                 cd.Open (timeout);
435                                 // This is likely hack.
436                                 if (cd is ChannelDispatcher)
437                                         ((ChannelDispatcher) cd).StartLoop ();
438                         }
439                 }
440
441                 [MonoTODO]
442                 protected override sealed void OnAbort ()
443                 {
444                 }
445
446                 Action<TimeSpan> close_delegate;
447                 Action<TimeSpan> open_delegate;
448
449                 protected override sealed IAsyncResult OnBeginClose (
450                         TimeSpan timeout, AsyncCallback callback, object state)
451                 {
452                         if (close_delegate != null)
453                                 close_delegate = new Action<TimeSpan> (OnClose);
454                         return close_delegate.BeginInvoke (timeout, callback, state);
455                 }
456
457                 protected override sealed IAsyncResult OnBeginOpen (
458                         TimeSpan timeout, AsyncCallback callback, object state)
459                 {
460                         if (open_delegate == null)
461                                 open_delegate = new Action<TimeSpan> (OnOpen);
462                         return open_delegate.BeginInvoke (timeout, callback, state);
463                 }
464
465                 protected override void OnClose (TimeSpan timeout)
466                 {
467                         DateTime start = DateTime.Now;
468                         ReleasePerformanceCounters ();
469                         List<ChannelDispatcherBase> l = new List<ChannelDispatcherBase> (ChannelDispatchers);
470                         foreach (ChannelDispatcherBase e in l) {
471                                 try {
472                                         TimeSpan ts = timeout - (DateTime.Now - start);
473                                         if (ts < TimeSpan.Zero)
474                                                 e.Abort ();
475                                         else
476                                                 e.Close (ts);
477                                 } catch (Exception ex) {
478                                         Console.WriteLine ("ServiceHostBase failed to close the channel dispatcher:");
479                                         Console.WriteLine (ex);
480                                 }
481                         }
482                 }
483
484                 protected override sealed void OnOpen (TimeSpan timeout)
485                 {
486                         InitializeRuntime ();
487                         DoOpen (timeout);
488                 }
489
490                 protected override void OnEndClose (IAsyncResult result)
491                 {
492                         if (close_delegate == null)
493                                 throw new InvalidOperationException ("Async close operation has not started");
494                         close_delegate.EndInvoke (result);
495                 }
496
497                 protected override sealed void OnEndOpen (IAsyncResult result)
498                 {
499                         if (open_delegate == null)
500                                 throw new InvalidOperationException ("Aync open operation has not started");
501                         open_delegate.EndInvoke (result);
502                 }
503
504                 protected override void OnOpened ()
505                 {
506                         base.OnOpened ();
507                 }
508
509                 [MonoTODO]
510                 protected void ReleasePerformanceCounters ()
511                 {
512                 }
513
514                 void IDisposable.Dispose ()
515                 {
516                         Close ();
517                 }
518
519                 /*
520                 class SyncMethodInvoker : IOperationInvoker
521                 {
522                         readonly MethodInfo _methodInfo;
523                         public SyncMethodInvoker (MethodInfo methodInfo) {
524                                 _methodInfo = methodInfo;
525                         }
526                         
527                         #region IOperationInvoker Members
528
529                         public bool IsSynchronous {
530                                 get { return true; }
531                         }
532
533                         public object [] AllocateParameters () {
534                                 return new object [_methodInfo.GetParameters ().Length];
535                         }
536
537                         public object Invoke (object instance, object [] parameters)
538             {
539                                 return _methodInfo.Invoke (instance, parameters);
540                         }
541
542                         public IAsyncResult InvokeBegin (object instance, object [] inputs, AsyncCallback callback, object state) {
543                                 throw new NotSupportedException ();
544                         }
545
546                         public object InvokeEnd (object instance, out object [] outputs, IAsyncResult result) {
547                                 throw new NotSupportedException ();
548                         }
549
550                         #endregion
551                 }
552
553                 class AsyncMethodInvoker : IOperationInvoker
554                 {
555                         readonly MethodInfo _beginMethodInfo, _endMethodInfo;
556                         public AsyncMethodInvoker (MethodInfo beginMethodInfo, MethodInfo endMethodInfo) {
557                                 _beginMethodInfo = beginMethodInfo;
558                                 _endMethodInfo = endMethodInfo;
559                         }
560
561                         #region IOperationInvoker Members
562
563                         public bool IsSynchronous {
564                                 get { return false; }
565                         }
566
567                         public object [] AllocateParameters () {
568                                 return new object [_beginMethodInfo.GetParameters ().Length - 2 + _endMethodInfo.GetParameters().Length-1];
569                         }
570
571                         public object Invoke (object instance, object [] parameters) {
572                                 throw new NotImplementedException ("Can't invoke async method synchronously");
573                                 //BUGBUG: need to differentiate between input and output parameters.
574                                 IAsyncResult asyncResult = InvokeBegin(instance, parameters, delegate(IAsyncResult ignore) { }, null);
575                                 asyncResult.AsyncWaitHandle.WaitOne();
576                                 return InvokeEnd(instance, out parameters, asyncResult);
577                         }
578
579                         public IAsyncResult InvokeBegin (object instance, object [] inputs, AsyncCallback callback, object state) {
580                                 if (inputs.Length + 2 != _beginMethodInfo.GetParameters ().Length)
581                                         throw new ArgumentException ("Wrong number of input parameters");
582                                 object [] fullargs = new object [_beginMethodInfo.GetParameters ().Length];
583                                 Array.Copy (inputs, fullargs, inputs.Length);
584                                 fullargs [inputs.Length] = callback;
585                                 fullargs [inputs.Length + 1] = state;
586                                 return (IAsyncResult) _beginMethodInfo.Invoke (instance, fullargs);
587                         }
588
589                         public object InvokeEnd (object instance, out object [] outputs, IAsyncResult asyncResult) {
590                                 outputs = new object [_endMethodInfo.GetParameters ().Length - 1];
591                                 object [] fullargs = new object [_endMethodInfo.GetParameters ().Length];
592                                 fullargs [outputs.Length] = asyncResult;
593                                 object result = _endMethodInfo.Invoke (instance, fullargs);
594                                 Array.Copy (fullargs, outputs, outputs.Length);
595                                 return result;
596                         }
597
598                         #endregion
599                 }
600                 */
601         }
602
603         partial class DispatcherBuilder
604         {
605                 internal ChannelDispatcher BuildChannelDispatcher (Type serviceType, ServiceEndpoint se, BindingParameterCollection commonParams)
606                 {
607                         //Let all behaviors add their binding parameters
608                         AddBindingParameters (commonParams, se);
609                         //User the binding parameters to build the channel listener and Dispatcher
610                         IChannelListener lf = BuildListener (se, commonParams);
611                         ChannelDispatcher cd = new ChannelDispatcher (
612                                 lf, se.Binding.Name);
613                         cd.InitializeServiceEndpoint (serviceType, se);
614                         return cd;
615                 }
616
617                 private void AddBindingParameters (BindingParameterCollection commonParams, ServiceEndpoint endPoint) {
618
619                         commonParams.Add (ChannelProtectionRequirements.CreateFromContract (endPoint.Contract));
620
621                         foreach (IContractBehavior b in endPoint.Contract.Behaviors)
622                                 b.AddBindingParameters (endPoint.Contract, endPoint, commonParams);
623                         foreach (IEndpointBehavior b in endPoint.Behaviors)
624                                 b.AddBindingParameters (endPoint, commonParams);
625                         foreach (OperationDescription operation in endPoint.Contract.Operations) {
626                                 foreach (IOperationBehavior b in operation.Behaviors)
627                                         b.AddBindingParameters (operation, commonParams);
628                         }
629                 }
630
631                 static IChannelListener BuildListener (ServiceEndpoint se,
632                         BindingParameterCollection pl)
633                 {
634                         Binding b = se.Binding;
635                         if (b.CanBuildChannelListener<IReplySessionChannel> (pl))
636                                 return b.BuildChannelListener<IReplySessionChannel> (se.ListenUri, "", se.ListenUriMode, pl);
637                         if (b.CanBuildChannelListener<IReplyChannel> (pl))
638                                 return b.BuildChannelListener<IReplyChannel> (se.ListenUri, "", se.ListenUriMode, pl);
639                         if (b.CanBuildChannelListener<IInputSessionChannel> (pl))
640                                 return b.BuildChannelListener<IInputSessionChannel> (se.ListenUri, "", se.ListenUriMode, pl);
641                         if (b.CanBuildChannelListener<IInputChannel> (pl))
642                                 return b.BuildChannelListener<IInputChannel> (se.ListenUri, "", se.ListenUriMode, pl);
643
644                         if (b.CanBuildChannelListener<IDuplexChannel> (pl))
645                                 return b.BuildChannelListener<IDuplexChannel> (se.ListenUri, "", se.ListenUriMode, pl);
646                         if (b.CanBuildChannelListener<IDuplexSessionChannel> (pl))
647                                 return b.BuildChannelListener<IDuplexSessionChannel> (se.ListenUri, "", se.ListenUriMode, pl);
648                         throw new InvalidOperationException ("None of the listener channel types is supported");
649                 }
650         }
651 }