2010-06-03 Jb Evain <jbevain@novell.com>
[mcs.git] / class / System.ServiceModel / System.ServiceModel / ServiceHostBase.cs
blobded567df07a47e07e39d0ebdf15641cd99350b48
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.
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 using System.Threading;
40 namespace System.ServiceModel
42 public abstract partial class ServiceHostBase
43 : CommunicationObject, IExtensibleObject<ServiceHostBase>, IDisposable
45 // It is used for mapping a ServiceHostBase to HttpChannelListener precisely.
46 internal static ServiceHostBase CurrentServiceHostHack;
48 ServiceCredentials credentials;
49 ServiceDescription description;
50 UriSchemeKeyedCollection base_addresses;
51 TimeSpan open_timeout, close_timeout, instance_idle_timeout;
52 ServiceThrottle throttle;
53 List<InstanceContext> contexts;
54 ReadOnlyCollection<InstanceContext> exposed_contexts;
55 ChannelDispatcherCollection channel_dispatchers;
56 IDictionary<string,ContractDescription> contracts;
57 int flow_limit = int.MaxValue;
58 IExtensionCollection<ServiceHostBase> extensions;
60 protected ServiceHostBase ()
62 open_timeout = DefaultOpenTimeout;
63 close_timeout = DefaultCloseTimeout;
65 credentials = new ServiceCredentials ();
66 throttle = new ServiceThrottle ();
67 contexts = new List<InstanceContext> ();
68 exposed_contexts = new ReadOnlyCollection<InstanceContext> (contexts);
69 channel_dispatchers = new ChannelDispatcherCollection (this);
72 public event EventHandler<UnknownMessageReceivedEventArgs>
73 UnknownMessageReceived;
75 internal void OnUnknownMessageReceived (Message message)
77 if (UnknownMessageReceived != null)
78 UnknownMessageReceived (this, new UnknownMessageReceivedEventArgs (message));
79 else
80 // FIXME: better be logged
81 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));
84 public ReadOnlyCollection<Uri> BaseAddresses {
85 get {
86 if (base_addresses == null)
87 base_addresses = new UriSchemeKeyedCollection ();
88 return new ReadOnlyCollection<Uri> (base_addresses.InternalItems);
92 internal Uri CreateUri (string scheme, Uri relativeUri)
94 Uri baseUri = base_addresses.Contains (scheme) ? base_addresses [scheme] : null;
96 if (relativeUri == null)
97 return baseUri;
98 if (relativeUri.IsAbsoluteUri)
99 return relativeUri;
100 if (baseUri == null)
101 return null;
102 var s = relativeUri.ToString ();
103 if (s.Length == 0)
104 return baseUri;
105 var l = baseUri.LocalPath;
106 var r = relativeUri.ToString ();
108 if (l.Length > 0 && l [l.Length - 1] != '/' && r [0] != '/')
109 return new Uri (String.Concat (baseUri.ToString (), "/", r));
110 else
111 return new Uri (String.Concat (baseUri.ToString (), r));
114 public ChannelDispatcherCollection ChannelDispatchers {
115 get { return channel_dispatchers; }
118 public ServiceAuthorizationBehavior Authorization {
119 get;
120 private set;
123 [MonoTODO]
124 public ServiceCredentials Credentials {
125 get { return credentials; }
128 public ServiceDescription Description {
129 get { return description; }
132 protected IDictionary<string,ContractDescription> ImplementedContracts {
133 get { return contracts; }
136 [MonoTODO]
137 public IExtensionCollection<ServiceHostBase> Extensions {
138 get {
139 if (extensions == null)
140 extensions = new ExtensionCollection<ServiceHostBase> (this);
141 return extensions;
145 protected internal override TimeSpan DefaultCloseTimeout {
146 get { return DefaultCommunicationTimeouts.Instance.CloseTimeout; }
149 protected internal override TimeSpan DefaultOpenTimeout {
150 get { return DefaultCommunicationTimeouts.Instance.OpenTimeout; }
153 public TimeSpan CloseTimeout {
154 get { return close_timeout; }
155 set { close_timeout = value; }
158 public TimeSpan OpenTimeout {
159 get { return open_timeout; }
160 set { open_timeout = value; }
163 public int ManualFlowControlLimit {
164 get { return flow_limit; }
165 set { flow_limit = value; }
168 protected void AddBaseAddress (Uri baseAddress)
170 if (base_addresses == null)
171 throw new InvalidOperationException ("Base addresses must be added before the service description is initialized");
172 base_addresses.Add (baseAddress);
175 public ServiceEndpoint AddServiceEndpoint (
176 string implementedContract, Binding binding, string address)
178 return AddServiceEndpoint (implementedContract,
179 binding,
180 new Uri (address, UriKind.RelativeOrAbsolute));
183 public ServiceEndpoint AddServiceEndpoint (
184 string implementedContract, Binding binding,
185 string address, Uri listenUri)
187 Uri uri = new Uri (address, UriKind.RelativeOrAbsolute);
188 return AddServiceEndpoint (
189 implementedContract, binding, uri, listenUri);
192 public ServiceEndpoint AddServiceEndpoint (
193 string implementedContract, Binding binding,
194 Uri address)
196 return AddServiceEndpoint (implementedContract, binding, address, address);
199 public ServiceEndpoint AddServiceEndpoint (
200 string implementedContract, Binding binding,
201 Uri address, Uri listenUri)
203 EndpointAddress ea = BuildEndpointAddress (address, binding);
204 ContractDescription cd = GetContract (implementedContract, binding.Namespace == "http://schemas.microsoft.com/ws/2005/02/mex/bindings");
205 if (cd == null)
206 throw new InvalidOperationException (String.Format ("Contract '{0}' was not found in the implemented contracts in this service host.", implementedContract));
207 return AddServiceEndpointCore (cd, binding, ea, listenUri);
210 Type PopulateType (string typeName)
212 Type type = Type.GetType (typeName);
213 if (type != null)
214 return type;
215 foreach (ContractDescription cd in ImplementedContracts.Values) {
216 type = cd.ContractType.Assembly.GetType (typeName);
217 if (type != null)
218 return type;
220 return null;
223 ContractDescription mex_contract, help_page_contract;
225 ContractDescription GetContract (string name, bool mexBinding)
227 // FIXME: not sure if they should really be special cases.
228 switch (name) {
229 case "IHttpGetHelpPageAndMetadataContract":
230 if (help_page_contract == null)
231 help_page_contract = ContractDescription.GetContract (typeof (IHttpGetHelpPageAndMetadataContract));
232 return help_page_contract;
233 case "IMetadataExchange":
234 // this is certainly looking special (or we may
235 // be missing something around ServiceMetadataExtension).
236 // It seems .NET WCF has some "infrastructure"
237 // endpoints. .NET ServiceHost fails to Open()
238 // if it was added only IMetadataExchange
239 // endpoint (and you'll see the word
240 // "infrastructure" in the exception message).
241 if (mexBinding && Description.Behaviors.Find<ServiceMetadataBehavior> () == null)
242 break;
243 if (mex_contract == null)
244 mex_contract = ContractDescription.GetContract (typeof (IMetadataExchange));
245 return mex_contract;
248 Type type = PopulateType (name);
249 if (type == null)
250 return null;
252 foreach (ContractDescription cd in ImplementedContracts.Values) {
253 // This check is a negative side effect of the above match-by-name design.
254 if (cd.ContractType == typeof (IMetadataExchange))
255 continue;
257 if (cd.ContractType == type ||
258 cd.ContractType.IsSubclassOf (type) ||
259 type.IsInterface && cd.ContractType.GetInterface (type.FullName) == type)
260 return cd;
262 return null;
265 internal EndpointAddress BuildEndpointAddress (Uri address, Binding binding)
267 if (!address.IsAbsoluteUri) {
268 // Find a Base address with matching scheme,
269 // and build new absolute address
270 if (!base_addresses.Contains (binding.Scheme))
271 throw new InvalidOperationException (String.Format ("Could not find base address that matches Scheme {0} for endpoint {1}", binding.Scheme, binding.Name));
273 Uri baseaddr = base_addresses [binding.Scheme];
275 if (!baseaddr.AbsoluteUri.EndsWith ("/") && address.OriginalString.Length > 0) // with empty URI it should not add '/' to possible file name of the absolute URI
276 baseaddr = new Uri (baseaddr.AbsoluteUri + "/");
277 address = new Uri (baseaddr, address);
279 return new EndpointAddress (address);
282 internal ServiceEndpoint AddServiceEndpointCore (
283 ContractDescription cd, Binding binding, EndpointAddress address, Uri listenUri)
285 foreach (ServiceEndpoint e in Description.Endpoints)
286 if (e.Contract == cd && e.Binding == binding && e.Address == address && e.ListenUri.Equals (listenUri))
287 return e;
288 ServiceEndpoint se = new ServiceEndpoint (cd, binding, address);
289 se.ListenUri = listenUri.IsAbsoluteUri ? listenUri : new Uri (address.Uri, listenUri);
290 Description.Endpoints.Add (se);
291 return se;
294 protected virtual void ApplyConfiguration ()
296 if (Description == null)
297 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");
299 ServiceElement service = GetServiceElement ();
301 //TODO: Should we call here LoadServiceElement ?
302 if (service != null) {
304 //base addresses
305 HostElement host = service.Host;
306 foreach (BaseAddressElement baseAddress in host.BaseAddresses) {
307 AddBaseAddress (new Uri (baseAddress.BaseAddress));
310 // behaviors
311 // TODO: use EvaluationContext of ServiceElement.
312 ServiceBehaviorElement behavior = ConfigUtil.BehaviorsSection.ServiceBehaviors [service.BehaviorConfiguration];
313 if (behavior != null) {
314 foreach (var bxe in behavior) {
315 IServiceBehavior b = (IServiceBehavior) bxe.CreateBehavior ();
316 Description.Behaviors.Add (b);
320 // services
321 foreach (ServiceEndpointElement endpoint in service.Endpoints) {
322 ServiceEndpoint se = AddServiceEndpoint (
323 endpoint.Contract,
324 ConfigUtil.CreateBinding (endpoint.Binding, endpoint.BindingConfiguration),
325 endpoint.Address.ToString ());
326 // endpoint behaviors
327 EndpointBehaviorElement epbehavior = ConfigUtil.BehaviorsSection.EndpointBehaviors [endpoint.BehaviorConfiguration];
328 if (epbehavior != null)
329 foreach (var bxe in epbehavior) {
330 IEndpointBehavior b = (IEndpointBehavior) bxe.CreateBehavior ();
331 se.Behaviors.Add (b);
335 // TODO: consider commonBehaviors here
337 // ensure ServiceAuthorizationBehavior
338 Authorization = Description.Behaviors.Find<ServiceAuthorizationBehavior> ();
339 if (Authorization == null) {
340 Authorization = new ServiceAuthorizationBehavior ();
341 Description.Behaviors.Add (Authorization);
344 // ensure ServiceDebugBehavior
345 ServiceDebugBehavior debugBehavior = Description.Behaviors.Find<ServiceDebugBehavior> ();
346 if (debugBehavior == null) {
347 debugBehavior = new ServiceDebugBehavior ();
348 Description.Behaviors.Add (debugBehavior);
352 private ServiceElement GetServiceElement() {
353 Type serviceType = Description.ServiceType;
354 if (serviceType == null)
355 return null;
357 return ConfigUtil.ServicesSection.Services [serviceType.FullName];
360 protected abstract ServiceDescription CreateDescription (
361 out IDictionary<string,ContractDescription> implementedContracts);
363 protected void InitializeDescription (UriSchemeKeyedCollection baseAddresses)
365 this.base_addresses = baseAddresses;
366 IDictionary<string,ContractDescription> retContracts;
367 description = CreateDescription (out retContracts);
368 contracts = retContracts;
370 ApplyConfiguration ();
373 protected virtual void InitializeRuntime ()
375 //First validate the description, which should call all behaviors
376 //'Validate' method.
377 ValidateDescription ();
379 //Build all ChannelDispatchers, one dispatcher per user configured EndPoint.
380 //We must keep thet ServiceEndpoints as a seperate collection, since the user
381 //can change the collection in the description during the behaviors events.
382 ServiceEndpoint[] endPoints = new ServiceEndpoint[Description.Endpoints.Count];
383 Description.Endpoints.CopyTo (endPoints, 0);
384 var builder = new DispatcherBuilder (this);
385 foreach (ServiceEndpoint se in endPoints) {
387 var commonParams = new BindingParameterCollection ();
388 foreach (IServiceBehavior b in Description.Behaviors)
389 b.AddBindingParameters (Description, this, Description.Endpoints, commonParams);
391 var channel = builder.BuildChannelDispatcher (Description.ServiceType, se, commonParams);
392 if (!ChannelDispatchers.Contains (channel))
393 ChannelDispatchers.Add (channel);
396 //After the ChannelDispatchers are created, and attached to the service host
397 //Apply dispatching behaviors.
399 // This behavior application order is tricky: first only
400 // ServiceDebugBehavior and ServiceMetadataBehavior are
401 // applied, and then other service behaviors are applied.
402 // It is because those two behaviors adds ChannelDispatchers
403 // and any other service behaviors must be applied to
404 // those newly populated dispatchers.
405 foreach (IServiceBehavior b in Description.Behaviors)
406 if (b is ServiceMetadataBehavior || b is ServiceDebugBehavior)
407 b.ApplyDispatchBehavior (Description, this);
408 foreach (IServiceBehavior b in Description.Behaviors)
409 if (!(b is ServiceMetadataBehavior || b is ServiceDebugBehavior))
410 b.ApplyDispatchBehavior (Description, this);
412 builder.ApplyDispatchBehaviors ();
415 private void ValidateDescription ()
417 foreach (IServiceBehavior b in Description.Behaviors)
418 b.Validate (Description, this);
419 foreach (ServiceEndpoint endPoint in Description.Endpoints)
420 endPoint.Validate ();
422 if (Description.Endpoints.FirstOrDefault (e => e.Contract != mex_contract) == null)
423 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.");
426 [MonoTODO]
427 protected void LoadConfigurationSection (ServiceElement element)
429 ServicesSection services = ConfigUtil.ServicesSection;
432 [MonoTODO]
433 protected override sealed void OnAbort ()
437 Action<TimeSpan> close_delegate;
438 Action<TimeSpan> open_delegate;
440 protected override sealed IAsyncResult OnBeginClose (
441 TimeSpan timeout, AsyncCallback callback, object state)
443 if (close_delegate != null)
444 close_delegate = new Action<TimeSpan> (OnClose);
445 return close_delegate.BeginInvoke (timeout, callback, state);
448 protected override sealed IAsyncResult OnBeginOpen (
449 TimeSpan timeout, AsyncCallback callback, object state)
451 if (open_delegate == null)
452 open_delegate = new Action<TimeSpan> (OnOpen);
453 return open_delegate.BeginInvoke (timeout, callback, state);
456 protected override void OnClose (TimeSpan timeout)
458 DateTime start = DateTime.Now;
459 ReleasePerformanceCounters ();
460 List<ChannelDispatcherBase> l = new List<ChannelDispatcherBase> (ChannelDispatchers);
461 foreach (ChannelDispatcherBase e in l) {
462 try {
463 TimeSpan ts = timeout - (DateTime.Now - start);
464 if (ts < TimeSpan.Zero)
465 e.Abort ();
466 else
467 e.Close (ts);
468 } catch (Exception ex) {
469 Console.WriteLine ("ServiceHostBase failed to close the channel dispatcher:");
470 Console.WriteLine (ex);
475 protected override sealed void OnOpen (TimeSpan timeout)
477 DateTime start = DateTime.Now;
478 InitializeRuntime ();
479 var waits = new List<ManualResetEvent> ();
480 foreach (var cd in ChannelDispatchers) {
481 var wait = new ManualResetEvent (false);
482 cd.Opened += delegate { wait.Set (); };
483 waits.Add (wait);
484 cd.Open (timeout - (DateTime.Now - start));
487 WaitHandle.WaitAll (waits.ToArray ());
490 protected override void OnEndClose (IAsyncResult result)
492 if (close_delegate == null)
493 throw new InvalidOperationException ("Async close operation has not started");
494 close_delegate.EndInvoke (result);
497 protected override sealed void OnEndOpen (IAsyncResult result)
499 if (open_delegate == null)
500 throw new InvalidOperationException ("Aync open operation has not started");
501 open_delegate.EndInvoke (result);
504 protected override void OnOpened ()
506 base.OnOpened ();
509 [MonoTODO]
510 protected void ReleasePerformanceCounters ()
514 void IDisposable.Dispose ()
516 Close ();
520 class SyncMethodInvoker : IOperationInvoker
522 readonly MethodInfo _methodInfo;
523 public SyncMethodInvoker (MethodInfo methodInfo) {
524 _methodInfo = methodInfo;
527 #region IOperationInvoker Members
529 public bool IsSynchronous {
530 get { return true; }
533 public object [] AllocateParameters () {
534 return new object [_methodInfo.GetParameters ().Length];
537 public object Invoke (object instance, object [] parameters)
539 return _methodInfo.Invoke (instance, parameters);
542 public IAsyncResult InvokeBegin (object instance, object [] inputs, AsyncCallback callback, object state) {
543 throw new NotSupportedException ();
546 public object InvokeEnd (object instance, out object [] outputs, IAsyncResult result) {
547 throw new NotSupportedException ();
550 #endregion
553 class AsyncMethodInvoker : IOperationInvoker
555 readonly MethodInfo _beginMethodInfo, _endMethodInfo;
556 public AsyncMethodInvoker (MethodInfo beginMethodInfo, MethodInfo endMethodInfo) {
557 _beginMethodInfo = beginMethodInfo;
558 _endMethodInfo = endMethodInfo;
561 #region IOperationInvoker Members
563 public bool IsSynchronous {
564 get { return false; }
567 public object [] AllocateParameters () {
568 return new object [_beginMethodInfo.GetParameters ().Length - 2 + _endMethodInfo.GetParameters().Length-1];
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);
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);
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;
598 #endregion
603 /// <summary>
604 /// Builds ChannelDispatchers as appropriate to service the service endpoints.
605 /// </summary>
606 /// <remarks>Will re-use ChannelDispatchers when two endpoint uris are the same</remarks>
607 partial class DispatcherBuilder
609 ServiceHostBase host;
611 public DispatcherBuilder (ServiceHostBase host)
613 this.host = host;
616 List<ChannelDispatcher> built_dispatchers = new List<ChannelDispatcher> ();
617 Dictionary<ServiceEndpoint, EndpointDispatcher> ep_to_dispatcher_ep = new Dictionary<ServiceEndpoint, EndpointDispatcher> ();
619 internal static Action<ChannelDispatcher> ChannelDispatcherSetter;
621 internal ChannelDispatcher BuildChannelDispatcher (Type serviceType, ServiceEndpoint se, BindingParameterCollection commonParams)
623 //Let all behaviors add their binding parameters
624 AddBindingParameters (commonParams, se);
626 // See if there's an existing channel that matches this endpoint
627 ChannelDispatcher cd = FindExistingDispatcher (se);
628 EndpointDispatcher ep;
629 if (cd != null) {
630 ep = cd.InitializeServiceEndpoint (serviceType, se);
631 } else {
632 // Use the binding parameters to build the channel listener and Dispatcher.
633 lock (HttpTransportBindingElement.ListenerBuildLock) {
634 ServiceHostBase.CurrentServiceHostHack = host;
635 IChannelListener lf = BuildListener (se, commonParams);
636 cd = new ChannelDispatcher (lf, se.Binding.Name);
637 if (ChannelDispatcherSetter != null) {
638 ChannelDispatcherSetter (cd);
639 ChannelDispatcherSetter = null;
641 ServiceHostBase.CurrentServiceHostHack = null;
643 ep = cd.InitializeServiceEndpoint (serviceType, se);
644 built_dispatchers.Add (cd);
646 ep_to_dispatcher_ep[se] = ep;
647 return cd;
650 ChannelDispatcher FindExistingDispatcher (ServiceEndpoint se)
652 return built_dispatchers.FirstOrDefault ((ChannelDispatcher cd) => (cd.Listener.Uri.Equals (se.ListenUri)) && cd.MessageVersion.Equals (se.Binding.MessageVersion));
655 internal void ApplyDispatchBehaviors ()
657 foreach (KeyValuePair<ServiceEndpoint, EndpointDispatcher> val in ep_to_dispatcher_ep)
658 ApplyDispatchBehavior (val.Value, val.Key);
661 private void ApplyDispatchBehavior (EndpointDispatcher ed, ServiceEndpoint endPoint)
663 foreach (IContractBehavior b in endPoint.Contract.Behaviors)
664 b.ApplyDispatchBehavior (endPoint.Contract, endPoint, ed.DispatchRuntime);
665 foreach (IEndpointBehavior b in endPoint.Behaviors)
666 b.ApplyDispatchBehavior (endPoint, ed);
667 foreach (OperationDescription operation in endPoint.Contract.Operations) {
668 foreach (IOperationBehavior b in operation.Behaviors)
669 b.ApplyDispatchBehavior (operation, ed.DispatchRuntime.Operations [operation.Name]);
674 private void AddBindingParameters (BindingParameterCollection commonParams, ServiceEndpoint endPoint) {
676 commonParams.Add (ChannelProtectionRequirements.CreateFromContract (endPoint.Contract));
678 foreach (IContractBehavior b in endPoint.Contract.Behaviors)
679 b.AddBindingParameters (endPoint.Contract, endPoint, commonParams);
680 foreach (IEndpointBehavior b in endPoint.Behaviors)
681 b.AddBindingParameters (endPoint, commonParams);
682 foreach (OperationDescription operation in endPoint.Contract.Operations) {
683 foreach (IOperationBehavior b in operation.Behaviors)
684 b.AddBindingParameters (operation, commonParams);
688 static IChannelListener BuildListener (ServiceEndpoint se,
689 BindingParameterCollection pl)
691 Binding b = se.Binding;
692 if (b.CanBuildChannelListener<IReplySessionChannel> (pl))
693 return b.BuildChannelListener<IReplySessionChannel> (se.ListenUri, "", se.ListenUriMode, pl);
694 if (b.CanBuildChannelListener<IReplyChannel> (pl))
695 return b.BuildChannelListener<IReplyChannel> (se.ListenUri, "", se.ListenUriMode, pl);
696 if (b.CanBuildChannelListener<IInputSessionChannel> (pl))
697 return b.BuildChannelListener<IInputSessionChannel> (se.ListenUri, "", se.ListenUriMode, pl);
698 if (b.CanBuildChannelListener<IInputChannel> (pl))
699 return b.BuildChannelListener<IInputChannel> (se.ListenUri, "", se.ListenUriMode, pl);
701 if (b.CanBuildChannelListener<IDuplexChannel> (pl))
702 return b.BuildChannelListener<IDuplexChannel> (se.ListenUri, "", se.ListenUriMode, pl);
703 if (b.CanBuildChannelListener<IDuplexSessionChannel> (pl))
704 return b.BuildChannelListener<IDuplexSessionChannel> (se.ListenUri, "", se.ListenUriMode, pl);
705 throw new InvalidOperationException ("None of the listener channel types is supported");