public ProcessRequestAsyncResult(RoutingService service, Message message, AsyncCallback callback, object state) : base(callback, state) { this.allCompletedSync = true; this.service = service; this.messageRpc = new MessageRpc(message, OperationContext.Current, service.ChannelExtension.ImpersonationRequired); if (TD.RoutingServiceProcessingMessageIsEnabled()) { TD.RoutingServiceProcessingMessage(this.messageRpc.EventTraceActivity, this.messageRpc.UniqueID, message.Headers.Action, this.messageRpc.OperationContext.EndpointDispatcher.EndpointAddress.Uri.ToString(), messageRpc.Transaction != null ? "True" : "False"); } try { EndpointNameMessageFilter.Set(this.messageRpc.Message.Properties, service.ChannelExtension.EndpointName); this.messageRpc.RouteToSingleEndpoint <TContract>(this.service.RoutingConfig); } catch (MultipleFilterMatchesException matchesException) { // Wrap this exception with one that is more meaningful to users of RoutingService: throw FxTrace.Exception.AsError(new ConfigurationErrorsException(SR.ReqReplyMulticastNotSupported(this.messageRpc.OperationContext.Channel.LocalAddress), matchesException)); } while (this.StartProcessing()) { } }
public CallState(MessageRpc messageRpc) { this.nullContextScope = new OperationContextScope((OperationContext)null); if (messageRpc.windowsIdentity != null) { this.impersonation = messageRpc.windowsIdentity.Impersonate(); } }
bool CompleteReceiveContextCompleted(IAsyncResult result) { MessageRpc messageRpc = this.service.SessionMessages[this.sessionMessageIndex]; messageRpc.ReceiveContext.EndComplete(result); if (++this.sessionMessageIndex >= this.service.SessionMessages.Count) { return(this.DoneCompletingReceiveContexts()); } return(true); }
void ClientOperationComplete(IAsyncResult result) { MessageRpc messageRpc = this.service.SessionMessages[this.sessionMessageIndex]; SendOperation currentDest = messageRpc.Operations[this.destinationIndex]; this.client.EndOperation(result); currentDest.TransmitSucceeded(this.service.GetTransactionForSending(messageRpc)); if (TD.RoutingServiceTransmitSucceededIsEnabled()) { TD.RoutingServiceTransmitSucceeded(messageRpc.EventTraceActivity, messageRpc.UniqueID, this.destinationIndex.ToString(TD.Culture), currentDest.CurrentEndpoint.ToString()); } MoveToNextClientOperation(messageRpc.Operations.Count); }
internal Transaction GetTransactionForSending(MessageRpc messageRpc) { if (messageRpc != null && messageRpc.Transaction != null) { return(messageRpc.Transaction); } if (this.ReceiveTransaction != null) { //This is the transaction used for the receive, we cannot perform error handling since we //didn't create it. return(this.ReceiveTransaction); } else { //This could be null, indicating non-transactional behavior return(this.RetryTransaction); } }
bool CompleteCurrentReceiveContext() { if (this.service.SessionException != null) { //This means at least one multicast branch did not reach any of the configured endpoints this.Fault(this.service.SessionException); return(false); } bool keepGoing; MessageRpc messageRpc = this.service.SessionMessages[this.sessionMessageIndex]; if (messageRpc.ReceiveContext != null) { if (TD.RoutingServiceCompletingReceiveContextIsEnabled()) { TD.RoutingServiceCompletingReceiveContext(messageRpc.EventTraceActivity, messageRpc.UniqueID); } IAsyncResult result; using (this.PrepareTransactionalCall(this.service.GetTransactionForSending(messageRpc))) { result = messageRpc.ReceiveContext.BeginComplete(this.timeoutHelper.RemainingTime(), this.PrepareAsyncCompletion(completeReceiveContextCallback), this); } if (this.CheckSyncContinue(result)) { keepGoing = this.CompleteReceiveContextCompleted(result); } else { keepGoing = false; } } else { // Either all messages have RC or all messages don't have RC. Since we don't have one // we know that none of these messages will, so we don't have to look at the other messages Fx.Assert("We shouldn't enter CompletingReceiveContexts state if the binding is not ReceiveContext capable"); keepGoing = this.DoneCompletingReceiveContexts(); } return(keepGoing); }
public ProcessMessagesAsyncResult(Message message, RoutingService service, TimeSpan timeout, AsyncCallback callback, object state) : base(callback, state) { this.service = service; this.channelExtension = service.ChannelExtension; this.timeoutHelper = new TimeoutHelper(timeout); this.timeoutHelper.RemainingTime(); //Start the timer if (message == null) { //Null message means end of session, time to close everything this.closeOutboundChannels = true; this.state = ProcessingState.ClosingChannels; } else { this.closeOutboundChannels = false; MessageRpc messageRpc = new MessageRpc(message, OperationContext.Current, this.channelExtension.ImpersonationRequired); if (TD.RoutingServiceProcessingMessageIsEnabled()) { TD.RoutingServiceProcessingMessage(messageRpc.EventTraceActivity, messageRpc.UniqueID, messageRpc.Message.Headers.Action, messageRpc.OperationContext.EndpointDispatcher.EndpointAddress.Uri.ToString(), (messageRpc.Transaction != null).ToString()); } EndpointNameMessageFilter.Set(messageRpc.Message.Properties, this.channelExtension.EndpointName); messageRpc.RouteToEndpoints <TContract>(this.service.RoutingConfig); this.service.SessionMessages.Add(messageRpc); this.sessionMessageIndex = this.service.SessionMessages.Count - 1; if (this.sessionMessageIndex == 0) { //First message, do initialization stuff this.state = ProcessingState.Initial; } else { this.state = ProcessingState.SendingSessionMessages; } } this.ProcessWhileSync(); }
internal void CreateNewTransactionIfNeeded(MessageRpc messageRpc) { if (messageRpc.Transaction != null && this.ChannelExtension.TransactedReceiveEnabled) { if (TD.RoutingServiceUsingExistingTransactionIsEnabled()) { TD.RoutingServiceUsingExistingTransaction(messageRpc.EventTraceActivity, messageRpc.Transaction.TransactionInformation.LocalIdentifier); } Fx.Assert(this.ReceiveTransaction == null, "Should only happen at the start of a session."); this.ReceiveTransaction = messageRpc.Transaction; return; } else if (!this.ChannelExtension.TransactedReceiveEnabled || !this.ChannelExtension.ReceiveContextEnabled) { return; } Fx.Assert(this.RetryTransaction == null, "Logic error, we shouldn't be calling CreateNewTransactionIfNeeded if we have a RC Transaction"); ChannelDispatcher channelDispatcher = this.operationContext.EndpointDispatcher.ChannelDispatcher; TimeSpan timeout = channelDispatcher.TransactionTimeout; IsolationLevel isolation = channelDispatcher.TransactionIsolationLevel; TransactionOptions options = new TransactionOptions(); if (timeout > TimeSpan.Zero) { options.Timeout = timeout; } if (isolation != IsolationLevel.Unspecified) { options.IsolationLevel = isolation; } this.RetryTransaction = new CommittableTransaction(options); if (TD.RoutingServiceCreatingTransactionIsEnabled()) { TD.RoutingServiceCreatingTransaction(messageRpc.EventTraceActivity, this.RetryTransaction.TransactionInformation.LocalIdentifier); } }
bool HandleClientOperationFailure(Exception e) { if (TD.RoutingServiceTransmitFailedIsEnabled()) { TD.RoutingServiceTransmitFailed(null, this.client.Key.ToString(), e); } if (!(e is CommunicationException || e is TimeoutException)) { //We only move to backup for CommunicationExceptions and TimeoutExceptions return(false); } bool canHandle; MessageRpc messageRpc = this.service.SessionMessages[this.sessionMessageIndex]; SendOperation sendOperation = messageRpc.Operations[this.destinationIndex]; if ((e is CommunicationObjectAbortedException || e is CommunicationObjectFaultedException) && !this.channelExtension.HasSession) { // Messages on a non sessionful channel share outbound connections and can // fail due to other messages failing on the same channel bool canRetry = (this.channelExtension.ReceiveContextEnabled || !this.channelExtension.TransactedReceiveEnabled); if (canRetry && !this.abortedRetry) { //No session and ReceiveContext or non transactional, retry the message 1 time (before moving to backup) this.abortedRetry = true; this.ResetState(); return(true); } } else if (e is EndpointNotFoundException) { // The channel may not fault for this exception for bindings other than netTcpBinding // We abort the channel in that case. We proactively clean up so that we don't have to cleanup later SessionChannels sessionChannels = this.service.GetSessionChannels(messageRpc.Impersonating); if (sessionChannels != null) { sessionChannels.AbortChannel(sendOperation.CurrentEndpoint); } } else if (e is MessageSecurityException) { // The service may have been stopped and restarted without the routing service knowledge. // When we try to use a cached channel to the service, the channel can fault due to this exception // The faulted channel gets cleaned up and we retry one more time only when service has backup // If there is no backup, we do not retry since we do not create a buffered message to prevent performance degradation if (!this.abortedRetry && (sendOperation.AlternateEndpointCount > 0)) { this.abortedRetry = true; this.ResetState(); return(true); } } if (sendOperation.TryMoveToAlternate(e)) { if (TD.RoutingServiceMovedToBackupIsEnabled()) { TD.RoutingServiceMovedToBackup(messageRpc.EventTraceActivity, messageRpc.UniqueID, this.destinationIndex.ToString(TD.Culture), sendOperation.CurrentEndpoint.ToString()); } this.ResetState(); canHandle = true; } else if (this.service.GetTransactionForSending(messageRpc) == null) { // This is OneWay with no Transaction... // store this exception for when we complete, but continue any multicasting this.service.SessionException = e; // Mark the SendOperation as 'Sent' because there's no more work we can do (non-tx and no more backups) sendOperation.TransmitSucceeded(null); if (this.channelExtension.HasSession) { this.channelExtension.SessionChannels.AbortChannel(this.client.Key); } this.MoveToNextClientOperation(messageRpc.Operations.Count); canHandle = true; } else { canHandle = false; } return(canHandle); }
bool SendToCurrentClient() { MessageRpc messageRpc = this.service.SessionMessages[this.sessionMessageIndex]; SendOperation sendOperation = messageRpc.Operations[this.destinationIndex]; if (sendOperation.Sent) { this.MoveToNextClientOperation(messageRpc.Operations.Count); return(true); } else if (!this.channelExtension.ReceiveContextEnabled && this.channelExtension.TransactedReceiveEnabled && sendOperation.HasAlternate) { // We can't do error handling for oneway Transactional unless there's RC. throw FxTrace.Exception.AsError(new ConfigurationErrorsException(SR.ErrorHandlingNotSupportedTxNoRC(messageRpc.OperationContext.Channel.LocalAddress))); } RoutingEndpointTrait endpointTrait = sendOperation.CurrentEndpoint; this.client = this.service.GetOrCreateClient <TContract>(endpointTrait, messageRpc.Impersonating); try { // We always work on cloned message when there are backup endpoints to handle exception cases Message message; if (messageRpc.Operations.Count == 1 && sendOperation.AlternateEndpointCount == 0) { message = messageRpc.Message; } else { message = messageRpc.CreateBuffer().CreateMessage(); } sendOperation.PrepareMessage(message); IAsyncResult result; if (TD.RoutingServiceTransmittingMessageIsEnabled()) { TD.RoutingServiceTransmittingMessage(messageRpc.EventTraceActivity, messageRpc.UniqueID, this.destinationIndex.ToString(TD.Culture), this.client.Key.ToString()); } Transaction transaction = this.service.GetTransactionForSending(messageRpc); using (this.PrepareTransactionalCall(transaction)) { IDisposable impersonationContext = null; try { //Perform the assignment in a finally block so it won't be interrupted asynchronously try { } finally { impersonationContext = messageRpc.PrepareCall(); } result = this.client.BeginOperation(message, transaction, this.PrepareAsyncCompletion(clientOperationCallback), this); } finally { if (impersonationContext != null) { impersonationContext.Dispose(); } } } if (this.CheckSyncContinue(result)) { this.ClientOperationComplete(result); return(true); } else { return(false); } } catch (Exception exception) { if (Fx.IsFatal(exception)) { throw; } //See if we can handle this Exception... if (this.HandleClientOperationFailure(exception)) { return(true); } throw; } }