ServiceHostBase.cs 22 KB

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