MessageRpc.cs 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859
  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.Diagnostics;
  9. using System.Runtime;
  10. using System.Runtime.CompilerServices;
  11. using System.Runtime.Diagnostics;
  12. using System.Security;
  13. using System.ServiceModel;
  14. using System.ServiceModel.Activation;
  15. using System.ServiceModel.Channels;
  16. using System.ServiceModel.Diagnostics;
  17. using System.Threading;
  18. using System.Xml;
  19. using System.Transactions;
  20. using System.ServiceModel.Diagnostics.Application;
  21. delegate void MessageRpcProcessor(ref MessageRpc rpc);
  22. struct MessageRpc
  23. {
  24. internal readonly ServiceChannel Channel;
  25. internal readonly ChannelHandler channelHandler;
  26. internal readonly object[] Correlation;
  27. internal readonly ServiceHostBase Host;
  28. internal readonly OperationContext OperationContext;
  29. internal ServiceModelActivity Activity;
  30. internal Guid ResponseActivityId;
  31. internal IAsyncResult AsyncResult;
  32. internal bool CanSendReply;
  33. internal bool SuccessfullySendReply;
  34. internal CorrelationCallbackMessageProperty CorrelationCallback;
  35. internal object[] InputParameters;
  36. internal object[] OutputParameters;
  37. internal object ReturnParameter;
  38. internal bool ParametersDisposed;
  39. internal bool DidDeserializeRequestBody;
  40. internal TransactionMessageProperty TransactionMessageProperty;
  41. internal TransactedBatchContext TransactedBatchContext;
  42. internal Exception Error;
  43. internal MessageRpcProcessor ErrorProcessor;
  44. internal ErrorHandlerFaultInfo FaultInfo;
  45. internal bool HasSecurityContext;
  46. internal object Instance;
  47. internal bool MessageRpcOwnsInstanceContextThrottle;
  48. internal MessageRpcProcessor NextProcessor;
  49. internal Collection<MessageHeaderInfo> NotUnderstoodHeaders;
  50. internal DispatchOperationRuntime Operation;
  51. internal Message Request;
  52. internal RequestContext RequestContext;
  53. internal bool RequestContextThrewOnReply;
  54. internal UniqueId RequestID;
  55. internal Message Reply;
  56. internal TimeoutHelper ReplyTimeoutHelper;
  57. internal RequestReplyCorrelator.ReplyToInfo ReplyToInfo;
  58. internal MessageVersion RequestVersion;
  59. internal ServiceSecurityContext SecurityContext;
  60. internal InstanceContext InstanceContext;
  61. internal bool SuccessfullyBoundInstance;
  62. internal bool SuccessfullyIncrementedActivity;
  63. internal bool SuccessfullyLockedInstance;
  64. internal ReceiveContextRPCFacet ReceiveContext;
  65. internal TransactionRpcFacet transaction;
  66. internal IAspNetMessageProperty HostingProperty;
  67. internal MessageRpcInvokeNotification InvokeNotification;
  68. internal EventTraceActivity EventTraceActivity;
  69. static AsyncCallback handleEndComplete = Fx.ThunkCallback(new AsyncCallback(HandleEndComplete));
  70. static AsyncCallback handleEndAbandon = Fx.ThunkCallback(new AsyncCallback(HandleEndAbandon));
  71. bool paused;
  72. bool switchedThreads;
  73. bool isInstanceContextSingleton;
  74. SignalGate<IAsyncResult> invokeContinueGate;
  75. internal MessageRpc(RequestContext requestContext, Message request, DispatchOperationRuntime operation,
  76. ServiceChannel channel, ServiceHostBase host, ChannelHandler channelHandler, bool cleanThread,
  77. OperationContext operationContext, InstanceContext instanceContext, EventTraceActivity eventTraceActivity)
  78. {
  79. Fx.Assert((operationContext != null), "System.ServiceModel.Dispatcher.MessageRpc.MessageRpc(), operationContext == null");
  80. Fx.Assert(channelHandler != null, "System.ServiceModel.Dispatcher.MessageRpc.MessageRpc(), channelHandler == null");
  81. this.Activity = null;
  82. this.EventTraceActivity = eventTraceActivity;
  83. this.AsyncResult = null;
  84. this.CanSendReply = true;
  85. this.Channel = channel;
  86. this.channelHandler = channelHandler;
  87. this.Correlation = EmptyArray.Allocate(operation.Parent.CorrelationCount);
  88. this.CorrelationCallback = null;
  89. this.DidDeserializeRequestBody = false;
  90. this.TransactionMessageProperty = null;
  91. this.TransactedBatchContext = null;
  92. this.Error = null;
  93. this.ErrorProcessor = null;
  94. this.FaultInfo = new ErrorHandlerFaultInfo(request.Version.Addressing.DefaultFaultAction);
  95. this.HasSecurityContext = false;
  96. this.Host = host;
  97. this.Instance = null;
  98. this.MessageRpcOwnsInstanceContextThrottle = false;
  99. this.NextProcessor = null;
  100. this.NotUnderstoodHeaders = null;
  101. this.Operation = operation;
  102. this.OperationContext = operationContext;
  103. this.paused = false;
  104. this.ParametersDisposed = false;
  105. this.ReceiveContext = null;
  106. this.Request = request;
  107. this.RequestContext = requestContext;
  108. this.RequestContextThrewOnReply = false;
  109. this.SuccessfullySendReply = false;
  110. this.RequestVersion = request.Version;
  111. this.Reply = null;
  112. this.ReplyTimeoutHelper = new TimeoutHelper();
  113. this.SecurityContext = null;
  114. this.InstanceContext = instanceContext;
  115. this.SuccessfullyBoundInstance = false;
  116. this.SuccessfullyIncrementedActivity = false;
  117. this.SuccessfullyLockedInstance = false;
  118. this.switchedThreads = !cleanThread;
  119. this.transaction = null;
  120. this.InputParameters = null;
  121. this.OutputParameters = null;
  122. this.ReturnParameter = null;
  123. this.isInstanceContextSingleton = InstanceContextProviderBase.IsProviderSingleton(this.Channel.DispatchRuntime.InstanceContextProvider);
  124. this.invokeContinueGate = null;
  125. if (!operation.IsOneWay && !operation.Parent.ManualAddressing)
  126. {
  127. this.RequestID = request.Headers.MessageId;
  128. this.ReplyToInfo = new RequestReplyCorrelator.ReplyToInfo(request);
  129. }
  130. else
  131. {
  132. this.RequestID = null;
  133. this.ReplyToInfo = new RequestReplyCorrelator.ReplyToInfo();
  134. }
  135. this.HostingProperty = AspNetEnvironment.Current.GetHostingProperty(request, true);
  136. if (DiagnosticUtility.ShouldUseActivity)
  137. {
  138. this.Activity = TraceUtility.ExtractActivity(this.Request);
  139. }
  140. if (DiagnosticUtility.ShouldUseActivity || TraceUtility.ShouldPropagateActivity)
  141. {
  142. this.ResponseActivityId = ActivityIdHeader.ExtractActivityId(this.Request);
  143. }
  144. else
  145. {
  146. this.ResponseActivityId = Guid.Empty;
  147. }
  148. this.InvokeNotification = new MessageRpcInvokeNotification(this.Activity, this.channelHandler);
  149. if (this.EventTraceActivity == null && FxTrace.Trace.IsEnd2EndActivityTracingEnabled)
  150. {
  151. if (this.Request != null)
  152. {
  153. this.EventTraceActivity = EventTraceActivityHelper.TryExtractActivity(this.Request, true);
  154. }
  155. }
  156. }
  157. internal bool FinalizeCorrelationImplicitly
  158. {
  159. get { return this.CorrelationCallback != null && this.CorrelationCallback.IsFullyDefined; }
  160. }
  161. internal bool IsPaused
  162. {
  163. get { return this.paused; }
  164. }
  165. internal bool SwitchedThreads
  166. {
  167. get { return this.switchedThreads; }
  168. }
  169. internal bool IsInstanceContextSingleton
  170. {
  171. set
  172. {
  173. this.isInstanceContextSingleton = value;
  174. }
  175. }
  176. internal TransactionRpcFacet Transaction
  177. {
  178. get
  179. {
  180. if (this.transaction == null)
  181. {
  182. this.transaction = new TransactionRpcFacet(ref this);
  183. }
  184. return this.transaction;
  185. }
  186. }
  187. internal void Abort()
  188. {
  189. this.AbortRequestContext();
  190. this.AbortChannel();
  191. this.AbortInstanceContext();
  192. }
  193. void AbortRequestContext(RequestContext requestContext)
  194. {
  195. try
  196. {
  197. requestContext.Abort();
  198. ReceiveContextRPCFacet receiveContext = this.ReceiveContext;
  199. if (receiveContext != null)
  200. {
  201. this.ReceiveContext = null;
  202. IAsyncResult result = receiveContext.BeginAbandon(
  203. TimeSpan.MaxValue,
  204. handleEndAbandon,
  205. new CallbackState
  206. {
  207. ReceiveContext = receiveContext,
  208. ChannelHandler = this.channelHandler
  209. });
  210. if (result.CompletedSynchronously)
  211. {
  212. receiveContext.EndAbandon(result);
  213. }
  214. }
  215. }
  216. catch (Exception e)
  217. {
  218. if (Fx.IsFatal(e))
  219. {
  220. throw;
  221. }
  222. this.channelHandler.HandleError(e);
  223. }
  224. }
  225. internal void AbortRequestContext()
  226. {
  227. if (this.OperationContext.RequestContext != null)
  228. {
  229. this.AbortRequestContext(this.OperationContext.RequestContext);
  230. }
  231. if ((this.RequestContext != null) && (this.RequestContext != this.OperationContext.RequestContext))
  232. {
  233. this.AbortRequestContext(this.RequestContext);
  234. }
  235. TraceCallDurationInDispatcherIfNecessary(false);
  236. }
  237. void TraceCallDurationInDispatcherIfNecessary(bool requestContextWasClosedSuccessfully)
  238. {
  239. // only need to trace once (either for the failure or success case)
  240. if (TD.DispatchFailedIsEnabled())
  241. {
  242. if (requestContextWasClosedSuccessfully)
  243. {
  244. TD.DispatchSuccessful(this.EventTraceActivity, this.Operation.Name);
  245. }
  246. else
  247. {
  248. TD.DispatchFailed(this.EventTraceActivity, this.Operation.Name);
  249. }
  250. }
  251. }
  252. internal void CloseRequestContext()
  253. {
  254. if (this.OperationContext.RequestContext != null)
  255. {
  256. this.DisposeRequestContext(this.OperationContext.RequestContext);
  257. }
  258. if ((this.RequestContext != null) && (this.RequestContext != this.OperationContext.RequestContext))
  259. {
  260. this.DisposeRequestContext(this.RequestContext);
  261. }
  262. TraceCallDurationInDispatcherIfNecessary(true);
  263. }
  264. void DisposeRequestContext(RequestContext context)
  265. {
  266. try
  267. {
  268. context.Close();
  269. ReceiveContextRPCFacet receiveContext = this.ReceiveContext;
  270. if (receiveContext != null)
  271. {
  272. this.ReceiveContext = null;
  273. IAsyncResult result = receiveContext.BeginComplete(
  274. TimeSpan.MaxValue,
  275. null,
  276. this.channelHandler,
  277. handleEndComplete,
  278. new CallbackState
  279. {
  280. ChannelHandler = this.channelHandler,
  281. ReceiveContext = receiveContext
  282. });
  283. if (result.CompletedSynchronously)
  284. {
  285. receiveContext.EndComplete(result);
  286. }
  287. }
  288. }
  289. catch (Exception e)
  290. {
  291. if (Fx.IsFatal(e))
  292. {
  293. throw;
  294. }
  295. this.AbortRequestContext(context);
  296. this.channelHandler.HandleError(e);
  297. }
  298. }
  299. static void HandleEndAbandon(IAsyncResult result)
  300. {
  301. if (result.CompletedSynchronously)
  302. {
  303. return;
  304. }
  305. CallbackState callbackState = (CallbackState)result.AsyncState;
  306. try
  307. {
  308. callbackState.ReceiveContext.EndAbandon(result);
  309. }
  310. catch (Exception e)
  311. {
  312. if (Fx.IsFatal(e))
  313. {
  314. throw;
  315. }
  316. callbackState.ChannelHandler.HandleError(e);
  317. }
  318. }
  319. static void HandleEndComplete(IAsyncResult result)
  320. {
  321. if (result.CompletedSynchronously)
  322. {
  323. return;
  324. }
  325. CallbackState callbackState = (CallbackState)result.AsyncState;
  326. try
  327. {
  328. callbackState.ReceiveContext.EndComplete(result);
  329. }
  330. catch (Exception e)
  331. {
  332. if (Fx.IsFatal(e))
  333. {
  334. throw;
  335. }
  336. callbackState.ChannelHandler.HandleError(e);
  337. }
  338. }
  339. internal void AbortChannel()
  340. {
  341. if ((this.Channel != null) && this.Channel.HasSession)
  342. {
  343. try
  344. {
  345. this.Channel.Abort();
  346. }
  347. catch (Exception e)
  348. {
  349. if (Fx.IsFatal(e))
  350. {
  351. throw;
  352. }
  353. this.channelHandler.HandleError(e);
  354. }
  355. }
  356. }
  357. internal void CloseChannel()
  358. {
  359. if ((this.Channel != null) && this.Channel.HasSession)
  360. {
  361. try
  362. {
  363. this.Channel.Close(ChannelHandler.CloseAfterFaultTimeout);
  364. }
  365. catch (Exception e)
  366. {
  367. if (Fx.IsFatal(e))
  368. {
  369. throw;
  370. }
  371. this.channelHandler.HandleError(e);
  372. }
  373. }
  374. }
  375. internal void AbortInstanceContext()
  376. {
  377. if (this.InstanceContext != null && !this.isInstanceContextSingleton)
  378. {
  379. try
  380. {
  381. this.InstanceContext.Abort();
  382. }
  383. catch (Exception e)
  384. {
  385. if (Fx.IsFatal(e))
  386. {
  387. throw;
  388. }
  389. this.channelHandler.HandleError(e);
  390. }
  391. }
  392. }
  393. internal void EnsureReceive()
  394. {
  395. using (ServiceModelActivity.BoundOperation(this.Activity))
  396. {
  397. ChannelHandler.Register(this.channelHandler);
  398. }
  399. }
  400. bool ProcessError(Exception e)
  401. {
  402. MessageRpcProcessor handler = this.ErrorProcessor;
  403. try
  404. {
  405. Type exceptionType = e.GetType();
  406. if (exceptionType.IsAssignableFrom(typeof(FaultException)))
  407. {
  408. DiagnosticUtility.TraceHandledException(e, TraceEventType.Information);
  409. }
  410. else
  411. {
  412. DiagnosticUtility.TraceHandledException(e, TraceEventType.Error);
  413. }
  414. if (TraceUtility.MessageFlowTracingOnly)
  415. {
  416. TraceUtility.SetActivityId(this.Request.Properties);
  417. if (Guid.Empty == DiagnosticTraceBase.ActivityId)
  418. {
  419. Guid receivedActivityId = TraceUtility.ExtractActivityId(this.Request);
  420. if (Guid.Empty != receivedActivityId)
  421. {
  422. DiagnosticTraceBase.ActivityId = receivedActivityId;
  423. }
  424. }
  425. }
  426. this.Error = e;
  427. if (this.ErrorProcessor != null)
  428. {
  429. this.ErrorProcessor(ref this);
  430. }
  431. return (this.Error == null);
  432. }
  433. #pragma warning suppress 56500 // covered by FxCOP
  434. catch (Exception e2)
  435. {
  436. if (Fx.IsFatal(e2))
  437. {
  438. throw;
  439. }
  440. return ((handler != this.ErrorProcessor) && this.ProcessError(e2));
  441. }
  442. }
  443. internal void DisposeParameters(bool excludeInput)
  444. {
  445. if (this.Operation.DisposeParameters)
  446. {
  447. this.DisposeParametersCore(excludeInput);
  448. }
  449. }
  450. internal void DisposeParametersCore(bool excludeInput)
  451. {
  452. if (!this.ParametersDisposed)
  453. {
  454. if (!excludeInput)
  455. {
  456. this.DisposeParameterList(this.InputParameters);
  457. }
  458. this.DisposeParameterList(this.OutputParameters);
  459. IDisposable disposableParameter = this.ReturnParameter as IDisposable;
  460. if (disposableParameter != null)
  461. {
  462. try
  463. {
  464. disposableParameter.Dispose();
  465. }
  466. catch (Exception e)
  467. {
  468. if (Fx.IsFatal(e))
  469. {
  470. throw;
  471. }
  472. this.channelHandler.HandleError(e);
  473. }
  474. }
  475. this.ParametersDisposed = true;
  476. }
  477. }
  478. void DisposeParameterList(object[] parameters)
  479. {
  480. IDisposable disposableParameter = null;
  481. if (parameters != null)
  482. {
  483. foreach (Object obj in parameters)
  484. {
  485. disposableParameter = obj as IDisposable;
  486. if (disposableParameter != null)
  487. {
  488. try
  489. {
  490. disposableParameter.Dispose();
  491. }
  492. catch (Exception e)
  493. {
  494. if (Fx.IsFatal(e))
  495. {
  496. throw;
  497. }
  498. this.channelHandler.HandleError(e);
  499. }
  500. }
  501. }
  502. }
  503. }
  504. // See notes on UnPause and Resume (mutually exclusive)
  505. // Pausing will Increment the BusyCount for the hosting environment
  506. internal IResumeMessageRpc Pause()
  507. {
  508. Wrapper wrapper = new Wrapper(ref this);
  509. this.paused = true;
  510. return wrapper;
  511. }
  512. [Fx.Tag.SecurityNote(Critical = "Calls SecurityCritical method ApplyHostingIntegrationContextNoInline. Caller must ensure that"
  513. + "function is called appropriately and result is guarded and Dispose()'d correctly.")]
  514. [SecurityCritical]
  515. IDisposable ApplyHostingIntegrationContext()
  516. {
  517. if (this.HostingProperty != null)
  518. {
  519. return this.ApplyHostingIntegrationContextNoInline();
  520. }
  521. else
  522. {
  523. return null;
  524. }
  525. }
  526. [Fx.Tag.SecurityNote(Critical = "Calls SecurityCritical method HostingMessageProperty.ApplyIntegrationContext. Caller must ensure that"
  527. + "function is called appropriately and result is guarded and Dispose()'d correctly.")]
  528. [SecurityCritical]
  529. [MethodImpl(MethodImplOptions.NoInlining)]
  530. IDisposable ApplyHostingIntegrationContextNoInline()
  531. {
  532. return this.HostingProperty.ApplyIntegrationContext();
  533. }
  534. [Fx.Tag.SecurityNote(Critical = "Calls SecurityCritical method ApplyHostingIntegrationContext.",
  535. Safe = "Does call properly and calls Dispose, doesn't leak control of the IDisposable out of the function.")]
  536. [SecuritySafeCritical]
  537. internal bool Process(bool isOperationContextSet)
  538. {
  539. using (ServiceModelActivity.BoundOperation(this.Activity))
  540. {
  541. bool completed = true;
  542. if (this.NextProcessor != null)
  543. {
  544. MessageRpcProcessor processor = this.NextProcessor;
  545. this.NextProcessor = null;
  546. OperationContext originalContext;
  547. OperationContext.Holder contextHolder;
  548. if (!isOperationContextSet)
  549. {
  550. contextHolder = OperationContext.CurrentHolder;
  551. originalContext = contextHolder.Context;
  552. }
  553. else
  554. {
  555. contextHolder = null;
  556. originalContext = null;
  557. }
  558. IncrementBusyCount();
  559. IDisposable hostedIntegrationContext = this.ApplyHostingIntegrationContext();
  560. try
  561. {
  562. if (!isOperationContextSet)
  563. {
  564. contextHolder.Context = this.OperationContext;
  565. }
  566. processor(ref this);
  567. if (!this.paused)
  568. {
  569. this.OperationContext.SetClientReply(null, false);
  570. }
  571. }
  572. #pragma warning suppress 56500 // covered by FxCOP
  573. catch (Exception e)
  574. {
  575. if (Fx.IsFatal(e))
  576. {
  577. throw;
  578. }
  579. if (!this.ProcessError(e) && this.FaultInfo.Fault == null)
  580. {
  581. this.Abort();
  582. }
  583. }
  584. finally
  585. {
  586. try
  587. {
  588. DecrementBusyCount();
  589. if (hostedIntegrationContext != null)
  590. {
  591. hostedIntegrationContext.Dispose();
  592. }
  593. if (!isOperationContextSet)
  594. {
  595. contextHolder.Context = originalContext;
  596. }
  597. completed = !this.paused;
  598. if (completed)
  599. {
  600. this.channelHandler.DispatchDone();
  601. this.OperationContext.ClearClientReplyNoThrow();
  602. }
  603. }
  604. #pragma warning suppress 56500 // covered by FxCOP
  605. catch (Exception e)
  606. {
  607. if (Fx.IsFatal(e))
  608. {
  609. throw;
  610. }
  611. throw DiagnosticUtility.ExceptionUtility.ThrowHelperFatal(e.Message, e);
  612. }
  613. }
  614. }
  615. return completed;
  616. }
  617. }
  618. // UnPause is called on the original MessageRpc to continue work on the current thread, and the copy is ignored.
  619. // Since the copy is ignored, Decrement the BusyCount
  620. internal void UnPause()
  621. {
  622. this.paused = false;
  623. DecrementBusyCount();
  624. }
  625. internal bool UnlockInvokeContinueGate(out IAsyncResult result)
  626. {
  627. return this.invokeContinueGate.Unlock(out result);
  628. }
  629. internal void PrepareInvokeContinueGate()
  630. {
  631. this.invokeContinueGate = new SignalGate<IAsyncResult>();
  632. }
  633. void IncrementBusyCount()
  634. {
  635. // Only increment the counter on the service side.
  636. if (this.Host != null)
  637. {
  638. this.Host.IncrementBusyCount();
  639. if (AspNetEnvironment.Current.TraceIncrementBusyCountIsEnabled())
  640. {
  641. AspNetEnvironment.Current.TraceIncrementBusyCount(SR.GetString(SR.ServiceBusyCountTrace, this.Operation.Action));
  642. }
  643. }
  644. }
  645. void DecrementBusyCount()
  646. {
  647. if (this.Host != null)
  648. {
  649. this.Host.DecrementBusyCount();
  650. if (AspNetEnvironment.Current.TraceDecrementBusyCountIsEnabled())
  651. {
  652. AspNetEnvironment.Current.TraceDecrementBusyCount(SR.GetString(SR.ServiceBusyCountTrace, this.Operation.Action));
  653. }
  654. }
  655. }
  656. class CallbackState
  657. {
  658. public ReceiveContextRPCFacet ReceiveContext
  659. {
  660. get;
  661. set;
  662. }
  663. public ChannelHandler ChannelHandler
  664. {
  665. get;
  666. set;
  667. }
  668. }
  669. class Wrapper : IResumeMessageRpc
  670. {
  671. MessageRpc rpc;
  672. bool alreadyResumed;
  673. internal Wrapper(ref MessageRpc rpc)
  674. {
  675. this.rpc = rpc;
  676. if (rpc.NextProcessor == null)
  677. {
  678. Fx.Assert("MessageRpc.Wrapper.Wrapper: (rpc.NextProcessor != null)");
  679. }
  680. this.rpc.IncrementBusyCount();
  681. }
  682. public InstanceContext GetMessageInstanceContext()
  683. {
  684. return this.rpc.InstanceContext;
  685. }
  686. // Resume is called on the copy on some completing thread, whereupon work continues on that thread.
  687. // BusyCount is Decremented as the copy is now complete
  688. public void Resume(out bool alreadyResumedNoLock)
  689. {
  690. try
  691. {
  692. alreadyResumedNoLock = this.alreadyResumed;
  693. this.alreadyResumed = true;
  694. this.rpc.switchedThreads = true;
  695. if (this.rpc.Process(false) && !rpc.InvokeNotification.DidInvokerEnsurePump)
  696. {
  697. this.rpc.EnsureReceive();
  698. }
  699. }
  700. finally
  701. {
  702. this.rpc.DecrementBusyCount();
  703. }
  704. }
  705. public void Resume(IAsyncResult result)
  706. {
  707. this.rpc.AsyncResult = result;
  708. this.Resume();
  709. }
  710. public void Resume(object instance)
  711. {
  712. this.rpc.Instance = instance;
  713. this.Resume();
  714. }
  715. public void Resume()
  716. {
  717. using (ServiceModelActivity.BoundOperation(this.rpc.Activity, true))
  718. {
  719. bool alreadyResumedNoLock;
  720. this.Resume(out alreadyResumedNoLock);
  721. if (alreadyResumedNoLock)
  722. {
  723. string text = SR.GetString(SR.SFxMultipleCallbackFromAsyncOperation, rpc.Operation.Name);
  724. Exception error = new InvalidOperationException(text);
  725. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(error);
  726. }
  727. }
  728. }
  729. public void SignalConditionalResume(IAsyncResult result)
  730. {
  731. if (this.rpc.invokeContinueGate.Signal(result))
  732. {
  733. this.rpc.AsyncResult = result;
  734. Resume();
  735. }
  736. }
  737. }
  738. }
  739. class MessageRpcInvokeNotification : IInvokeReceivedNotification
  740. {
  741. ServiceModelActivity activity;
  742. ChannelHandler handler;
  743. public MessageRpcInvokeNotification(ServiceModelActivity activity, ChannelHandler handler)
  744. {
  745. this.activity = activity;
  746. this.handler = handler;
  747. }
  748. public bool DidInvokerEnsurePump { get; set; }
  749. public void NotifyInvokeReceived()
  750. {
  751. using (ServiceModelActivity.BoundOperation(this.activity))
  752. {
  753. ChannelHandler.Register(this.handler);
  754. }
  755. this.DidInvokerEnsurePump = true;
  756. }
  757. public void NotifyInvokeReceived(RequestContext request)
  758. {
  759. using (ServiceModelActivity.BoundOperation(this.activity))
  760. {
  761. ChannelHandler.Register(this.handler, request);
  762. }
  763. this.DidInvokerEnsurePump = true;
  764. }
  765. }
  766. }