AsyncMethodInvoker.cs 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388
  1. //-----------------------------------------------------------------------------
  2. // Copyright (c) Microsoft Corporation. All rights reserved.
  3. //-----------------------------------------------------------------------------
  4. namespace System.ServiceModel.Dispatcher
  5. {
  6. using System;
  7. using System.Diagnostics;
  8. using System.Reflection;
  9. using System.Runtime.Diagnostics;
  10. using System.Security;
  11. using System.ServiceModel.Description;
  12. using System.ServiceModel.Diagnostics;
  13. using System.ServiceModel.Diagnostics.Application;
  14. using System.Runtime;
  15. class AsyncMethodInvoker : IOperationInvoker
  16. {
  17. MethodInfo beginMethod;
  18. MethodInfo endMethod;
  19. InvokeBeginDelegate invokeBeginDelegate;
  20. InvokeEndDelegate invokeEndDelegate;
  21. int inputParameterCount;
  22. int outputParameterCount;
  23. public AsyncMethodInvoker(MethodInfo beginMethod, MethodInfo endMethod)
  24. {
  25. if (beginMethod == null)
  26. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("beginMethod"));
  27. if (endMethod == null)
  28. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("endMethod"));
  29. this.beginMethod = beginMethod;
  30. this.endMethod = endMethod;
  31. }
  32. public MethodInfo BeginMethod
  33. {
  34. get { return this.beginMethod; }
  35. }
  36. public MethodInfo EndMethod
  37. {
  38. get { return this.endMethod; }
  39. }
  40. public bool IsSynchronous
  41. {
  42. get { return false; }
  43. }
  44. public object[] AllocateInputs()
  45. {
  46. return EmptyArray.Allocate(this.InputParameterCount);
  47. }
  48. public object Invoke(object instance, object[] inputs, out object[] outputs)
  49. {
  50. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotImplementedException());
  51. }
  52. internal static void CreateActivityInfo(ref ServiceModelActivity activity, ref Activity boundActivity)
  53. {
  54. if (DiagnosticUtility.ShouldUseActivity)
  55. {
  56. activity = ServiceModelActivity.CreateAsyncActivity();
  57. TraceUtility.UpdateAsyncOperationContextWithActivity(activity);
  58. boundActivity = ServiceModelActivity.BoundOperation(activity, true);
  59. }
  60. else if (TraceUtility.MessageFlowTracingOnly)
  61. {
  62. Guid activityId = TraceUtility.GetReceivedActivityId(OperationContext.Current);
  63. if (activityId != Guid.Empty)
  64. {
  65. DiagnosticTraceBase.ActivityId = activityId;
  66. }
  67. }
  68. else if (TraceUtility.ShouldPropagateActivity)
  69. {
  70. //Message flow tracing only scenarios use a light-weight ActivityID management logic
  71. Guid activityId = ActivityIdHeader.ExtractActivityId(OperationContext.Current.IncomingMessage);
  72. if (activityId != Guid.Empty)
  73. {
  74. boundActivity = Activity.CreateActivity(activityId);
  75. }
  76. TraceUtility.UpdateAsyncOperationContextWithActivity(activityId);
  77. }
  78. }
  79. public IAsyncResult InvokeBegin(object instance, object[] inputs, AsyncCallback callback, object state)
  80. {
  81. if (instance == null)
  82. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.SFxNoServiceObject)));
  83. if (inputs == null)
  84. {
  85. if (this.InputParameterCount > 0)
  86. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.SFxInputParametersToServiceNull, this.InputParameterCount)));
  87. }
  88. else if (inputs.Length != this.InputParameterCount)
  89. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.SFxInputParametersToServiceInvalid, this.InputParameterCount, inputs.Length)));
  90. StartOperationInvokePerformanceCounters(this.beginMethod.Name.Substring(ServiceReflector.BeginMethodNamePrefix.Length));
  91. IAsyncResult returnValue;
  92. bool callFailed = true;
  93. bool callFaulted = false;
  94. ServiceModelActivity activity = null;
  95. try
  96. {
  97. Activity boundActivity = null;
  98. CreateActivityInfo(ref activity, ref boundActivity);
  99. StartOperationInvokeTrace(this.beginMethod.Name);
  100. using (boundActivity)
  101. {
  102. if (DiagnosticUtility.ShouldUseActivity)
  103. {
  104. string activityName = null;
  105. if (this.endMethod == null)
  106. {
  107. activityName = SR.GetString(SR.ActivityExecuteMethod,
  108. this.beginMethod.DeclaringType.FullName, this.beginMethod.Name);
  109. }
  110. else
  111. {
  112. activityName = SR.GetString(SR.ActivityExecuteAsyncMethod,
  113. this.beginMethod.DeclaringType.FullName, this.beginMethod.Name,
  114. this.endMethod.DeclaringType.FullName, this.endMethod.Name);
  115. }
  116. ServiceModelActivity.Start(activity, activityName, ActivityType.ExecuteUserCode);
  117. }
  118. returnValue = this.InvokeBeginDelegate(instance, inputs, callback, state);
  119. callFailed = false;
  120. }
  121. }
  122. catch (System.Security.SecurityException e)
  123. {
  124. DiagnosticUtility.TraceHandledException(e, TraceEventType.Warning);
  125. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(AuthorizationBehavior.CreateAccessDeniedFaultException());
  126. }
  127. catch (Exception e)
  128. {
  129. TraceUtility.TraceUserCodeException(e, this.beginMethod);
  130. if (e is FaultException)
  131. {
  132. callFaulted = true;
  133. callFailed = false;
  134. }
  135. throw;
  136. }
  137. finally
  138. {
  139. ServiceModelActivity.Stop(activity);
  140. // An exception during the InvokeBegin will not call InvokeEnd,
  141. // so we complete the trace and performance counters here.
  142. if (callFailed || callFaulted)
  143. {
  144. StopOperationInvokeTrace(callFailed, callFaulted, this.EndMethod.Name);
  145. StopOperationInvokePerformanceCounters(callFailed, callFaulted, endMethod.Name.Substring(ServiceReflector.EndMethodNamePrefix.Length));
  146. }
  147. }
  148. return returnValue;
  149. }
  150. internal static void GetActivityInfo(ref ServiceModelActivity activity, ref Activity boundOperation)
  151. {
  152. if (TraceUtility.MessageFlowTracingOnly)
  153. {
  154. if (null != OperationContext.Current)
  155. {
  156. Guid activityId = TraceUtility.GetReceivedActivityId(OperationContext.Current);
  157. if (activityId != Guid.Empty)
  158. {
  159. DiagnosticTraceBase.ActivityId = activityId;
  160. }
  161. }
  162. }
  163. else if (DiagnosticUtility.ShouldUseActivity || TraceUtility.ShouldPropagateActivity)
  164. {
  165. object activityInfo = TraceUtility.ExtractAsyncOperationContextActivity();
  166. if (activityInfo != null)
  167. {
  168. if (DiagnosticUtility.ShouldUseActivity)
  169. {
  170. activity = activityInfo as ServiceModelActivity;
  171. boundOperation = ServiceModelActivity.BoundOperation(activity, true);
  172. }
  173. else if (TraceUtility.ShouldPropagateActivity)
  174. {
  175. if (activityInfo is Guid)
  176. {
  177. Guid activityId = (Guid)activityInfo;
  178. boundOperation = Activity.CreateActivity(activityId);
  179. }
  180. }
  181. }
  182. }
  183. }
  184. public object InvokeEnd(object instance, out object[] outputs, IAsyncResult result)
  185. {
  186. object returnVal;
  187. if (instance == null)
  188. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.SFxNoServiceObject)));
  189. outputs = EmptyArray.Allocate(this.OutputParameterCount);
  190. bool callFailed = true;
  191. bool callFaulted = false;
  192. ServiceModelActivity activity = null;
  193. try
  194. {
  195. Activity boundOperation = null;
  196. GetActivityInfo(ref activity, ref boundOperation);
  197. using (boundOperation)
  198. {
  199. returnVal = this.InvokeEndDelegate(instance, outputs, result);
  200. callFailed = false;
  201. }
  202. }
  203. catch (SecurityException e)
  204. {
  205. DiagnosticUtility.TraceHandledException(e, TraceEventType.Warning);
  206. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(AuthorizationBehavior.CreateAccessDeniedFaultException());
  207. }
  208. catch (FaultException)
  209. {
  210. callFaulted = true;
  211. callFailed = false;
  212. throw;
  213. }
  214. finally
  215. {
  216. ServiceModelActivity.Stop(activity);
  217. StopOperationInvokeTrace(callFailed, callFaulted, this.endMethod.Name);
  218. StopOperationInvokePerformanceCounters(callFailed, callFaulted, this.endMethod.Name.Substring(ServiceReflector.EndMethodNamePrefix.Length));
  219. }
  220. return returnVal;
  221. }
  222. internal static void StartOperationInvokeTrace(string methodName)
  223. {
  224. if (TD.OperationInvokedIsEnabled())
  225. {
  226. OperationContext context = OperationContext.Current;
  227. EventTraceActivity eventTraceActivity = null;
  228. if (context != null && context.IncomingMessage != null)
  229. {
  230. eventTraceActivity = EventTraceActivityHelper.TryExtractActivity(context.IncomingMessage);
  231. }
  232. if (TD.OperationInvokedIsEnabled())
  233. {
  234. TD.OperationInvoked(eventTraceActivity, methodName, TraceUtility.GetCallerInfo(OperationContext.Current));
  235. }
  236. if (TD.OperationCompletedIsEnabled() || TD.OperationFaultedIsEnabled() || TD.OperationFailedIsEnabled())
  237. {
  238. TraceUtility.UpdateAsyncOperationContextWithStartTime(eventTraceActivity, DateTime.UtcNow.Ticks);
  239. }
  240. }
  241. }
  242. internal static void StopOperationInvokeTrace(bool callFailed, bool callFaulted, string methodName)
  243. {
  244. if (!(TD.OperationCompletedIsEnabled() ||
  245. TD.OperationFaultedIsEnabled() ||
  246. TD.OperationFailedIsEnabled()))
  247. {
  248. return;
  249. }
  250. EventTraceActivity eventTraceActivity;
  251. long startTime;
  252. TraceUtility.ExtractAsyncOperationStartTime(out eventTraceActivity, out startTime);
  253. long duration = TraceUtility.GetUtcBasedDurationForTrace(startTime);
  254. if (callFailed)
  255. {
  256. if (TD.OperationFailedIsEnabled())
  257. {
  258. TD.OperationFailed(eventTraceActivity, methodName, duration);
  259. }
  260. }
  261. else if (callFaulted)
  262. {
  263. if (TD.OperationFaultedIsEnabled())
  264. {
  265. TD.OperationFaulted(eventTraceActivity, methodName, duration);
  266. }
  267. }
  268. else
  269. {
  270. if (TD.OperationCompletedIsEnabled())
  271. {
  272. TD.OperationCompleted(eventTraceActivity, methodName, duration);
  273. }
  274. }
  275. }
  276. internal static void StartOperationInvokePerformanceCounters(string methodName)
  277. {
  278. if (PerformanceCounters.PerformanceCountersEnabled)
  279. {
  280. PerformanceCounters.MethodCalled(methodName);
  281. }
  282. }
  283. internal static void StopOperationInvokePerformanceCounters(bool callFailed, bool callFaulted, string methodName)
  284. {
  285. if (PerformanceCounters.PerformanceCountersEnabled)
  286. {
  287. if (callFailed)
  288. {
  289. PerformanceCounters.MethodReturnedError(methodName);
  290. }
  291. else if (callFaulted)
  292. {
  293. PerformanceCounters.MethodReturnedFault(methodName);
  294. }
  295. else
  296. {
  297. PerformanceCounters.MethodReturnedSuccess(methodName);
  298. }
  299. }
  300. }
  301. InvokeBeginDelegate InvokeBeginDelegate
  302. {
  303. get
  304. {
  305. EnsureIsInitialized();
  306. return invokeBeginDelegate;
  307. }
  308. }
  309. InvokeEndDelegate InvokeEndDelegate
  310. {
  311. get
  312. {
  313. EnsureIsInitialized();
  314. return invokeEndDelegate;
  315. }
  316. }
  317. int InputParameterCount
  318. {
  319. get
  320. {
  321. EnsureIsInitialized();
  322. return this.inputParameterCount;
  323. }
  324. }
  325. int OutputParameterCount
  326. {
  327. get
  328. {
  329. EnsureIsInitialized();
  330. return this.outputParameterCount;
  331. }
  332. }
  333. void EnsureIsInitialized()
  334. {
  335. if (this.invokeBeginDelegate == null)
  336. {
  337. // Only pass locals byref because InvokerUtil may store temporary results in the byref.
  338. // If two threads both reference this.count, temporary results may interact.
  339. int inputParameterCount;
  340. InvokeBeginDelegate invokeBeginDelegate = new InvokerUtil().GenerateInvokeBeginDelegate(this.beginMethod, out inputParameterCount);
  341. this.inputParameterCount = inputParameterCount;
  342. int outputParameterCount;
  343. InvokeEndDelegate invokeEndDelegate = new InvokerUtil().GenerateInvokeEndDelegate(this.endMethod, out outputParameterCount);
  344. this.outputParameterCount = outputParameterCount;
  345. this.invokeEndDelegate = invokeEndDelegate;
  346. this.invokeBeginDelegate = invokeBeginDelegate; // must set this last due to ----
  347. }
  348. }
  349. }
  350. }