/// <summary> /// the event when the session failed. /// </summary> public override void SessionFailed() { if (this.Queue.ProcessedRequestsCount <= 0) { this.ReplyFaultMessage(this.lastResponseServiceCallback, FrontEndFaultMessage.GenerateFaultMessage(null, this.Version, SOAFaultCode.Broker_SessionFailure, SR.SessionFailure), this.clientData); this.ReplyEndOfMessage(this.lastResponseServiceCallback, this.clientData); } }
/// <summary> /// generate the fault message when the session failed. /// </summary> private void GenerateSessionFailureFaultMessage() { XmlDocument doc = new XmlDocument() { XmlResolver = null }; Message soap11FaultMessage = FrontEndFaultMessage.GenerateFaultMessage(null, MessageVersion.Soap11, SOAFaultCode.Broker_SessionFailure, SR.SessionFailure); XPathNavigator nav = soap11FaultMessage.CreateBufferedCopy(BrokerEntry.MaxMessageSize).CreateNavigator(); doc.Load(nav.ReadSubtree()); this.messages.Add(doc.DocumentElement); }
/// <summary> /// End of responses received /// </summary> /// <param name="eventId">indicating the event id</param> /// <param name="eventArgs">indicating the event args</param> public override void EndOfResponses(BrokerQueueEventId eventId, ResponseEventArgs eventArgs) { IResponseServiceCallback callback = (IResponseServiceCallback)(eventArgs.State as object[])[0]; string clientData = (eventArgs.State as object[])[1].ToString(); // if the broker fails and the last available response received, then append the session failure fault message let the client API to handle the failure gracefully. if (eventId == BrokerQueueEventId.AvailableResponsesDispatched) { this.ReplyFaultMessage(callback, FrontEndFaultMessage.GenerateFaultMessage(null, this.Version, SOAFaultCode.Broker_SessionFailure, SR.SessionFailure), clientData); } this.ReplyEndOfMessage(callback, clientData); }
/// <summary> /// Get more responses /// </summary> /// <param name="position">indicating the position</param> /// <param name="count">indicating the count</param> /// <param name="callbackInstance">indicating the callback instance</param> public void GetResponses(GetResponsePosition position, int count, IResponseServiceCallback callbackInstance) { if (position == GetResponsePosition.Begin) { this.ResponsesCount = 0; if (this.IsSessionFailed()) { IResponseServiceCallback callback = callbackInstance; this.ReplyFaultMessage(callback, FrontEndFaultMessage.GenerateFaultMessage(null, this.Version, SOAFaultCode.Broker_SessionFailure, SR.SessionFailure), this.clientData); this.ReplyEndOfMessage(callback, this.clientData); return; } if (this.cacheBrokerQueueItem) { // ACK the items as they were failed to send back to client lock (this.lockCacheItemList) { this.Queue.AckResponses(this.cachedItemList, false); this.cachedItemList = new List <BrokerQueueItem>(); } } this.Queue.ResetResponsesCallback(); } else { if (this.cacheBrokerQueueItem) { // ACK the items as they were succeeded to send back to client lock (this.lockCacheItemList) { this.Queue.AckResponses(this.cachedItemList, true); this.cachedItemList = new List <BrokerQueueItem>(); } } } ResponseActionFilter filter = GenerateResponseActionFilter(this.Action); this.lastResponseServiceCallback = callbackInstance; if (!this.Queue.RegisterResponsesCallback(this.ReceiveResponse, this.Version, filter, count, new object[] { this.lastResponseServiceCallback, this.clientData })) { this.ReplyEndOfMessage(this.lastResponseServiceCallback, this.clientData); } }
/// <summary> /// generate the fault message when the session failed. /// </summary> private void GenerateFaultMessage(EndOfResponsesReason reason) { XmlDocument doc = new XmlDocument() { XmlResolver = null }; Message soap11FaultMessage = null; switch (reason) { case EndOfResponsesReason.ClientPurged: soap11FaultMessage = FrontEndFaultMessage.GenerateFaultMessage(null, MessageVersion.Soap11, SOAFaultCode.ClientPurged, SR.ClientPurged); break; case EndOfResponsesReason.ClientTimeout: soap11FaultMessage = FrontEndFaultMessage.GenerateFaultMessage(null, MessageVersion.Soap11, SOAFaultCode.ClientTimeout, SR.ClientTimeout); break; } XPathNavigator nav = soap11FaultMessage.CreateBufferedCopy(BrokerEntry.MaxMessageSize).CreateNavigator(); doc.Load(nav.ReadSubtree()); this.messages.Add(doc.DocumentElement); }
/// <summary> /// Receive response message /// </summary> /// <param name="item">broker queue item</param> /// <param name="asyncState">async state</param> private void ReceiveResponse(BrokerQueueItem item, object asyncState) { if (this.callbackChannelDisposed) { throw new Exception("Callback channel was disposed"); } this.ResetTimeout(); BrokerTracing.TraceEvent(System.Diagnostics.TraceEventType.Verbose, 0, "[BrokerClient] Client {0}: Receive Response from BrokerQueue", this.clientId); object[] objArray = asyncState as object[]; IResponseServiceCallback callback = (IResponseServiceCallback)objArray[0]; string clientData = objArray[1].ToString(); Message response = this.ConvertMessage(item.Message); int index = response.Headers.FindHeader(Constant.ResponseCallbackIdHeaderName, Constant.ResponseCallbackIdHeaderNS); if (index < 0) { response.Headers.Add(MessageHeader.CreateHeader(Constant.ResponseCallbackIdHeaderName, Constant.ResponseCallbackIdHeaderNS, clientData)); } Exception exception = null; try { if (callback is AzureQueueProxy) { callback.SendResponse(response, clientData); } else { callback.SendResponse(response); } BrokerTracing.EtwTrace.LogFrontEndResponseSent(this.SharedData.BrokerInfo.SessionId, this.clientId, Utility.GetMessageIdFromResponse(response)); this.IncreaseResponsesCount(); } catch (ObjectDisposedException e) { this.callbackChannelDisposed = true; exception = new Exception("Callback channel is disposed", e); throw exception; } catch (CommunicationObjectFaultedException e) { this.callbackChannelDisposed = true; exception = new Exception("Callback channel is faulted", e); throw exception; } catch (CommunicationObjectAbortedException e) { this.callbackChannelDisposed = true; exception = new Exception("Callback channel is abroted", e); throw exception; } catch (Exception ce) { BrokerTracing.TraceEvent(System.Diagnostics.TraceEventType.Error, 0, "[BrokerClient] Client {0}: Send back response error: {1}", this.clientId, ce); // Reply a fault message indicating failed to send back the response and reply EOR and finish. this.ReplyFaultMessage(callback, FrontEndFaultMessage.GenerateFaultMessage(null, MessageVersion.Default, SOAFaultCode.Broker_SendBackResponseFailed, SR.SendBackResponseFailed), clientData); this.ReplyEndOfMessage(callback, clientData); } finally { // We do not need to lock here because this callback is designed to be // triggered by BrokerQueue synchronizely if (this.cacheBrokerQueueItem) { lock (this.lockCacheItemList) { this.cachedItemList.Add(item); } } else { this.Queue.AckResponse(item, (exception == null)); } if (this.callbackChannelDisposed) { this.Queue.ResetResponsesCallback(); } } }
/// <summary> /// Put response back into broker queue /// </summary> /// <param name="data">indicating the instance of dispatch data</param> public void PutResponseBack(DispatchData data) { Contract.Requires(data.BrokerQueueItem != null); // Either the exception is null or it is a FaultException<RetryOperationError>; var faultException = data.Exception as FaultException <RetryOperationError>; Contract.Requires(data.Exception == null || faultException != null); // Either we will get a reply message or an exception. Contract.Requires(data.ReplyMessage != null || data.Exception != null); Contract.Requires(data.DispatchTime != null); Contract.Ensures(data.ReplyMessage == null); Contract.Ensures(data.BrokerQueueItem == null); Contract.Ensures(data.Exception == null); // Indicate that a call has completed try { long callDuration = DateTime.Now.Subtract(data.DispatchTime).Ticks / 10000 / (this.serviceRequestPrefetchCount + 1); this.observer.CallComplete(callDuration); } catch (Exception e) { // There may be some null reference exception while cleaning up // Ignore these exceptions BrokerTracing.TraceEvent(TraceEventType.Warning, 0, "[ResponseQueueAdapter] ID = {0} Exception throwed while updating the broker observer: {1}", data.TaskId, e); } var item = data.BrokerQueueItem; if (item.Context is DummyRequestContext) { Message reply = null; if (data.Exception != null) { if (faultException != null) { reply = Message.CreateMessage(MessageVersion.Default, faultException.CreateMessageFault(), faultException.Action); // Only add relatesTo header to WSAddressing messages if (item.Message.Headers.MessageId != null && MessageVersion.Default.Addressing == AddressingVersion.WSAddressing10) { reply.Headers.RelatesTo = item.Message.Headers.MessageId; } BrokerTracing.EtwTrace.LogBackendGeneratedFaultReply(data.SessionId, data.TaskId, data.MessageId, reply.ToString()); } else { Debug.Fail("The exception in DispatchData should be an instance of FaultException<RetryOperationError>"); } } else if (data.ReplyMessage != null) { reply = data.ReplyMessage; // Put the response to the broker queue BrokerTracing.EtwTrace.LogBackendResponseStored(data.SessionId, data.TaskId, data.MessageId, reply.IsFault); } else { Debug.Fail("Both ReplyMessage and Exception are null. This shouldn't happen."); } this.queueFactory.PutResponseAsync(reply, item); } else { Message reply = null; if (data.Exception != null) { if (faultException != null) { reply = FrontEndFaultMessage.GenerateFaultMessage(item.Message, item.Context.MessageVersion, faultException); BrokerTracing.EtwTrace.LogBackendGeneratedFaultReply(data.SessionId, data.TaskId, data.MessageId, reply.ToString()); } else { Debug.Fail("The exception in DispatchData should be an instance of FaultException<RetryOperationError>"); } } else if (data.ReplyMessage != null) { reply = data.ReplyMessage; // Reply the message // Convert the message version if (reply.Version != item.Context.MessageVersion) { if (reply.IsFault) { MessageFault fault = MessageFault.CreateFault(reply, int.MaxValue); reply = Message.CreateMessage(item.Context.MessageVersion, fault, reply.Headers.Action); } else { reply = Message.CreateMessage(item.Context.MessageVersion, reply.Headers.Action, reply.GetReaderAtBodyContents()); } } } else { Debug.Fail("Both ReplyMessage and Exception are null. This shouldn't happen."); } this.TryReplyMessage(data.SessionId, item.Context, reply, data.MessageId); // dispose request item item.Dispose(); } // Set to null since we returned it back to queue data.BrokerQueueItem = null; data.ReplyMessage = null; data.Exception = null; }