5 // Atsushi Enomoto <atsushi@ximian.com>
7 // Copyright (C) 2005-2006 Novell, Inc. http://www.novell.com
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:
17 // The above copyright notice and this permission notice shall be
18 // included in all copies or substantial portions of the Software.
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.
29 using System
.Collections
.Generic
;
30 using System
.Collections
.ObjectModel
;
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
));
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
{
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)
98 if (relativeUri
.IsAbsoluteUri
)
102 var s
= relativeUri
.ToString ();
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
));
111 return new Uri (String
.Concat (baseUri
.ToString (), r
));
114 public ChannelDispatcherCollection ChannelDispatchers
{
115 get { return channel_dispatchers; }
118 public ServiceAuthorizationBehavior Authorization
{
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; }
137 public IExtensionCollection
<ServiceHostBase
> Extensions
{
139 if (extensions
== null)
140 extensions
= new ExtensionCollection
<ServiceHostBase
> (this);
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
,
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
,
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");
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
);
215 foreach (ContractDescription cd
in ImplementedContracts
.Values
) {
216 type
= cd
.ContractType
.Assembly
.GetType (typeName
);
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.
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)
243 if (mex_contract
== null)
244 mex_contract
= ContractDescription
.GetContract (typeof (IMetadataExchange
));
248 Type type
= PopulateType (name
);
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
))
257 if (cd
.ContractType
== type
||
258 cd
.ContractType
.IsSubclassOf (type
) ||
259 type
.IsInterface
&& cd
.ContractType
.GetInterface (type
.FullName
) == type
)
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
))
288 ServiceEndpoint se
= new ServiceEndpoint (cd
, binding
, address
);
289 se
.ListenUri
= listenUri
.IsAbsoluteUri
? listenUri
: new Uri (address
.Uri
, listenUri
);
290 Description
.Endpoints
.Add (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) {
305 HostElement host
= service
.Host
;
306 foreach (BaseAddressElement baseAddress
in host
.BaseAddresses
) {
307 AddBaseAddress (new Uri (baseAddress
.BaseAddress
));
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
);
321 foreach (ServiceEndpointElement endpoint
in service
.Endpoints
) {
322 ServiceEndpoint se
= AddServiceEndpoint (
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)
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
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.");
427 protected void LoadConfigurationSection (ServiceElement element
)
429 ServicesSection services
= ConfigUtil
.ServicesSection
;
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
) {
463 TimeSpan ts
= timeout
- (DateTime
.Now
- start
);
464 if (ts
< TimeSpan
.Zero
)
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 (); }
;
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 ()
510 protected void ReleasePerformanceCounters ()
514 void IDisposable
.Dispose ()
520 class SyncMethodInvoker : IOperationInvoker
522 readonly MethodInfo _methodInfo;
523 public SyncMethodInvoker (MethodInfo methodInfo) {
524 _methodInfo = methodInfo;
527 #region IOperationInvoker Members
529 public bool IsSynchronous {
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 ();
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);
604 /// Builds ChannelDispatchers as appropriate to service the service endpoints.
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
)
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
;
630 ep
= cd
.InitializeServiceEndpoint (serviceType
, se
);
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
;
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");