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); }
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; } }
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); }
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); }