public void AttachService(RoutingService service)
        {
            SessionChannels channelsToClose = null;

            lock (this.thisLock)
            {
                if (!this.hasSession)
                {
                    RoutingConfiguration oldConfig = null;
                    if (this.sessionService != null)
                    {
                        oldConfig = this.sessionService.RoutingConfig;
                    }

                    if (oldConfig != null && !object.ReferenceEquals(service.RoutingConfig, oldConfig))
                    {
                        //The RoutingConfiguration has changed.  We need to release any old channels that are cached.
                        channelsToClose      = this.sessionChannels;
                        this.sessionChannels = null;
                    }
                }
                else
                {
                    Fx.Assert(this.sessionService == null, "There must only be one RoutingService created for a sessionful channel");
                }
                this.sessionService = service;
            }

            if (channelsToClose != null)
            {
                channelsToClose.BeginClose(this.channel.OperationTimeout, closeChannelsCallback, channelsToClose);
            }
        }
        public void Fault(Exception exception)
        {
            FxTrace.Trace.SetAndTraceTransfer(this.ActivityID, true);

            //Notify the error handlers that a problem occurred
            foreach (IErrorHandler errorHandler in this.endpointBehavior.ChannelDispatcher.ErrorHandlers)
            {
                if (errorHandler.HandleError(exception))
                {
                    break;
                }
            }

            SessionChannels channelsToAbort;

            lock (this.thisLock)
            {
                channelsToAbort      = this.sessionChannels;
                this.sessionChannels = null;
            }

            if (channelsToAbort != null)
            {
                channelsToAbort.AbortAll();
            }

            RoutingUtilities.Abort(this.channel, this.channel.LocalAddress);
        }
Beispiel #3
0
 void IDisposable.Dispose()
 {
     if (this.perMessageChannels != null)
     {
         //This is for impersonation, thus it's supposed to complete sync
         IAsyncResult result = this.perMessageChannels.BeginClose(this.ChannelExtension.OperationTimeout, null, null);
         this.perMessageChannels.EndClose(result);
         this.perMessageChannels = null;
     }
 }
Beispiel #4
0
 internal IRoutingClient GetOrCreateClient <TContract>(RoutingEndpointTrait endpointTrait, bool impersonating)
 {
     if (impersonating && !this.ChannelExtension.HasSession)
     {
         if (this.perMessageChannels == null)
         {
             this.perMessageChannels = new SessionChannels(this.ChannelExtension.ActivityID);
         }
         return(this.perMessageChannels.GetOrCreateClient <TContract>(endpointTrait, this, impersonating));
     }
     else
     {
         return(this.ChannelExtension.SessionChannels.GetOrCreateClient <TContract>(endpointTrait, this, impersonating));
     }
 }
        static void CloseChannelsCallback(IAsyncResult asyncResult)
        {
            SessionChannels channelsToClose = (SessionChannels)asyncResult.AsyncState;
            Exception       exception       = null;

            try
            {
                channelsToClose.EndClose(asyncResult);
            }
            catch (CommunicationException communicationException)
            {
                exception = communicationException;
            }
            catch (TimeoutException timeoutException)
            {
                exception = timeoutException;
            }

            if (exception != null && TD.RoutingServiceHandledExceptionIsEnabled())
            {
                TD.RoutingServiceHandledException(null, exception);
            }
        }
        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);
        }
Beispiel #7
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);
        }