示例#1
0
        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);
        }
示例#2
0
        // A Sessionful channel failed when closing, find all messages that went on that
        // session/channel and move them to their backup endpoints
        bool HandleCloseFailure(Exception e)
        {
            if (!(e is CommunicationException || e is TimeoutException))
            {
                return(false);
            }

            if (TD.RoutingServiceCloseFailedIsEnabled())
            {
                TD.RoutingServiceCloseFailed(this.client.Key.ToString(), e);
            }
            this.channelExtension.SessionChannels.AbortChannel(this.client.Key);

            if (this.service.SessionMessages.Count == 0)
            {
                //All messages have been sent and we're non-transactional
                Fx.Assert(!this.service.ChannelExtension.TransactedReceiveEnabled, "Should only happen for non-transactional cases");
                return(true);
            }

            foreach (MessageRpc messageRpc in this.service.SessionMessages)
            {
                for (this.destinationIndex = 0; this.destinationIndex < messageRpc.Operations.Count; this.destinationIndex++)
                {
                    SendOperation sendOperation = messageRpc.Operations[this.destinationIndex];
                    if (client.Key.Equals(sendOperation.CurrentEndpoint))
                    {
                        if (!sendOperation.TryMoveToAlternate(e))
                        {
                            return(false);
                        }
                        if (TD.RoutingServiceMovedToBackupIsEnabled())
                        {
                            TD.RoutingServiceMovedToBackup(messageRpc.EventTraceActivity, messageRpc.UniqueID, this.destinationIndex.ToString(TD.Culture), sendOperation.CurrentEndpoint.ToString());
                        }
                    }
                }
            }

            this.ResetState();
            return(true);
        }
        bool StartProcessing()
        {
            bool          callAgain     = false;
            SendOperation sendOperation = this.messageRpc.Operations[0];

            this.currentClient = this.service.GetOrCreateClient <TContract>(sendOperation.CurrentEndpoint, this.messageRpc.Impersonating);

            if (TD.RoutingServiceTransmittingMessageIsEnabled())
            {
                TD.RoutingServiceTransmittingMessage(this.messageRpc.EventTraceActivity, this.messageRpc.UniqueID, "0", this.currentClient.Key.ToString());
            }

            try
            {
                if (messageRpc.Transaction != null && sendOperation.HasAlternate)
                {
                    throw FxTrace.Exception.AsError(new ConfigurationErrorsException(SR.ErrorHandlingNotSupportedReqReplyTxn(this.messageRpc.OperationContext.Channel.LocalAddress)));
                }

                // We always work on cloned message when there are backup endpoints to handle exception cases
                Message message;
                if (sendOperation.AlternateEndpointCount > 0)
                {
                    message = messageRpc.CreateBuffer().CreateMessage();
                }
                else
                {
                    message = messageRpc.Message;
                }

                sendOperation.PrepareMessage(message);

                IAsyncResult result = null;
                using (this.PrepareTransactionalCall(messageRpc.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.currentClient.BeginOperation(message, messageRpc.Transaction, this.PrepareAsyncCompletion(operationCallback), this);
                    }
                    finally
                    {
                        if (impersonationContext != null)
                        {
                            impersonationContext.Dispose();
                        }
                    }
                }

                if (this.CheckSyncContinue(result))
                {
                    if (this.OperationComplete(result))
                    {
                        this.Complete(this.allCompletedSync);
                    }
                    else
                    {
                        callAgain = true;
                    }
                }
            }
            catch (Exception exception)
            {
                if (Fx.IsFatal(exception))
                {
                    throw;
                }

                if (!this.HandleClientOperationFailure(exception))
                {
                    throw;
                }
                callAgain = true;
            }
            return(callAgain);
        }
        bool HandleClientOperationFailure(Exception exception)
        {
            SendOperation sendOperation = this.messageRpc.Operations[0];

            if (TD.RoutingServiceTransmitFailedIsEnabled())
            {
                TD.RoutingServiceTransmitFailed(this.messageRpc.EventTraceActivity, sendOperation.CurrentEndpoint.ToString(), exception);
            }

            if (!(exception is CommunicationException || exception is TimeoutException))
            {
                //We only move to backup for CommunicationExceptions and TimeoutExceptions
                return(false);
            }

            if ((exception is CommunicationObjectAbortedException || exception is CommunicationObjectFaultedException) &&
                !this.service.ChannelExtension.HasSession)
            {
                // Messages on a non sessionful channel share outbound connections and can
                // fail due to other messages failing on the same channel
                if (messageRpc.Transaction == null && !this.abortedRetry)
                {
                    //No session and non transactional, retry the message 1 time (before moving to backup)
                    this.abortedRetry = true;
                    return(true);
                }
            }
            else if (exception 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(this.messageRpc.Impersonating);
                if (sessionChannels != null)
                {
                    sessionChannels.AbortChannel(sendOperation.CurrentEndpoint);
                }
            }
            else if (exception 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;
                    return(true);
                }
            }
            else if (exception is ProtocolException)
            {
                // This exception may happen when the current cached channel was closed due to end service recycles.
                // We abort the channel in this case and clean it up from the session.
                // We will then retry the request one more time only. In retried request, it will create a new channel because the cached channel has been cleaned up.
                if (!this.abortedRetry)
                {
                    SessionChannels sessionChannels = this.service.GetSessionChannels(this.messageRpc.Impersonating);
                    if (sessionChannels != null)
                    {
                        this.abortedRetry = true;
                        sessionChannels.AbortChannel(sendOperation.CurrentEndpoint);
                        return(true);
                    }
                }
            }

            if (sendOperation.TryMoveToAlternate(exception))
            {
                if (TD.RoutingServiceMovedToBackupIsEnabled())
                {
                    TD.RoutingServiceMovedToBackup(this.messageRpc.EventTraceActivity, messageRpc.UniqueID, "0", sendOperation.CurrentEndpoint.ToString());
                }

                return(true);
            }

            return(false);
        }
示例#5
0
        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);
        }
示例#6
0
        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;
            }
        }