ContextOutputChannelBase.cs 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268
  1. //------------------------------------------------------------
  2. // Copyright (c) Microsoft Corporation. All rights reserved.
  3. //------------------------------------------------------------
  4. namespace System.ServiceModel.Channels
  5. {
  6. using System;
  7. using System.Runtime;
  8. using System.ServiceModel;
  9. abstract class ContextOutputChannelBase<TChannel> : LayeredChannel<TChannel> where TChannel : class, IOutputChannel
  10. {
  11. protected ContextOutputChannelBase(ChannelManagerBase channelManager, TChannel innerChannel)
  12. : base(channelManager, innerChannel)
  13. {
  14. }
  15. public EndpointAddress RemoteAddress
  16. {
  17. get { return this.InnerChannel.RemoteAddress; }
  18. }
  19. public Uri Via
  20. {
  21. get { return this.InnerChannel.Via; }
  22. }
  23. protected abstract ContextProtocol ContextProtocol
  24. {
  25. get;
  26. }
  27. protected abstract bool IsClient
  28. {
  29. get;
  30. }
  31. public IAsyncResult BeginSend(Message message, TimeSpan timeout, AsyncCallback callback, object state)
  32. {
  33. return new SendAsyncResult(message, this, this.ContextProtocol, timeout, callback, state);
  34. }
  35. public IAsyncResult BeginSend(Message message, AsyncCallback callback, object state)
  36. {
  37. return this.BeginSend(message, this.DefaultSendTimeout, callback, state);
  38. }
  39. public void EndSend(IAsyncResult result)
  40. {
  41. SendAsyncResult.End(result);
  42. }
  43. public override T GetProperty<T>()
  44. {
  45. if (typeof(T) == typeof(IContextManager))
  46. {
  47. return (T)(object)this.ContextProtocol;
  48. }
  49. else
  50. {
  51. return base.GetProperty<T>();
  52. }
  53. }
  54. public void Send(Message message, TimeSpan timeout)
  55. {
  56. CorrelationCallbackMessageProperty callback = null;
  57. TimeoutHelper timeoutHelper = new TimeoutHelper(timeout);
  58. Message sendMessage = message;
  59. if (message != null)
  60. {
  61. this.ContextProtocol.OnOutgoingMessage(message, null);
  62. if (CorrelationCallbackMessageProperty.TryGet(message, out callback))
  63. {
  64. ContextExchangeCorrelationHelper.AddOutgoingCorrelationCallbackData(callback, message, this.IsClient);
  65. if (callback.IsFullyDefined)
  66. {
  67. sendMessage = callback.FinalizeCorrelation(message, timeoutHelper.RemainingTime());
  68. }
  69. }
  70. }
  71. try
  72. {
  73. this.InnerChannel.Send(sendMessage, timeoutHelper.RemainingTime());
  74. }
  75. finally
  76. {
  77. if (message != null && !object.ReferenceEquals(message, sendMessage))
  78. {
  79. sendMessage.Close();
  80. }
  81. }
  82. }
  83. public void Send(Message message)
  84. {
  85. this.Send(message, this.DefaultSendTimeout);
  86. }
  87. class SendAsyncResult : AsyncResult
  88. {
  89. static AsyncCallback onFinalizeCorrelation = Fx.ThunkCallback(new AsyncCallback(OnFinalizeCorrelationCompletedCallback));
  90. static AsyncCallback onSend = Fx.ThunkCallback(new AsyncCallback(OnSendCompletedCallback));
  91. ContextOutputChannelBase<TChannel> channel;
  92. CorrelationCallbackMessageProperty correlationCallback;
  93. Message message;
  94. Message sendMessage;
  95. TimeoutHelper timeoutHelper;
  96. public SendAsyncResult(Message message, ContextOutputChannelBase<TChannel> channel, ContextProtocol contextProtocol,
  97. TimeSpan timeout, AsyncCallback callback, object state)
  98. : base(callback, state)
  99. {
  100. this.channel = channel;
  101. this.message = this.sendMessage = message;
  102. this.timeoutHelper = new TimeoutHelper(timeout);
  103. bool shouldSend = true;
  104. if (message != null)
  105. {
  106. contextProtocol.OnOutgoingMessage(message, null);
  107. if (CorrelationCallbackMessageProperty.TryGet(message, out this.correlationCallback))
  108. {
  109. ContextExchangeCorrelationHelper.AddOutgoingCorrelationCallbackData(this.correlationCallback, message, this.channel.IsClient);
  110. if (this.correlationCallback.IsFullyDefined)
  111. {
  112. IAsyncResult result = this.correlationCallback.BeginFinalizeCorrelation(this.message, this.timeoutHelper.RemainingTime(), onFinalizeCorrelation, this);
  113. if (result.CompletedSynchronously)
  114. {
  115. if (OnFinalizeCorrelationCompleted(result))
  116. {
  117. base.Complete(true);
  118. }
  119. }
  120. shouldSend = false;
  121. }
  122. }
  123. }
  124. if (shouldSend)
  125. {
  126. IAsyncResult result = this.channel.InnerChannel.BeginSend(
  127. this.message, this.timeoutHelper.RemainingTime(), onSend, this);
  128. if (result.CompletedSynchronously)
  129. {
  130. OnSendCompleted(result);
  131. base.Complete(true);
  132. }
  133. }
  134. }
  135. public static void End(IAsyncResult result)
  136. {
  137. SendAsyncResult thisPtr = AsyncResult.End<SendAsyncResult>(result);
  138. }
  139. static void OnFinalizeCorrelationCompletedCallback(IAsyncResult result)
  140. {
  141. if (result.CompletedSynchronously)
  142. {
  143. return;
  144. }
  145. SendAsyncResult thisPtr = (SendAsyncResult)result.AsyncState;
  146. Exception completionException = null;
  147. bool completeSelf;
  148. try
  149. {
  150. completeSelf = thisPtr.OnFinalizeCorrelationCompleted(result);
  151. }
  152. catch (Exception e)
  153. {
  154. if (Fx.IsFatal(e))
  155. {
  156. throw;
  157. }
  158. completionException = e;
  159. completeSelf = true;
  160. }
  161. if (completeSelf)
  162. {
  163. thisPtr.Complete(false, completionException);
  164. }
  165. }
  166. static void OnSendCompletedCallback(IAsyncResult result)
  167. {
  168. if (result.CompletedSynchronously)
  169. {
  170. return;
  171. }
  172. SendAsyncResult thisPtr = (SendAsyncResult)result.AsyncState;
  173. Exception completionException = null;
  174. try
  175. {
  176. thisPtr.OnSendCompleted(result);
  177. }
  178. catch (Exception e)
  179. {
  180. if (Fx.IsFatal(e))
  181. {
  182. throw;
  183. }
  184. completionException = e;
  185. }
  186. thisPtr.Complete(false, completionException);
  187. }
  188. bool OnFinalizeCorrelationCompleted(IAsyncResult result)
  189. {
  190. this.sendMessage = this.correlationCallback.EndFinalizeCorrelation(result);
  191. bool throwing = true;
  192. IAsyncResult sendResult;
  193. try
  194. {
  195. sendResult = this.channel.InnerChannel.BeginSend(
  196. this.sendMessage, this.timeoutHelper.RemainingTime(), onSend, this);
  197. throwing = false;
  198. }
  199. finally
  200. {
  201. if (throwing)
  202. {
  203. if (this.message != null && !object.ReferenceEquals(this.message, this.sendMessage))
  204. {
  205. this.sendMessage.Close();
  206. }
  207. }
  208. }
  209. if (sendResult.CompletedSynchronously)
  210. {
  211. OnSendCompleted(sendResult);
  212. return true;
  213. }
  214. return false;
  215. }
  216. void OnSendCompleted(IAsyncResult result)
  217. {
  218. try
  219. {
  220. this.channel.InnerChannel.EndSend(result);
  221. }
  222. finally
  223. {
  224. if (this.message != null && !object.ReferenceEquals(this.message, this.sendMessage))
  225. {
  226. this.sendMessage.Close();
  227. }
  228. }
  229. }
  230. }
  231. }
  232. }