ProxyOperationRuntime.cs 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427
  1. //-----------------------------------------------------------------------------
  2. // Copyright (c) Microsoft Corporation. All rights reserved.
  3. //-----------------------------------------------------------------------------
  4. namespace System.ServiceModel.Dispatcher
  5. {
  6. using System;
  7. using System.Collections.ObjectModel;
  8. using System.Reflection;
  9. using System.Runtime;
  10. using System.Runtime.Remoting.Messaging;
  11. using System.Security;
  12. using System.ServiceModel;
  13. using System.ServiceModel.Channels;
  14. using System.ServiceModel.Description;
  15. using System.ServiceModel.Diagnostics;
  16. using System.ServiceModel.Diagnostics.Application;
  17. class ProxyOperationRuntime
  18. {
  19. static internal readonly ParameterInfo[] NoParams = new ParameterInfo[0];
  20. static internal readonly object[] EmptyArray = new object[0];
  21. readonly IClientMessageFormatter formatter;
  22. readonly bool isInitiating;
  23. readonly bool isOneWay;
  24. readonly bool isTerminating;
  25. readonly bool isSessionOpenNotificationEnabled;
  26. readonly string name;
  27. readonly IParameterInspector[] parameterInspectors;
  28. readonly IClientFaultFormatter faultFormatter;
  29. readonly ImmutableClientRuntime parent;
  30. bool serializeRequest;
  31. bool deserializeReply;
  32. string action;
  33. string replyAction;
  34. MethodInfo beginMethod;
  35. MethodInfo syncMethod;
  36. MethodInfo taskMethod;
  37. ParameterInfo[] inParams;
  38. ParameterInfo[] outParams;
  39. ParameterInfo[] endOutParams;
  40. ParameterInfo returnParam;
  41. internal ProxyOperationRuntime(ClientOperation operation, ImmutableClientRuntime parent)
  42. {
  43. if (operation == null)
  44. throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("operation");
  45. if (parent == null)
  46. throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("parent");
  47. this.parent = parent;
  48. this.formatter = operation.Formatter;
  49. this.isInitiating = operation.IsInitiating;
  50. this.isOneWay = operation.IsOneWay;
  51. this.isTerminating = operation.IsTerminating;
  52. this.isSessionOpenNotificationEnabled = operation.IsSessionOpenNotificationEnabled;
  53. this.name = operation.Name;
  54. this.parameterInspectors = EmptyArray<IParameterInspector>.ToArray(operation.ParameterInspectors);
  55. this.faultFormatter = operation.FaultFormatter;
  56. this.serializeRequest = operation.SerializeRequest;
  57. this.deserializeReply = operation.DeserializeReply;
  58. this.action = operation.Action;
  59. this.replyAction = operation.ReplyAction;
  60. this.beginMethod = operation.BeginMethod;
  61. this.syncMethod = operation.SyncMethod;
  62. this.taskMethod = operation.TaskMethod;
  63. this.TaskTResult = operation.TaskTResult;
  64. if (this.beginMethod != null)
  65. {
  66. this.inParams = ServiceReflector.GetInputParameters(this.beginMethod, true);
  67. if (this.syncMethod != null)
  68. {
  69. this.outParams = ServiceReflector.GetOutputParameters(this.syncMethod, false);
  70. }
  71. else
  72. {
  73. this.outParams = NoParams;
  74. }
  75. this.endOutParams = ServiceReflector.GetOutputParameters(operation.EndMethod, true);
  76. this.returnParam = operation.EndMethod.ReturnParameter;
  77. }
  78. else if (this.syncMethod != null)
  79. {
  80. this.inParams = ServiceReflector.GetInputParameters(this.syncMethod, false);
  81. this.outParams = ServiceReflector.GetOutputParameters(this.syncMethod, false);
  82. this.returnParam = this.syncMethod.ReturnParameter;
  83. }
  84. if (this.formatter == null && (serializeRequest || deserializeReply))
  85. {
  86. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.ClientRuntimeRequiresFormatter0, this.name)));
  87. }
  88. }
  89. internal string Action
  90. {
  91. get { return this.action; }
  92. }
  93. internal IClientFaultFormatter FaultFormatter
  94. {
  95. get { return this.faultFormatter; }
  96. }
  97. internal bool IsInitiating
  98. {
  99. get { return this.isInitiating; }
  100. }
  101. internal bool IsOneWay
  102. {
  103. get { return this.isOneWay; }
  104. }
  105. internal bool IsTerminating
  106. {
  107. get { return this.isTerminating; }
  108. }
  109. internal bool IsSessionOpenNotificationEnabled
  110. {
  111. get { return this.isSessionOpenNotificationEnabled; }
  112. }
  113. internal string Name
  114. {
  115. get { return this.name; }
  116. }
  117. internal ImmutableClientRuntime Parent
  118. {
  119. get { return this.parent; }
  120. }
  121. internal string ReplyAction
  122. {
  123. get { return this.replyAction; }
  124. }
  125. internal bool DeserializeReply
  126. {
  127. get { return this.deserializeReply; }
  128. }
  129. internal bool SerializeRequest
  130. {
  131. get { return this.serializeRequest; }
  132. }
  133. internal Type TaskTResult
  134. {
  135. get;
  136. set;
  137. }
  138. internal void AfterReply(ref ProxyRpc rpc)
  139. {
  140. if (!this.isOneWay)
  141. {
  142. Message reply = rpc.Reply;
  143. if (this.deserializeReply)
  144. {
  145. if (TD.ClientFormatterDeserializeReplyStartIsEnabled())
  146. {
  147. TD.ClientFormatterDeserializeReplyStart(rpc.EventTraceActivity);
  148. }
  149. rpc.ReturnValue = this.formatter.DeserializeReply(reply, rpc.OutputParameters);
  150. if (TD.ClientFormatterDeserializeReplyStopIsEnabled())
  151. {
  152. TD.ClientFormatterDeserializeReplyStop(rpc.EventTraceActivity);
  153. }
  154. }
  155. else
  156. {
  157. rpc.ReturnValue = reply;
  158. }
  159. int offset = this.parent.ParameterInspectorCorrelationOffset;
  160. try
  161. {
  162. for (int i = parameterInspectors.Length - 1; i >= 0; i--)
  163. {
  164. this.parameterInspectors[i].AfterCall(this.name,
  165. rpc.OutputParameters,
  166. rpc.ReturnValue,
  167. rpc.Correlation[offset + i]);
  168. if (TD.ClientParameterInspectorAfterCallInvokedIsEnabled())
  169. {
  170. TD.ClientParameterInspectorAfterCallInvoked(rpc.EventTraceActivity, this.parameterInspectors[i].GetType().FullName);
  171. }
  172. }
  173. }
  174. catch (Exception e)
  175. {
  176. if (Fx.IsFatal(e))
  177. {
  178. throw;
  179. }
  180. if (ErrorBehavior.ShouldRethrowClientSideExceptionAsIs(e))
  181. {
  182. throw;
  183. }
  184. throw DiagnosticUtility.ExceptionUtility.ThrowHelperCallback(e);
  185. }
  186. if (parent.ValidateMustUnderstand)
  187. {
  188. Collection<MessageHeaderInfo> headersNotUnderstood = reply.Headers.GetHeadersNotUnderstood();
  189. if (headersNotUnderstood != null && headersNotUnderstood.Count > 0)
  190. {
  191. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ProtocolException(SR.GetString(SR.SFxHeaderNotUnderstood, headersNotUnderstood[0].Name, headersNotUnderstood[0].Namespace)));
  192. }
  193. }
  194. }
  195. }
  196. internal void BeforeRequest(ref ProxyRpc rpc)
  197. {
  198. int offset = this.parent.ParameterInspectorCorrelationOffset;
  199. try
  200. {
  201. for (int i = 0; i < parameterInspectors.Length; i++)
  202. {
  203. rpc.Correlation[offset + i] = this.parameterInspectors[i].BeforeCall(this.name, rpc.InputParameters);
  204. if (TD.ClientParameterInspectorBeforeCallInvokedIsEnabled())
  205. {
  206. TD.ClientParameterInspectorBeforeCallInvoked(rpc.EventTraceActivity, this.parameterInspectors[i].GetType().FullName);
  207. }
  208. }
  209. }
  210. catch (Exception e)
  211. {
  212. if (Fx.IsFatal(e))
  213. {
  214. throw;
  215. }
  216. if (ErrorBehavior.ShouldRethrowClientSideExceptionAsIs(e))
  217. {
  218. throw;
  219. }
  220. throw DiagnosticUtility.ExceptionUtility.ThrowHelperCallback(e);
  221. }
  222. if (this.serializeRequest)
  223. {
  224. if (TD.ClientFormatterSerializeRequestStartIsEnabled())
  225. {
  226. TD.ClientFormatterSerializeRequestStart(rpc.EventTraceActivity);
  227. }
  228. rpc.Request = this.formatter.SerializeRequest(rpc.MessageVersion, rpc.InputParameters);
  229. if (TD.ClientFormatterSerializeRequestStopIsEnabled())
  230. {
  231. TD.ClientFormatterSerializeRequestStop(rpc.EventTraceActivity);
  232. }
  233. }
  234. else
  235. {
  236. if (rpc.InputParameters[0] == null)
  237. {
  238. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.SFxProxyRuntimeMessageCannotBeNull, this.name)));
  239. }
  240. rpc.Request = (Message)rpc.InputParameters[0];
  241. if (!IsValidAction(rpc.Request, Action))
  242. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.SFxInvalidRequestAction, this.Name, rpc.Request.Headers.Action ?? "{NULL}", this.Action)));
  243. }
  244. }
  245. internal static object GetDefaultParameterValue(Type parameterType)
  246. {
  247. return (parameterType.IsValueType && parameterType != typeof(void)) ? Activator.CreateInstance(parameterType) : null;
  248. }
  249. [SecurityCritical]
  250. internal bool IsSyncCall(IMethodCallMessage methodCall)
  251. {
  252. if (this.syncMethod == null)
  253. {
  254. return false;
  255. }
  256. return (methodCall.MethodBase.MethodHandle == this.syncMethod.MethodHandle);
  257. }
  258. [SecurityCritical]
  259. internal bool IsBeginCall(IMethodCallMessage methodCall)
  260. {
  261. if (this.beginMethod == null)
  262. {
  263. return false;
  264. }
  265. return (methodCall.MethodBase.MethodHandle == this.beginMethod.MethodHandle);
  266. }
  267. [SecurityCritical]
  268. internal bool IsTaskCall(IMethodCallMessage methodCall)
  269. {
  270. if (this.taskMethod == null)
  271. {
  272. return false;
  273. }
  274. return (methodCall.MethodBase.MethodHandle == this.taskMethod.MethodHandle);
  275. }
  276. [SecurityCritical]
  277. internal object[] MapSyncInputs(IMethodCallMessage methodCall, out object[] outs)
  278. {
  279. if (this.outParams.Length == 0)
  280. {
  281. outs = EmptyArray;
  282. }
  283. else
  284. {
  285. outs = new object[this.outParams.Length];
  286. }
  287. if (this.inParams.Length == 0)
  288. return EmptyArray;
  289. return methodCall.InArgs;
  290. }
  291. [SecurityCritical]
  292. internal object[] MapAsyncBeginInputs(IMethodCallMessage methodCall, out AsyncCallback callback, out object asyncState)
  293. {
  294. object[] ins;
  295. if (this.inParams.Length == 0)
  296. {
  297. ins = EmptyArray;
  298. }
  299. else
  300. {
  301. ins = new object[this.inParams.Length];
  302. }
  303. object[] args = methodCall.Args;
  304. for (int i = 0; i < ins.Length; i++)
  305. {
  306. ins[i] = args[this.inParams[i].Position];
  307. }
  308. callback = args[methodCall.ArgCount - 2] as AsyncCallback;
  309. asyncState = args[methodCall.ArgCount - 1];
  310. return ins;
  311. }
  312. [SecurityCritical]
  313. internal void MapAsyncEndInputs(IMethodCallMessage methodCall, out IAsyncResult result, out object[] outs)
  314. {
  315. outs = new object[this.endOutParams.Length];
  316. result = methodCall.Args[methodCall.ArgCount - 1] as IAsyncResult;
  317. }
  318. [SecurityCritical]
  319. internal object[] MapSyncOutputs(IMethodCallMessage methodCall, object[] outs, ref object ret)
  320. {
  321. return MapOutputs(this.outParams, methodCall, outs, ref ret);
  322. }
  323. [SecurityCritical]
  324. internal object[] MapAsyncOutputs(IMethodCallMessage methodCall, object[] outs, ref object ret)
  325. {
  326. return MapOutputs(this.endOutParams, methodCall, outs, ref ret);
  327. }
  328. [SecurityCritical]
  329. object[] MapOutputs(ParameterInfo[] parameters, IMethodCallMessage methodCall, object[] outs, ref object ret)
  330. {
  331. if (ret == null && this.returnParam != null)
  332. {
  333. ret = GetDefaultParameterValue(TypeLoader.GetParameterType(this.returnParam));
  334. }
  335. if (parameters.Length == 0)
  336. {
  337. return null;
  338. }
  339. object[] args = methodCall.Args;
  340. for (int i = 0; i < parameters.Length; i++)
  341. {
  342. if (outs[i] == null)
  343. {
  344. // the RealProxy infrastructure requires a default value for value types
  345. args[parameters[i].Position] = GetDefaultParameterValue(TypeLoader.GetParameterType(parameters[i]));
  346. }
  347. else
  348. {
  349. args[parameters[i].Position] = outs[i];
  350. }
  351. }
  352. return args;
  353. }
  354. static internal bool IsValidAction(Message message, string action)
  355. {
  356. if (message == null)
  357. {
  358. return false;
  359. }
  360. if (message.IsFault)
  361. {
  362. return true;
  363. }
  364. if (action == MessageHeaders.WildcardAction)
  365. {
  366. return true;
  367. }
  368. return (String.CompareOrdinal(message.Headers.Action, action) == 0);
  369. }
  370. }
  371. }