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