OneWayChannelFactory.cs 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816
  1. //------------------------------------------------------------
  2. // Copyright (c) Microsoft Corporation. All rights reserved.
  3. //------------------------------------------------------------
  4. namespace System.ServiceModel.Channels
  5. {
  6. using System.Diagnostics;
  7. using System.IO;
  8. using System.Runtime;
  9. using System.ServiceModel.Diagnostics;
  10. using System.Xml;
  11. using System.ServiceModel.Diagnostics.Application;
  12. class PacketRoutableHeader : DictionaryHeader
  13. {
  14. PacketRoutableHeader()
  15. : base()
  16. {
  17. }
  18. public static void AddHeadersTo(Message message, MessageHeader header)
  19. {
  20. int index = message.Headers.FindHeader(DotNetOneWayStrings.HeaderName, DotNetOneWayStrings.Namespace);
  21. if (index == -1)
  22. {
  23. if (header == null)
  24. {
  25. header = PacketRoutableHeader.Create();
  26. }
  27. message.Headers.Add(header);
  28. }
  29. }
  30. public static void ValidateMessage(Message message)
  31. {
  32. if (!TryValidateMessage(message))
  33. {
  34. throw TraceUtility.ThrowHelperError(
  35. new ProtocolException(SR.GetString(SR.OneWayHeaderNotFound)), message);
  36. }
  37. }
  38. public static bool TryValidateMessage(Message message)
  39. {
  40. int index = message.Headers.FindHeader(
  41. DotNetOneWayStrings.HeaderName, DotNetOneWayStrings.Namespace);
  42. return (index != -1);
  43. }
  44. public static PacketRoutableHeader Create()
  45. {
  46. return new PacketRoutableHeader();
  47. }
  48. public override XmlDictionaryString DictionaryName
  49. {
  50. get { return XD.DotNetOneWayDictionary.HeaderName; }
  51. }
  52. public override XmlDictionaryString DictionaryNamespace
  53. {
  54. get { return XD.DotNetOneWayDictionary.Namespace; }
  55. }
  56. protected override void OnWriteHeaderContents(XmlDictionaryWriter writer, MessageVersion messageVersion)
  57. {
  58. // no contents necessary
  59. }
  60. }
  61. /// <summary>
  62. /// OneWayChannelFactory built on top of IRequestChannel
  63. /// </summary>
  64. class RequestOneWayChannelFactory : LayeredChannelFactory<IOutputChannel>
  65. {
  66. PacketRoutableHeader packetRoutableHeader;
  67. public RequestOneWayChannelFactory(OneWayBindingElement bindingElement, BindingContext context)
  68. : base(context.Binding, context.BuildInnerChannelFactory<IRequestChannel>())
  69. {
  70. if (bindingElement.PacketRoutable)
  71. {
  72. this.packetRoutableHeader = PacketRoutableHeader.Create();
  73. }
  74. }
  75. protected override IOutputChannel OnCreateChannel(EndpointAddress to, Uri via)
  76. {
  77. IRequestChannel innerChannel =
  78. ((IChannelFactory<IRequestChannel>)this.InnerChannelFactory).CreateChannel(to, via);
  79. return new RequestOutputChannel(this, innerChannel, this.packetRoutableHeader);
  80. }
  81. class RequestOutputChannel : OutputChannel
  82. {
  83. IRequestChannel innerChannel;
  84. MessageHeader packetRoutableHeader;
  85. public RequestOutputChannel(ChannelManagerBase factory,
  86. IRequestChannel innerChannel, MessageHeader packetRoutableHeader)
  87. : base(factory)
  88. {
  89. this.innerChannel = innerChannel;
  90. this.packetRoutableHeader = packetRoutableHeader;
  91. }
  92. #region Inner Channel delegation
  93. public override EndpointAddress RemoteAddress
  94. {
  95. get { return this.innerChannel.RemoteAddress; }
  96. }
  97. public override Uri Via
  98. {
  99. get { return this.innerChannel.Via; }
  100. }
  101. protected override void OnAbort()
  102. {
  103. this.innerChannel.Abort();
  104. }
  105. protected override void OnOpen(TimeSpan timeout)
  106. {
  107. this.innerChannel.Open(timeout);
  108. }
  109. protected override IAsyncResult OnBeginOpen(TimeSpan timeout, AsyncCallback callback, object state)
  110. {
  111. return this.innerChannel.BeginOpen(timeout, callback, state);
  112. }
  113. protected override void OnEndOpen(IAsyncResult result)
  114. {
  115. this.innerChannel.EndOpen(result);
  116. }
  117. protected override void OnClose(TimeSpan timeout)
  118. {
  119. this.innerChannel.Close(timeout);
  120. }
  121. protected override IAsyncResult OnBeginClose(TimeSpan timeout, AsyncCallback callback, object state)
  122. {
  123. return this.innerChannel.BeginClose(timeout, callback, state);
  124. }
  125. protected override void OnEndClose(IAsyncResult result)
  126. {
  127. this.innerChannel.EndClose(result);
  128. }
  129. public override T GetProperty<T>()
  130. {
  131. T result = base.GetProperty<T>();
  132. if (result == null)
  133. {
  134. result = this.innerChannel.GetProperty<T>();
  135. }
  136. return result;
  137. }
  138. #endregion
  139. // add our oneWay header to every message (if it's not already there)
  140. protected override void AddHeadersTo(Message message)
  141. {
  142. base.AddHeadersTo(message);
  143. if (this.packetRoutableHeader != null)
  144. {
  145. PacketRoutableHeader.AddHeadersTo(message, this.packetRoutableHeader);
  146. }
  147. }
  148. protected override void OnSend(Message message, TimeSpan timeout)
  149. {
  150. Message response = this.innerChannel.Request(message, timeout);
  151. using (response)
  152. {
  153. ValidateResponse(response);
  154. }
  155. }
  156. protected override IAsyncResult OnBeginSend(Message message, TimeSpan timeout, AsyncCallback callback, object state)
  157. {
  158. return this.innerChannel.BeginRequest(message, timeout, callback, state);
  159. }
  160. protected override void OnEndSend(IAsyncResult result)
  161. {
  162. Message response = this.innerChannel.EndRequest(result);
  163. using (response)
  164. {
  165. ValidateResponse(response);
  166. }
  167. }
  168. void ValidateResponse(Message response)
  169. {
  170. if (response != null)
  171. {
  172. if (response.Version == MessageVersion.None && response is NullMessage)
  173. {
  174. response.Close();
  175. return;
  176. }
  177. Exception innerException = null;
  178. if (response.IsFault)
  179. {
  180. try
  181. {
  182. MessageFault messageFault = MessageFault.CreateFault(response, TransportDefaults.MaxFaultSize);
  183. innerException = new FaultException(messageFault);
  184. }
  185. catch (Exception e)
  186. {
  187. if (Fx.IsFatal(e))
  188. {
  189. throw;
  190. }
  191. if (e is CommunicationException ||
  192. e is TimeoutException ||
  193. e is XmlException ||
  194. e is IOException)
  195. {
  196. innerException = e; // expected exception generating fault
  197. }
  198. else
  199. {
  200. throw;
  201. }
  202. }
  203. }
  204. throw TraceUtility.ThrowHelperError(
  205. new ProtocolException(SR.GetString(SR.OneWayUnexpectedResponse), innerException),
  206. response);
  207. }
  208. }
  209. }
  210. }
  211. // <summary>
  212. // OneWayChannelFactory built on top of IDuplexChannel
  213. // </summary>
  214. class DuplexOneWayChannelFactory : LayeredChannelFactory<IOutputChannel>
  215. {
  216. IChannelFactory<IDuplexChannel> innnerFactory;
  217. bool packetRoutable;
  218. public DuplexOneWayChannelFactory(OneWayBindingElement bindingElement, BindingContext context)
  219. : base(context.Binding, context.BuildInnerChannelFactory<IDuplexChannel>())
  220. {
  221. this.innnerFactory = (IChannelFactory<IDuplexChannel>)this.InnerChannelFactory;
  222. this.packetRoutable = bindingElement.PacketRoutable;
  223. }
  224. protected override IOutputChannel OnCreateChannel(EndpointAddress address, Uri via)
  225. {
  226. IDuplexChannel channel = this.innnerFactory.CreateChannel(address, via);
  227. return new DuplexOutputChannel(this, channel);
  228. }
  229. class DuplexOutputChannel : OutputChannel
  230. {
  231. IDuplexChannel innerChannel;
  232. bool packetRoutable;
  233. public DuplexOutputChannel(DuplexOneWayChannelFactory factory, IDuplexChannel innerChannel)
  234. : base(factory)
  235. {
  236. this.packetRoutable = factory.packetRoutable;
  237. this.innerChannel = innerChannel;
  238. }
  239. public override EndpointAddress RemoteAddress
  240. {
  241. get { return this.innerChannel.RemoteAddress; }
  242. }
  243. public override Uri Via
  244. {
  245. get { return this.innerChannel.Via; }
  246. }
  247. protected override void OnAbort()
  248. {
  249. this.innerChannel.Abort();
  250. }
  251. protected override IAsyncResult OnBeginClose(TimeSpan timeout, AsyncCallback callback, object state)
  252. {
  253. return this.innerChannel.BeginClose(timeout, callback, state);
  254. }
  255. protected override IAsyncResult OnBeginOpen(TimeSpan timeout, AsyncCallback callback, object state)
  256. {
  257. return this.innerChannel.BeginOpen(timeout, callback, state);
  258. }
  259. protected override IAsyncResult OnBeginSend(Message message, TimeSpan timeout, AsyncCallback callback, object state)
  260. {
  261. StampMessage(message);
  262. return this.innerChannel.BeginSend(message, timeout, callback, state);
  263. }
  264. protected override void OnClose(TimeSpan timeout)
  265. {
  266. this.innerChannel.Close(timeout);
  267. }
  268. protected override void OnEndClose(IAsyncResult result)
  269. {
  270. this.innerChannel.EndClose(result);
  271. }
  272. protected override void OnEndOpen(IAsyncResult result)
  273. {
  274. this.innerChannel.EndOpen(result);
  275. }
  276. protected override void OnEndSend(IAsyncResult result)
  277. {
  278. this.innerChannel.EndSend(result);
  279. }
  280. protected override void OnOpen(TimeSpan timeout)
  281. {
  282. this.innerChannel.Open(timeout);
  283. }
  284. protected override void OnSend(Message message, TimeSpan timeout)
  285. {
  286. StampMessage(message);
  287. this.innerChannel.Send(message, timeout);
  288. }
  289. void StampMessage(Message message)
  290. {
  291. if (this.packetRoutable)
  292. {
  293. PacketRoutableHeader.AddHeadersTo(message, null);
  294. }
  295. }
  296. }
  297. }
  298. /// <summary>
  299. /// OneWayChannelFactory built on top of IDuplexSessionChannel
  300. /// </summary>
  301. class DuplexSessionOneWayChannelFactory : LayeredChannelFactory<IOutputChannel>
  302. {
  303. ChannelPool<IDuplexSessionChannel> channelPool;
  304. ChannelPoolSettings channelPoolSettings;
  305. bool packetRoutable;
  306. public DuplexSessionOneWayChannelFactory(OneWayBindingElement bindingElement, BindingContext context)
  307. : base(context.Binding, context.BuildInnerChannelFactory<IDuplexSessionChannel>())
  308. {
  309. this.packetRoutable = bindingElement.PacketRoutable;
  310. ISecurityCapabilities innerSecurityCapabilities = this.InnerChannelFactory.GetProperty<ISecurityCapabilities>();
  311. // can't pool across outer channels if the inner channels support client auth
  312. if (innerSecurityCapabilities != null && innerSecurityCapabilities.SupportsClientAuthentication)
  313. {
  314. this.channelPoolSettings = bindingElement.ChannelPoolSettings.Clone();
  315. }
  316. else
  317. {
  318. this.channelPool = new ChannelPool<IDuplexSessionChannel>(bindingElement.ChannelPoolSettings);
  319. }
  320. }
  321. internal ChannelPool<IDuplexSessionChannel> GetChannelPool(out bool cleanupChannelPool)
  322. {
  323. if (this.channelPool != null)
  324. {
  325. cleanupChannelPool = false;
  326. return this.channelPool;
  327. }
  328. else
  329. {
  330. cleanupChannelPool = true;
  331. Fx.Assert(this.channelPoolSettings != null, "Need either settings or a pool");
  332. return new ChannelPool<IDuplexSessionChannel>(this.channelPoolSettings);
  333. }
  334. }
  335. protected override void OnAbort()
  336. {
  337. if (this.channelPool != null)
  338. {
  339. this.channelPool.Close(TimeSpan.Zero);
  340. }
  341. base.OnAbort();
  342. }
  343. protected override void OnClose(TimeSpan timeout)
  344. {
  345. TimeoutHelper timeoutHelper = new TimeoutHelper(timeout);
  346. if (this.channelPool != null)
  347. {
  348. this.channelPool.Close(timeoutHelper.RemainingTime());
  349. }
  350. base.OnClose(timeoutHelper.RemainingTime());
  351. }
  352. protected override IAsyncResult OnBeginClose(TimeSpan timeout, AsyncCallback callback, object state)
  353. {
  354. TimeoutHelper timeoutHelper = new TimeoutHelper(timeout);
  355. if (this.channelPool != null)
  356. {
  357. this.channelPool.Close(timeoutHelper.RemainingTime());
  358. }
  359. return base.OnBeginClose(timeoutHelper.RemainingTime(), callback, state);
  360. }
  361. protected override IOutputChannel OnCreateChannel(EndpointAddress address, Uri via)
  362. {
  363. return new DuplexSessionOutputChannel(this, address, via);
  364. }
  365. class DuplexSessionOutputChannel : OutputChannel
  366. {
  367. ChannelPool<IDuplexSessionChannel> channelPool;
  368. EndpointAddress remoteAddress;
  369. IChannelFactory<IDuplexSessionChannel> innerFactory;
  370. AsyncCallback onReceive;
  371. bool packetRoutable;
  372. bool cleanupChannelPool;
  373. Uri via;
  374. public DuplexSessionOutputChannel(DuplexSessionOneWayChannelFactory factory,
  375. EndpointAddress remoteAddress, Uri via)
  376. : base(factory)
  377. {
  378. this.channelPool = factory.GetChannelPool(out cleanupChannelPool);
  379. this.packetRoutable = factory.packetRoutable;
  380. this.innerFactory = (IChannelFactory<IDuplexSessionChannel>)factory.InnerChannelFactory;
  381. this.remoteAddress = remoteAddress;
  382. this.via = via;
  383. }
  384. public override EndpointAddress RemoteAddress
  385. {
  386. get { return this.remoteAddress; }
  387. }
  388. public override Uri Via
  389. {
  390. get { return this.via; }
  391. }
  392. #region Channel Lifetime
  393. protected override void OnOpen(TimeSpan timeout)
  394. {
  395. }
  396. protected override IAsyncResult OnBeginOpen(TimeSpan timeout, AsyncCallback callback, object state)
  397. {
  398. return new CompletedAsyncResult(callback, state);
  399. }
  400. protected override void OnEndOpen(IAsyncResult result)
  401. {
  402. CompletedAsyncResult.End(result);
  403. }
  404. protected override void OnAbort()
  405. {
  406. if (cleanupChannelPool)
  407. {
  408. this.channelPool.Close(TimeSpan.Zero);
  409. }
  410. }
  411. protected override void OnClose(TimeSpan timeout)
  412. {
  413. if (cleanupChannelPool)
  414. {
  415. this.channelPool.Close(timeout);
  416. }
  417. }
  418. protected override IAsyncResult OnBeginClose(TimeSpan timeout, AsyncCallback callback, object state)
  419. {
  420. if (cleanupChannelPool)
  421. {
  422. this.channelPool.Close(timeout);
  423. }
  424. return new CompletedAsyncResult(callback, state);
  425. }
  426. protected override void OnEndClose(IAsyncResult result)
  427. {
  428. CompletedAsyncResult.End(result);
  429. }
  430. #endregion
  431. protected override IAsyncResult OnBeginSend(Message message, TimeSpan timeout, AsyncCallback callback, object state)
  432. {
  433. return new SendAsyncResult(this, message, timeout, callback, state);
  434. }
  435. protected override void OnEndSend(IAsyncResult result)
  436. {
  437. SendAsyncResult.End(result);
  438. }
  439. protected override void OnSend(Message message, TimeSpan timeout)
  440. {
  441. TimeoutHelper timeoutHelper = new TimeoutHelper(timeout);
  442. ChannelPoolKey key = null;
  443. bool isConnectionFromPool = true;
  444. IDuplexSessionChannel innerChannel =
  445. GetChannelFromPool(ref timeoutHelper, out key, out isConnectionFromPool);
  446. bool success = false;
  447. try
  448. {
  449. if (!isConnectionFromPool)
  450. {
  451. StampInitialMessage(message);
  452. innerChannel.Open(timeoutHelper.RemainingTime());
  453. StartBackgroundReceive(innerChannel);
  454. }
  455. innerChannel.Send(message, timeoutHelper.RemainingTime());
  456. success = true;
  457. }
  458. finally
  459. {
  460. if (!success)
  461. {
  462. CleanupChannel(innerChannel, false, key, isConnectionFromPool, ref timeoutHelper);
  463. }
  464. }
  465. CleanupChannel(innerChannel, true, key, isConnectionFromPool, ref timeoutHelper);
  466. }
  467. // kick off an async receive so that we notice when the server is trying to shutdown
  468. void StartBackgroundReceive(IDuplexSessionChannel channel)
  469. {
  470. if (this.onReceive == null)
  471. {
  472. this.onReceive = Fx.ThunkCallback(new AsyncCallback(OnReceive));
  473. }
  474. channel.BeginReceive(TimeSpan.MaxValue, this.onReceive, channel);
  475. }
  476. void OnReceive(IAsyncResult result)
  477. {
  478. IDuplexSessionChannel channel = (IDuplexSessionChannel)result.AsyncState;
  479. bool success = false;
  480. try
  481. {
  482. Message message = channel.EndReceive(result);
  483. if (message == null)
  484. {
  485. channel.Close(this.channelPool.IdleTimeout);
  486. success = true;
  487. }
  488. else
  489. {
  490. message.Close();
  491. }
  492. }
  493. catch (CommunicationException e)
  494. {
  495. DiagnosticUtility.TraceHandledException(e, TraceEventType.Information);
  496. }
  497. catch (TimeoutException e)
  498. {
  499. if (TD.CloseTimeoutIsEnabled())
  500. {
  501. TD.CloseTimeout(e.Message);
  502. }
  503. DiagnosticUtility.TraceHandledException(e, TraceEventType.Information);
  504. }
  505. finally
  506. {
  507. if (!success)
  508. {
  509. channel.Abort();
  510. }
  511. }
  512. }
  513. void StampInitialMessage(Message message)
  514. {
  515. if (this.packetRoutable)
  516. {
  517. PacketRoutableHeader.AddHeadersTo(message, null);
  518. }
  519. }
  520. void CleanupChannel(IDuplexSessionChannel channel, bool connectionStillGood, ChannelPoolKey key, bool isConnectionFromPool, ref TimeoutHelper timeoutHelper)
  521. {
  522. if (isConnectionFromPool)
  523. {
  524. this.channelPool.ReturnConnection(key, channel, connectionStillGood, timeoutHelper.RemainingTime());
  525. }
  526. else
  527. {
  528. if (connectionStillGood)
  529. {
  530. this.channelPool.AddConnection(key, channel, timeoutHelper.RemainingTime());
  531. }
  532. else
  533. {
  534. channel.Abort();
  535. }
  536. }
  537. }
  538. IDuplexSessionChannel GetChannelFromPool(ref TimeoutHelper timeoutHelper, out ChannelPoolKey key,
  539. out bool isConnectionFromPool)
  540. {
  541. isConnectionFromPool = true;
  542. while (true)
  543. {
  544. IDuplexSessionChannel pooledChannel
  545. = this.channelPool.TakeConnection(this.RemoteAddress, this.Via, timeoutHelper.RemainingTime(), out key);
  546. if (pooledChannel == null)
  547. {
  548. isConnectionFromPool = false;
  549. return this.innerFactory.CreateChannel(RemoteAddress, Via);
  550. }
  551. // only return good connections
  552. if (pooledChannel.State == CommunicationState.Opened)
  553. {
  554. return pooledChannel;
  555. }
  556. // Abort stale connections from the pool
  557. this.channelPool.ReturnConnection(key, pooledChannel, false, timeoutHelper.RemainingTime());
  558. }
  559. }
  560. class SendAsyncResult : AsyncResult
  561. {
  562. DuplexSessionOutputChannel parent;
  563. IDuplexSessionChannel innerChannel;
  564. Message message;
  565. TimeoutHelper timeoutHelper;
  566. static AsyncCallback onOpen;
  567. static AsyncCallback onInnerSend = Fx.ThunkCallback(new AsyncCallback(OnInnerSend));
  568. ChannelPoolKey key;
  569. bool isConnectionFromPool;
  570. public SendAsyncResult(DuplexSessionOutputChannel parent, Message message, TimeSpan timeout,
  571. AsyncCallback callback, object state)
  572. : base(callback, state)
  573. {
  574. this.parent = parent;
  575. this.message = message;
  576. this.timeoutHelper = new TimeoutHelper(timeout);
  577. this.innerChannel =
  578. parent.GetChannelFromPool(ref this.timeoutHelper, out this.key, out this.isConnectionFromPool);
  579. bool success = false;
  580. bool completeSelf = true;
  581. try
  582. {
  583. if (!this.isConnectionFromPool)
  584. {
  585. completeSelf = OpenNewChannel();
  586. }
  587. if (completeSelf)
  588. {
  589. completeSelf = SendMessage();
  590. }
  591. success = true;
  592. }
  593. finally
  594. {
  595. if (!success)
  596. {
  597. Cleanup(false);
  598. }
  599. }
  600. if (completeSelf)
  601. {
  602. Cleanup(true);
  603. base.Complete(true);
  604. }
  605. }
  606. public static void End(IAsyncResult result)
  607. {
  608. AsyncResult.End<SendAsyncResult>(result);
  609. }
  610. void Cleanup(bool connectionStillGood)
  611. {
  612. parent.CleanupChannel(this.innerChannel, connectionStillGood, this.key,
  613. this.isConnectionFromPool, ref this.timeoutHelper);
  614. }
  615. bool OpenNewChannel()
  616. {
  617. if (onOpen == null)
  618. {
  619. onOpen = Fx.ThunkCallback(new AsyncCallback(OnOpen));
  620. }
  621. this.parent.StampInitialMessage(this.message);
  622. IAsyncResult result = this.innerChannel.BeginOpen(timeoutHelper.RemainingTime(), onOpen, this);
  623. if (!result.CompletedSynchronously)
  624. {
  625. return false;
  626. }
  627. this.CompleteOpen(result);
  628. return true;
  629. }
  630. void CompleteOpen(IAsyncResult result)
  631. {
  632. this.innerChannel.EndOpen(result);
  633. this.parent.StartBackgroundReceive(this.innerChannel);
  634. }
  635. bool SendMessage()
  636. {
  637. IAsyncResult result = innerChannel.BeginSend(this.message, onInnerSend, this);
  638. if (!result.CompletedSynchronously)
  639. {
  640. return false;
  641. }
  642. innerChannel.EndSend(result);
  643. return true;
  644. }
  645. static void OnOpen(IAsyncResult result)
  646. {
  647. if (result.CompletedSynchronously)
  648. {
  649. return;
  650. }
  651. SendAsyncResult thisPtr = (SendAsyncResult)result.AsyncState;
  652. Exception completionException = null;
  653. bool completeSelf = false;
  654. try
  655. {
  656. thisPtr.CompleteOpen(result);
  657. completeSelf = thisPtr.SendMessage();
  658. }
  659. #pragma warning suppress 56500 // [....], transferring exception to another thread
  660. catch (Exception e)
  661. {
  662. if (Fx.IsFatal(e))
  663. {
  664. throw;
  665. }
  666. completeSelf = true;
  667. completionException = e;
  668. }
  669. if (completeSelf)
  670. {
  671. thisPtr.Cleanup(completionException == null);
  672. thisPtr.Complete(false, completionException);
  673. }
  674. }
  675. static void OnInnerSend(IAsyncResult result)
  676. {
  677. if (result.CompletedSynchronously)
  678. {
  679. return;
  680. }
  681. SendAsyncResult thisPtr = (SendAsyncResult)result.AsyncState;
  682. Exception completionException = null;
  683. try
  684. {
  685. thisPtr.innerChannel.EndSend(result);
  686. }
  687. #pragma warning suppress 56500 // [....], transferring exception to another thread
  688. catch (Exception e)
  689. {
  690. if (Fx.IsFatal(e))
  691. {
  692. throw;
  693. }
  694. completionException = e;
  695. }
  696. thisPtr.Cleanup(completionException == null);
  697. thisPtr.Complete(false, completionException);
  698. }
  699. }
  700. }
  701. }
  702. }