private async Task DispatchAndReleasePumpAsync(RequestContext request, bool cleanThread, RequestInfo requestInfo) { OperationContext currentOperationContext = null; ServiceChannel channel = requestInfo.Channel; EndpointDispatcher endpoint = requestInfo.Endpoint; bool releasedPump = false; try { DispatchRuntime dispatchBehavior = requestInfo.DispatchRuntime; if (channel == null || dispatchBehavior == null) { Fx.Assert("System.ServiceModel.Dispatcher.ChannelHandler.Dispatch(): (channel == null || dispatchBehavior == null)"); return; } Message message; //EventTraceActivity eventTraceActivity = TraceDispatchMessageStart(request.RequestMessage); message = request.RequestMessage; DispatchOperationRuntime operation = dispatchBehavior.GetOperation(ref message); if (operation == null) { Fx.Assert("ChannelHandler.Dispatch (operation == null)"); throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(string.Format(CultureInfo.InvariantCulture, "No DispatchOperationRuntime found to process message."))); } if (_shouldRejectMessageWithOnOpenActionHeader && message.Headers.Action == OperationDescription.SessionOpenedAction) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.Format(SR.SFxNoEndpointMatchingAddressForConnectionOpeningMessage, message.Headers.Action, "Open"))); } //if (MessageLogger.LoggingEnabled) //{ // MessageLogger.LogMessage(ref message, (operation.IsOneWay ? MessageLoggingSource.ServiceLevelReceiveDatagram : MessageLoggingSource.ServiceLevelReceiveRequest) | MessageLoggingSource.LastChance); //} if (operation.IsTerminating && _hasSession) { _isChannelTerminated = true; } bool hasOperationContextBeenSet; if (currentOperationContext != null) { hasOperationContextBeenSet = true; currentOperationContext.ReInit(request, message, channel); } else { hasOperationContextBeenSet = false; currentOperationContext = new OperationContext(request, message, channel, _host); } if (currentOperationContext.EndpointDispatcher == null && _serviceDispatcher != null) { currentOperationContext.EndpointDispatcher = endpoint; } var rpc = new MessageRpc(request, message, operation, channel, _host, this, cleanThread, currentOperationContext, requestInfo.ExistingInstanceContext); //TraceUtility.MessageFlowAtMessageReceived(message, currentOperationContext, eventTraceActivity, true); // passing responsibility for call throttle to MessageRpc // (MessageRpc implicitly owns this throttle once it's created) requestInfo.ChannelHandlerOwnsCallThrottle = false; // explicitly passing responsibility for instance throttle to MessageRpc rpc.MessageRpcOwnsInstanceContextThrottle = requestInfo.ChannelHandlerOwnsInstanceContextThrottle; requestInfo.ChannelHandlerOwnsInstanceContextThrottle = false; // These need to happen before Dispatch but after accessing any ChannelHandler // state, because we go multi-threaded after this ReleasePump(); releasedPump = true; await operation.Parent.DispatchAsync(rpc, hasOperationContextBeenSet); } catch (Exception e) { if (Fx.IsFatal(e)) { throw; } await HandleErrorAsync(e, request, requestInfo, channel); } finally { if (!releasedPump) { ReleasePump(); } } }
// Similar to DispatchAndReleasePump on Desktop internal async Task DispatchAsyncCore(RequestContext request, RequestInfo requestInfo, bool cleanThread, OperationContext currentOperationContext) { ServiceChannel channel = requestInfo.Channel; EndpointDispatcher endpoint = requestInfo.Endpoint; try { DispatchRuntime dispatchBehavior = requestInfo.DispatchRuntime; if (channel == null || dispatchBehavior == null) { Fx.Assert("System.ServiceModel.Dispatcher.ChannelHandler.Dispatch(): (channel == null || dispatchBehavior == null)"); } Message message = request.RequestMessage; DispatchOperationRuntime operation = dispatchBehavior.GetOperation(ref message); if (operation == null) { Fx.Assert("ChannelHandler.Dispatch (operation == null)"); throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException("No DispatchOperationRuntime found to process message.")); } if (_shouldRejectMessageWithOnOpenActionHeader && message.Headers.Action == OperationDescription.SessionOpenedAction) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.Format(SR.SFxNoEndpointMatchingAddressForConnectionOpeningMessage, message.Headers.Action, "Open"))); } if (operation.IsTerminating && _hasSession) { _isChannelTerminated = true; } bool hasOperationContextBeenSet; if (currentOperationContext != null) { hasOperationContextBeenSet = true; currentOperationContext.ReInit(request, message, channel); } else { hasOperationContextBeenSet = false; currentOperationContext = new OperationContext(request, message, channel, null); } if (currentOperationContext.EndpointDispatcher == null && _serviceDispatcher != null) { currentOperationContext.EndpointDispatcher = endpoint; } MessageRpc rpc = new MessageRpc(request, message, operation, channel, _host, this, cleanThread, currentOperationContext, requestInfo.ExistingInstanceContext); // passing responsibility for call throttle to MessageRpc // (MessageRpc implicitly owns this throttle once it's created) requestInfo.ChannelHandlerOwnsCallThrottle = false; // explicitly passing responsibility for instance throttle to MessageRpc rpc.MessageRpcOwnsInstanceContextThrottle = requestInfo.ChannelHandlerOwnsInstanceContextThrottle; requestInfo.ChannelHandlerOwnsInstanceContextThrottle = false; // These need to happen before Dispatch but after accessing any ChannelHandler // state, because we go multi-threaded after this until we reacquire pump mutex. await operation.Parent.DispatchAsync(rpc, hasOperationContextBeenSet); } catch (Exception e) { if (Fx.IsFatal(e)) { throw; } await HandleErrorAsync(e, request, requestInfo, channel); } }