Create the Response Handler Service

The Client Application uses a WCF service to retrieve and log response messages from the responsequeue and ItalyMilan subscription of the responsetopic. This topic lists the steps to create the Response Handler WCF Service.

Response Handler Service

The following code shows how the Response Handler WCF service retrieves and logs response messages from the responsequeue and ItalyMilan subscription of the responsetopic:

[ServiceBehavior(Namespace = "https://windowsazure.cat.microsoft.com/samples/servicebus")]
public class ResponseHandlerService : ICalculatorResponseSessionful
{
    #region Private Constants
    //***************************
    // Formats
    //***************************
    private const string MessageSuccessfullyReceived = "Response Message Received:\n - EndpointUrl:[{0}]" +
                                                        "\n - CorrelationId=[{1}]\n - SessionId=[{2}]\n - Label=[{3}]";
    private const string ReceivedMessagePropertiesHeader = "Properties:";
    private const string PayloadFormat = "Payload:";
    private const string StatusFormat = " - Status=[{0}]";
    private const string ResultFormat = " - Result[{0}]: Value=[{1}] Error=[{2}]";
    private const string MessagePropertyFormat = " - Key=[{0}] Value=[{1}]";

    //***************************
    // Constants
    //***************************
    private const string Empty = "EMPTY";
    #endregion

    #region Public Operations
    [OperationBehavior]
    public void ReceiveResponse(CalculatorResponseMessage calculatorResponseMessage)
    {
        try
        {
            if (calculatorResponseMessage != null &&
                calculatorResponseMessage.CalculatorResponse != null)
            {
                // Initialize calculatorResponse var
                var calculatorResponse = calculatorResponseMessage.CalculatorResponse;

                // Get the message properties
                var incomingProperties = OperationContext.Current.IncomingMessageProperties;
                var brokeredMessageProperty = incomingProperties[BrokeredMessageProperty.Name] as 
                                              BrokeredMessageProperty;

                // Trace the response message
                var builder = new StringBuilder();
                if (brokeredMessageProperty != null)
                    builder.AppendLine(string.Format(MessageSuccessfullyReceived, 
                                                     OperationContext.Current.Channel.LocalAddress.Uri.AbsoluteUri,
                                                     brokeredMessageProperty.CorrelationId ?? Empty,
                                                     brokeredMessageProperty.SessionId ?? Empty,
                                                     brokeredMessageProperty.Label ?? Empty));
                builder.AppendLine(PayloadFormat);
                builder.AppendLine(string.Format(StatusFormat,
                                                    calculatorResponse.Status));
                if (calculatorResponse.Results != null && 
                    calculatorResponse.Results.Count > 0)
                {
                    for (int i = 0; i < calculatorResponse.Results.Count; i++)
                    {
                        builder.AppendLine(string.Format(ResultFormat, 
                                                            i + 1, 
                                                            calculatorResponse.Results[i].Value,
                                                            calculatorResponse.Results[i].Error));
                    }
                }
                builder.AppendLine(ReceivedMessagePropertiesHeader);
                if (brokeredMessageProperty != null)
                {
                    foreach (var property in brokeredMessageProperty.Properties)
                    {
                        builder.AppendLine(string.Format(MessagePropertyFormat,
                                                            property.Key,
                                                            property.Value));
                    }
                }
                var traceMessage = builder.ToString();
                Trace.WriteLine(traceMessage.Substring(0, traceMessage.Length - 1));

                //Complete the Message
                ReceiveContext receiveContext;
                if (ReceiveContext.TryGet(incomingProperties, out receiveContext))
                {
                    receiveContext.Complete(TimeSpan.FromSeconds(10.0d));
                }
                else
                {
                    throw new InvalidOperationException("An exception occurred.");
                }
            }
        }
        catch (Exception ex)
        {
            Trace.WriteLine(ex.Message);
        }
    } 
    #endregion
}

To retrieve and log the response messages, the Response Handler WCF service exposes two endpoints that use the NetMessagingBinding and receive messages from one of the two queues. Each subscription can be seen as a virtual queue getting copies of messages published to the topic they belong to.

Looking at the ResponseHandlerService class in the code, the service retrieves the BrokeredMessageProperty from the Properties collection of the incoming WCF message and uses this object to access the properties of the response message. In the ICalculatorResponse service contract, the ReceiveResponse method uses the [ReceiveContextEnabled(ManualControl = true)] attribute. As a result, the service method must explicitly signal the receive. This signaling requires the service to explicitly invoke the ReceiveContext.Complete method to commit the receive operation. When the ManualControl property is set to true, the message received from the channel is delivered to the service operation with a lock for the message. The service implementation must call Complete(TimeSpan) or Abandon(TimeSpan) to signal the receive completion of the message. Failure to call either of these methods causes a lock on the message until the lock timeout interval passes. Once the lock is released (either through a call to Abandon(TimeSpan) or lock timeout), the message is redispatched from the channel to the service. Calling Complete(TimeSpan) marks the message as successfully received.

Next

Test the Solution

See Also

Concepts

Create the Client Application
Create the Response Handler Service
Invoke the application