/// <summary> /// Reply the fault message. /// </summary> /// <param name="callback">the response service callback.</param> /// <param name="faultMessage">indicating the fault message</param> /// <param name="clientData">the client data.</param> private void ReplyFaultMessage(IResponseServiceCallback callback, Message faultMessage, string clientData) { if (this.callbackChannelDisposed) { return; } this.ResetTimeout(); try { faultMessage.Headers.Add(MessageHeader.CreateHeader(Constant.ResponseCallbackIdHeaderName, Constant.ResponseCallbackIdHeaderNS, clientData)); if (callback is AzureQueueProxy) { callback.SendResponse(faultMessage, clientData); } else { callback.SendResponse(faultMessage); } this.IncreaseResponsesCount(); } catch (ObjectDisposedException) { this.callbackChannelDisposed = true; this.Queue.ResetResponsesCallback(); } catch (Exception e) { BrokerTracing.TraceEvent(System.Diagnostics.TraceEventType.Error, 0, "[BrokerClient] Client {0}: Failed to send fault message, Exception, {1}", this.clientId, e); } }
/// <summary> /// reply the end of message to the client. /// </summary> /// <param name="callback">the response service callback.</param> /// <param name="clientData">the client data.</param> /// <param name="clientPurged">indicating the client purged flag</param> private void ReplyEndOfMessage(IResponseServiceCallback callback, string clientData, EndOfResponsesReason reason) { if (this.callbackChannelDisposed) { return; } BrokerTracing.TraceInfo("[GetResponsesHandler] Client {0}: Send end of response, clientPurged = {1}", this.clientId, reason); this.ResetTimeout(); TypedMessageConverter converter = TypedMessageConverter.Create(typeof(EndOfResponses), Constant.EndOfMessageAction); EndOfResponses endOfResponses = new EndOfResponses(); endOfResponses.Count = this.ResponsesCount; endOfResponses.Reason = reason; Message eom = converter.ToMessage(endOfResponses, this.Version); eom.Headers.Add(MessageHeader.CreateHeader(Constant.ResponseCallbackIdHeaderName, Constant.ResponseCallbackIdHeaderNS, clientData)); this.eorReplied = true; try { if (callback is AzureQueueProxy) { callback.SendResponse(eom, clientData); } else { callback.SendResponse(eom); } } catch (ObjectDisposedException) { BrokerTracing.TraceEvent(System.Diagnostics.TraceEventType.Error, 0, "[BrokerClient] Client {0}: Send end of response error: communication object is disposed.", this.clientId); this.callbackChannelDisposed = true; this.Queue.ResetResponsesCallback(); } catch (Exception ce) { BrokerTracing.TraceEvent(System.Diagnostics.TraceEventType.Error, 0, "[BrokerClient] Client {0}: Send end of response error: {1}", this.clientId, ce); // Swallow exception } }
/// <summary> /// Called when responses arrive from broker response service /// </summary> /// <param name="message">Response message </param> public void SendResponse(Message message) { if (message == null || message.Headers == null) { SessionBase.TraceSource.TraceData(TraceEventType.Error, 0, "Null or headerless message received in main callback"); return; } if (this.isSchedulerOnAzure) { // Use heartbeat to avoid being idle 1 minute. if (message.Headers.Action == Constant.BrokerHeartbeatAction) { return; } } int index = message.Headers.FindHeader(Constant.ResponseCallbackIdHeaderName, Constant.ResponseCallbackIdHeaderNS); if (index != -1) { string responseCallbackId = message.Headers.GetHeader <string>(index); IResponseServiceCallback responseServiceCallback = null; bool callbackExists = false; lock (this.responseCallbacks) { callbackExists = this.responseCallbacks.TryGetValue(responseCallbackId, out responseServiceCallback); } if (callbackExists) { responseServiceCallback.SendResponse(message); } else { SessionBase.TraceSource.TraceInformation("call back {0} doesn't exist. callbacks count: {1}", responseCallbackId, this.responseCallbacks.Count); // Enumerator or async listener exited early so ignore further responses } } else { SessionBase.TraceSource.TraceData(TraceEventType.Error, 0, "Unexpected message received in main callback - {0}", message.Headers.Action); } }
/// <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(); } } }