ImmutableClientRuntime.cs 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371
  1. //-----------------------------------------------------------------------------
  2. // Copyright (c) Microsoft Corporation. All rights reserved.
  3. //-----------------------------------------------------------------------------
  4. namespace System.ServiceModel.Dispatcher
  5. {
  6. using System;
  7. using System.Collections.Generic;
  8. using System.Reflection;
  9. using System.Runtime;
  10. using System.Runtime.Remoting.Messaging;
  11. using System.ServiceModel;
  12. using System.ServiceModel.Channels;
  13. using System.ServiceModel.Diagnostics.Application;
  14. using System.Transactions;
  15. class ImmutableClientRuntime
  16. {
  17. int correlationCount;
  18. bool addTransactionFlowProperties;
  19. IInteractiveChannelInitializer[] interactiveChannelInitializers;
  20. IClientOperationSelector operationSelector;
  21. IChannelInitializer[] channelInitializers;
  22. IClientMessageInspector[] messageInspectors;
  23. Dictionary<string, ProxyOperationRuntime> operations;
  24. ProxyOperationRuntime unhandled;
  25. bool useSynchronizationContext;
  26. bool validateMustUnderstand;
  27. internal ImmutableClientRuntime(ClientRuntime behavior)
  28. {
  29. this.channelInitializers = EmptyArray<IChannelInitializer>.ToArray(behavior.ChannelInitializers);
  30. this.interactiveChannelInitializers = EmptyArray<IInteractiveChannelInitializer>.ToArray(behavior.InteractiveChannelInitializers);
  31. this.messageInspectors = EmptyArray<IClientMessageInspector>.ToArray(behavior.MessageInspectors);
  32. this.operationSelector = behavior.OperationSelector;
  33. this.useSynchronizationContext = behavior.UseSynchronizationContext;
  34. this.validateMustUnderstand = behavior.ValidateMustUnderstand;
  35. this.unhandled = new ProxyOperationRuntime(behavior.UnhandledClientOperation, this);
  36. this.addTransactionFlowProperties = behavior.AddTransactionFlowProperties;
  37. this.operations = new Dictionary<string, ProxyOperationRuntime>();
  38. for (int i = 0; i < behavior.Operations.Count; i++)
  39. {
  40. ClientOperation operation = behavior.Operations[i];
  41. ProxyOperationRuntime operationRuntime = new ProxyOperationRuntime(operation, this);
  42. this.operations.Add(operation.Name, operationRuntime);
  43. }
  44. this.correlationCount = this.messageInspectors.Length + behavior.MaxParameterInspectors;
  45. }
  46. internal int MessageInspectorCorrelationOffset
  47. {
  48. get { return 0; }
  49. }
  50. internal int ParameterInspectorCorrelationOffset
  51. {
  52. get { return this.messageInspectors.Length; }
  53. }
  54. internal int CorrelationCount
  55. {
  56. get { return this.correlationCount; }
  57. }
  58. internal IClientOperationSelector OperationSelector
  59. {
  60. get { return this.operationSelector; }
  61. }
  62. internal ProxyOperationRuntime UnhandledProxyOperation
  63. {
  64. get { return this.unhandled; }
  65. }
  66. internal bool UseSynchronizationContext
  67. {
  68. get { return this.useSynchronizationContext; }
  69. }
  70. internal bool ValidateMustUnderstand
  71. {
  72. get { return validateMustUnderstand; }
  73. set { validateMustUnderstand = value; }
  74. }
  75. internal void AfterReceiveReply(ref ProxyRpc rpc)
  76. {
  77. int offset = this.MessageInspectorCorrelationOffset;
  78. try
  79. {
  80. for (int i = 0; i < this.messageInspectors.Length; i++)
  81. {
  82. this.messageInspectors[i].AfterReceiveReply(ref rpc.Reply, rpc.Correlation[offset + i]);
  83. if (TD.ClientMessageInspectorAfterReceiveInvokedIsEnabled())
  84. {
  85. TD.ClientMessageInspectorAfterReceiveInvoked(rpc.EventTraceActivity, this.messageInspectors[i].GetType().FullName);
  86. }
  87. }
  88. }
  89. catch (Exception e)
  90. {
  91. if (Fx.IsFatal(e))
  92. {
  93. throw;
  94. }
  95. if (ErrorBehavior.ShouldRethrowClientSideExceptionAsIs(e))
  96. {
  97. throw;
  98. }
  99. throw DiagnosticUtility.ExceptionUtility.ThrowHelperCallback(e);
  100. }
  101. }
  102. internal void BeforeSendRequest(ref ProxyRpc rpc)
  103. {
  104. int offset = this.MessageInspectorCorrelationOffset;
  105. try
  106. {
  107. for (int i = 0; i < this.messageInspectors.Length; i++)
  108. {
  109. rpc.Correlation[offset + i] = this.messageInspectors[i].BeforeSendRequest(ref rpc.Request, (IClientChannel)rpc.Channel.Proxy);
  110. if (TD.ClientMessageInspectorBeforeSendInvokedIsEnabled())
  111. {
  112. TD.ClientMessageInspectorBeforeSendInvoked(rpc.EventTraceActivity, this.messageInspectors[i].GetType().FullName);
  113. }
  114. }
  115. }
  116. catch (Exception e)
  117. {
  118. if (Fx.IsFatal(e))
  119. {
  120. throw;
  121. }
  122. if (ErrorBehavior.ShouldRethrowClientSideExceptionAsIs(e))
  123. {
  124. throw;
  125. }
  126. throw DiagnosticUtility.ExceptionUtility.ThrowHelperCallback(e);
  127. }
  128. if (this.addTransactionFlowProperties)
  129. {
  130. SendTransaction(ref rpc);
  131. }
  132. }
  133. internal void DisplayInitializationUI(ServiceChannel channel)
  134. {
  135. EndDisplayInitializationUI(BeginDisplayInitializationUI(channel, null, null));
  136. }
  137. internal IAsyncResult BeginDisplayInitializationUI(ServiceChannel channel, AsyncCallback callback, object state)
  138. {
  139. return new DisplayInitializationUIAsyncResult(channel, this.interactiveChannelInitializers, callback, state);
  140. }
  141. internal void EndDisplayInitializationUI(IAsyncResult result)
  142. {
  143. DisplayInitializationUIAsyncResult.End(result);
  144. }
  145. // this should not be inlined, since we want to JIT the reference to System.Transactions
  146. // only if transactions are being flowed.
  147. [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.NoInlining)]
  148. static void SendTransaction(ref ProxyRpc rpc)
  149. {
  150. System.ServiceModel.Channels.TransactionFlowProperty.Set(Transaction.Current, rpc.Request);
  151. }
  152. internal void InitializeChannel(IClientChannel channel)
  153. {
  154. try
  155. {
  156. for (int i = 0; i < this.channelInitializers.Length; ++i)
  157. {
  158. this.channelInitializers[i].Initialize(channel);
  159. }
  160. }
  161. catch (Exception e)
  162. {
  163. if (Fx.IsFatal(e))
  164. {
  165. throw;
  166. }
  167. if (ErrorBehavior.ShouldRethrowClientSideExceptionAsIs(e))
  168. {
  169. throw;
  170. }
  171. throw DiagnosticUtility.ExceptionUtility.ThrowHelperCallback(e);
  172. }
  173. }
  174. internal ProxyOperationRuntime GetOperation(MethodBase methodBase, object[] args, out bool canCacheResult)
  175. {
  176. if (this.operationSelector == null)
  177. {
  178. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotSupportedException
  179. (SR.GetString(SR.SFxNeedProxyBehaviorOperationSelector2,
  180. methodBase.Name,
  181. methodBase.DeclaringType.Name)));
  182. }
  183. try
  184. {
  185. if (operationSelector.AreParametersRequiredForSelection)
  186. {
  187. canCacheResult = false;
  188. }
  189. else
  190. {
  191. args = null;
  192. canCacheResult = true;
  193. }
  194. string operationName = operationSelector.SelectOperation(methodBase, args);
  195. ProxyOperationRuntime operation;
  196. if ((operationName != null) && this.operations.TryGetValue(operationName, out operation))
  197. {
  198. return operation;
  199. }
  200. else
  201. {
  202. // did not find the right operation, will not know how
  203. // to invoke the method.
  204. return null;
  205. }
  206. }
  207. catch (Exception e)
  208. {
  209. if (Fx.IsFatal(e))
  210. {
  211. throw;
  212. }
  213. if (ErrorBehavior.ShouldRethrowClientSideExceptionAsIs(e))
  214. {
  215. throw;
  216. }
  217. throw DiagnosticUtility.ExceptionUtility.ThrowHelperCallback(e);
  218. }
  219. }
  220. internal ProxyOperationRuntime GetOperationByName(string operationName)
  221. {
  222. ProxyOperationRuntime operation = null;
  223. if (this.operations.TryGetValue(operationName, out operation))
  224. return operation;
  225. else
  226. return null;
  227. }
  228. class DisplayInitializationUIAsyncResult : System.Runtime.AsyncResult
  229. {
  230. ServiceChannel channel;
  231. int index = -1;
  232. IInteractiveChannelInitializer[] initializers;
  233. IClientChannel proxy;
  234. static AsyncCallback callback = Fx.ThunkCallback(new AsyncCallback(DisplayInitializationUIAsyncResult.Callback));
  235. internal DisplayInitializationUIAsyncResult(ServiceChannel channel,
  236. IInteractiveChannelInitializer[] initializers,
  237. AsyncCallback callback, object state)
  238. : base(callback, state)
  239. {
  240. this.channel = channel;
  241. this.initializers = initializers;
  242. this.proxy = channel.Proxy as IClientChannel;
  243. this.CallBegin(true);
  244. }
  245. void CallBegin(bool completedSynchronously)
  246. {
  247. while (++this.index < initializers.Length)
  248. {
  249. IAsyncResult result = null;
  250. Exception exception = null;
  251. try
  252. {
  253. result = this.initializers[this.index].BeginDisplayInitializationUI(
  254. this.proxy,
  255. DisplayInitializationUIAsyncResult.callback,
  256. this
  257. );
  258. }
  259. catch (Exception e)
  260. {
  261. if (Fx.IsFatal(e))
  262. {
  263. throw;
  264. }
  265. exception = e;
  266. }
  267. if (exception == null)
  268. {
  269. if (!result.CompletedSynchronously)
  270. {
  271. return;
  272. }
  273. this.CallEnd(result, out exception);
  274. }
  275. if (exception != null)
  276. {
  277. this.CallComplete(completedSynchronously, exception);
  278. return;
  279. }
  280. }
  281. this.CallComplete(completedSynchronously, null);
  282. }
  283. static void Callback(IAsyncResult result)
  284. {
  285. if (result.CompletedSynchronously)
  286. {
  287. return;
  288. }
  289. DisplayInitializationUIAsyncResult outer = (DisplayInitializationUIAsyncResult)result.AsyncState;
  290. Exception exception = null;
  291. outer.CallEnd(result, out exception);
  292. if (exception != null)
  293. {
  294. outer.CallComplete(false, exception);
  295. return;
  296. }
  297. outer.CallBegin(false);
  298. }
  299. void CallEnd(IAsyncResult result, out Exception exception)
  300. {
  301. try
  302. {
  303. this.initializers[this.index].EndDisplayInitializationUI(result);
  304. exception = null;
  305. }
  306. catch (Exception e)
  307. {
  308. if (Fx.IsFatal(e))
  309. {
  310. throw;
  311. }
  312. exception = e;
  313. }
  314. }
  315. void CallComplete(bool completedSynchronously, Exception exception)
  316. {
  317. this.Complete(completedSynchronously, exception);
  318. }
  319. internal static void End(IAsyncResult result)
  320. {
  321. System.Runtime.AsyncResult.End<DisplayInitializationUIAsyncResult>(result);
  322. }
  323. }
  324. }
  325. }