// Logic for knowing when to close stuff: // // ASSUMPTIONS: // Closing a stream over a message also closes the message. // Closing a message over a stream does not close the stream. // (OperationStreamProvider.ReleaseStream is no-op) // // This is a table of what should be disposed in what cases. // The rows represent the type of parameter to the method and // whether we are disposing parameters or not. The columns // are for the inputs vs. the outputs. The cells contain the // values that need to be Disposed. M^P means that exactly // one of the message and parameter needs to be disposed, // since they refer to the same object. // // Request Reply // Message | M or P | M or P // Dispose Stream | P | M and P // Params | M and P | M and P // | | // Message | none | none // NoDispose Stream | none | M // Params | M | M // // By choosing to dispose the parameter in both of the "M or P" // cases, the logic needed to generate this table is: // // CloseRequestMessage = IsParams // CloseRequestParams = rpc.Operation.DisposeParameters // CloseReplyMessage = rpc.Operation.SerializeReply // CloseReplyParams = rpc.Operation.DisposeParameters // // IsParams can be calculated based on whether the request // message was consumed after deserializing but before calling // the user. This is stored as rpc.DidDeserializeRequestBody. // void ProcessMessageCleanup(ref MessageRpc rpc) { Fx.Assert( !object.ReferenceEquals(rpc.ErrorProcessor, this.processMessageCleanupError), "ProcessMessageCleanup run twice on the same MessageRpc!"); rpc.ErrorProcessor = this.processMessageCleanupError; bool replyWasSent = false; if (rpc.CanSendReply) { if (this.sendAsynchronously) { replyWasSent = this.EndReply(ref rpc); } else { replyWasSent = rpc.SuccessfullySendReply; } } try { try { if (rpc.DidDeserializeRequestBody) { rpc.Request.Close(); } } catch (Exception e) { if (Fx.IsFatal(e)) { throw; } this.error.HandleError(e); } if (rpc.HostingProperty != null) { try { rpc.HostingProperty.Close(); } catch (Exception e) { if (Fx.IsFatal(e)) { throw; } throw DiagnosticUtility.ExceptionUtility.ThrowHelperFatal(e.Message, e); } } // for wf, wf owns the lifetime of the request message. So in that case, we should not dispose the inputs IManualConcurrencyOperationInvoker manualInvoker = rpc.Operation.Invoker as IManualConcurrencyOperationInvoker; rpc.DisposeParameters(manualInvoker != null && manualInvoker.OwnsFormatter); //Dispose all input/output/return parameters if (rpc.FaultInfo.IsConsideredUnhandled) { if (!replyWasSent) { rpc.AbortRequestContext(); rpc.AbortChannel(); } else { rpc.CloseRequestContext(); rpc.CloseChannel(); } rpc.AbortInstanceContext(); } else { if (rpc.RequestContextThrewOnReply) { rpc.AbortRequestContext(); } else { rpc.CloseRequestContext(); } } if ((rpc.Reply != null) && (rpc.Reply != rpc.ReturnParameter)) { try { rpc.Reply.Close(); } catch (Exception e) { if (Fx.IsFatal(e)) { throw; } this.error.HandleError(e); } } if ((rpc.FaultInfo.Fault != null) && (rpc.FaultInfo.Fault.State != MessageState.Closed)) { // maybe ProvideFault gave a Message, but then BeforeSendReply replaced it // in that case, we need to close the one from ProvideFault try { rpc.FaultInfo.Fault.Close(); } catch (Exception e) { if (Fx.IsFatal(e)) { throw; } this.error.HandleError(e); } } try { rpc.OperationContext.FireOperationCompleted(); } #pragma warning suppress 56500 // covered by FxCOP catch (Exception e) { if (Fx.IsFatal(e)) { throw; } throw DiagnosticUtility.ExceptionUtility.ThrowHelperCallback(e); } this.instance.AfterReply(ref rpc, this.error); if (rpc.SuccessfullyLockedInstance) { try { this.concurrency.UnlockInstance(ref rpc); } catch (Exception e) { if (Fx.IsFatal(e)) { throw; } Fx.Assert("Exceptions should be caught by callee"); rpc.InstanceContext.FaultInternal(); this.error.HandleError(e); } } if (this.terminate != null) { try { this.terminate.AfterReply(ref rpc); } catch (Exception e) { if (Fx.IsFatal(e)) { throw; } this.error.HandleError(e); } } if (rpc.SuccessfullyIncrementedActivity) { try { rpc.Channel.DecrementActivity(); } catch (Exception e) { if (Fx.IsFatal(e)) { throw; } this.error.HandleError(e); } } } finally { if (rpc.MessageRpcOwnsInstanceContextThrottle && rpc.channelHandler.InstanceContextServiceThrottle != null) { rpc.channelHandler.InstanceContextServiceThrottle.DeactivateInstanceContext(); } if (rpc.Activity != null && DiagnosticUtility.ShouldUseActivity) { rpc.Activity.Stop(); } } this.error.HandleError(ref rpc); }
private void ProcessMessageCleanup(ref MessageRpc rpc) { Fx.Assert( !object.ReferenceEquals(rpc.ErrorProcessor, _processMessageCleanupError), "ProcessMessageCleanup run twice on the same MessageRpc!"); rpc.ErrorProcessor = _processMessageCleanupError; bool replyWasSent = false; if (rpc.CanSendReply) { if (_sendAsynchronously) { replyWasSent = this.EndReply(ref rpc); } else { replyWasSent = rpc.SuccessfullySendReply; } } try { try { if (rpc.DidDeserializeRequestBody) { rpc.Request.Close(); } } catch (Exception e) { if (Fx.IsFatal(e)) { throw; } _error.HandleError(e); } rpc.DisposeParameters(false); //Dispose all input/output/return parameters if (rpc.FaultInfo.IsConsideredUnhandled) { if (!replyWasSent) { rpc.AbortRequestContext(); rpc.AbortChannel(); } else { rpc.CloseRequestContext(); rpc.CloseChannel(); } rpc.AbortInstanceContext(); } else { if (rpc.RequestContextThrewOnReply) { rpc.AbortRequestContext(); } else { rpc.CloseRequestContext(); } } if ((rpc.Reply != null) && (rpc.Reply != rpc.ReturnParameter)) { try { rpc.Reply.Close(); } catch (Exception e) { if (Fx.IsFatal(e)) { throw; } _error.HandleError(e); } } if ((rpc.FaultInfo.Fault != null) && (rpc.FaultInfo.Fault.State != MessageState.Closed)) { // maybe ProvideFault gave a Message, but then BeforeSendReply replaced it // in that case, we need to close the one from ProvideFault try { rpc.FaultInfo.Fault.Close(); } catch (Exception e) { if (Fx.IsFatal(e)) { throw; } _error.HandleError(e); } } try { rpc.OperationContext.FireOperationCompleted(); } catch (Exception e) { if (Fx.IsFatal(e)) { throw; } throw DiagnosticUtility.ExceptionUtility.ThrowHelperCallback(e); } _instance.AfterReply(ref rpc, _error); if (rpc.SuccessfullyLockedInstance) { try { _concurrency.UnlockInstance(ref rpc); } catch (Exception e) { if (Fx.IsFatal(e)) { throw; } Fx.Assert("Exceptions should be caught by callee"); rpc.InstanceContext.FaultInternal(); _error.HandleError(e); } } if (rpc.SuccessfullyIncrementedActivity) { try { rpc.Channel.DecrementActivity(); } catch (Exception e) { if (Fx.IsFatal(e)) { throw; } _error.HandleError(e); } } } finally { if (rpc.Activity != null && DiagnosticUtility.ShouldUseActivity) { rpc.Activity.Stop(); } } _error.HandleError(ref rpc); }
private void ProcessMessageCleanup(ref MessageRpc rpc) { rpc.ErrorProcessor = this.processMessageCleanupError; bool successfullySendReply = false; if (rpc.CanSendReply) { if (this.sendAsynchronously) { successfullySendReply = this.EndReply(ref rpc); } else { successfullySendReply = rpc.SuccessfullySendReply; } } try { try { if (rpc.DidDeserializeRequestBody) { rpc.Request.Close(); } } catch (Exception exception) { if (Fx.IsFatal(exception)) { throw; } this.error.HandleError(exception); } if (rpc.HostingProperty != null) { try { rpc.HostingProperty.Close(); } catch (Exception exception2) { if (Fx.IsFatal(exception2)) { throw; } throw DiagnosticUtility.ExceptionUtility.ThrowHelperFatal(exception2.Message, exception2); } } IManualConcurrencyOperationInvoker invoker = rpc.Operation.Invoker as IManualConcurrencyOperationInvoker; rpc.DisposeParameters((invoker != null) && invoker.OwnsFormatter); if (rpc.FaultInfo.IsConsideredUnhandled) { if (!successfullySendReply) { rpc.AbortRequestContext(); rpc.AbortChannel(); } else { rpc.CloseRequestContext(); rpc.CloseChannel(); } rpc.AbortInstanceContext(); } else if (rpc.RequestContextThrewOnReply) { rpc.AbortRequestContext(); } else { rpc.CloseRequestContext(); } if ((rpc.Reply != null) && (rpc.Reply != rpc.ReturnParameter)) { try { rpc.Reply.Close(); } catch (Exception exception3) { if (Fx.IsFatal(exception3)) { throw; } this.error.HandleError(exception3); } } if ((rpc.FaultInfo.Fault != null) && (rpc.FaultInfo.Fault.State != MessageState.Closed)) { try { rpc.FaultInfo.Fault.Close(); } catch (Exception exception4) { if (Fx.IsFatal(exception4)) { throw; } this.error.HandleError(exception4); } } try { rpc.OperationContext.FireOperationCompleted(); } catch (Exception exception5) { if (Fx.IsFatal(exception5)) { throw; } throw DiagnosticUtility.ExceptionUtility.ThrowHelperCallback(exception5); } this.instance.AfterReply(ref rpc, this.error); if (rpc.SuccessfullyLockedInstance) { try { this.concurrency.UnlockInstance(ref rpc); } catch (Exception exception6) { if (Fx.IsFatal(exception6)) { throw; } rpc.InstanceContext.FaultInternal(); this.error.HandleError(exception6); } } if (this.terminate != null) { try { this.terminate.AfterReply(ref rpc); } catch (Exception exception7) { if (Fx.IsFatal(exception7)) { throw; } this.error.HandleError(exception7); } } if (rpc.SuccessfullyIncrementedActivity) { try { rpc.Channel.DecrementActivity(); } catch (Exception exception8) { if (Fx.IsFatal(exception8)) { throw; } this.error.HandleError(exception8); } } } finally { if (rpc.MessageRpcOwnsInstanceContextThrottle && (rpc.channelHandler.InstanceContextServiceThrottle != null)) { rpc.channelHandler.InstanceContextServiceThrottle.DeactivateInstanceContext(); } if ((rpc.Activity != null) && DiagnosticUtility.ShouldUseActivity) { rpc.Activity.Stop(); } } this.error.HandleError(ref rpc); }