Export (0) Print
Expand All

NetMessagingBinding

Updated: March 13, 2014

Service Bus Brokered Messaging supports the WCF programming model and provides a new binding called NetMessagingBinding that can be used by WCF-enabled applications to send and receive messages through queues, topics and subscriptions. NetMessagingBinding is the new name for the binding for queues and topics that provides full integration with WCF. From a functional perspective, NetMessagingBinding is similar to NetMsmqBinding, which supports queuing by using Message Queuing (MSMQ) as a transport and enables support for loosely-coupled applications. On the service-side, NetMessagingBinding provides an automatic message-pump that pulls messages off a queue or subscription and is integrated with WCF’s ReceiveContext mechanism.

The new binding supports the standard interfaces IInputChannel, IOutputChannel, and IInputSessionChannel. When an application uses WCF and NetMessagingBinding to send a message to a queue or a topic, the message is wrapped in a SOAP envelope and encoded. To set BrokeredMessage-specific properties, you need to create a BrokeredMessageProperty object, set the properties on it, and add it to the Properties collection of the WCF message, as shown in the following example. When using the NetMessagingBinding to write a message to queue or a topic, the ServiceBusOutputChannel internal class looks for the BrokeredMessageProperty property in the Properties collection of the WCF message and copies all its properties to the BrokeredMessage object it creates. Then it copies the payload from the WCF message to the BrokeredMessage object and finally, publishes the resulting message to the target queue or topic.

static void Main(string[] args)
{
    try
    {
        // Create the 
        var channelFactory = new ChannelFactory<IOrderService>("orderEndpoint");
        var clientChannel = channelFactory.CreateChannel();
        
        // Create a order object
        var order = new Order()
                        {
                            ItemId = "001",
                            Quantity = 10
                        };

        // Use the OperationContextScope to create a block within which to access the current OperationScope
        using (var scope = new OperationContextScope((IContextChannel)clientChannel))
        {
            // Create a new BrokeredMessageProperty object
            var property = new BrokeredMessageProperty();

            // Use the BrokeredMessageProperty object to set the BrokeredMessage properties
            property.Label = "OrderItem";
            property.MessageId = Guid.NewGuid().ToString();
            property.ReplyTo = "sb://acme.servicebus.windows.net/invoicequeue";

            // Use the BrokeredMessageProperty object to define application-specific properties
            property.Properties.Add("ShipCountry", "Italy");
            property.Properties.Add("ShipCity", "Milan");

            // Add BrokeredMessageProperty to the OutgoingMessageProperties bag provided 
            // by the current Operation Context 
            OperationContext.Current.OutgoingMessageProperties.Add(BrokeredMessageProperty.Name, property);
            clientChannel.SendOrder(order);
        }
    }
    catch (Exception ex)
    {
        Console.WriteLine(ex.Message);
    }
}

Likewise, when you use a NetMessagingBinding-based service endpoint to receive messages from a queue or a topic, an application can retrieve the BrokeredMessageProperty object from the Properties collection of the incoming WCF Message, as shown in the following example. In particular, when the service endpoint receives messages, the ServiceBusInputChannel and ServiceBusInputSessionChannel internal classes create a new WCF Message and copy the payload from the body on the inbound to the body of the newly created WCF message. (ServiceBusInputSessionChannel is used to receive messages from sessionful queues and subscriptions). Then they copy the properties from the inbound BrokeredMessage to a new instance of the BrokeredMessageProperty class and, finally, add the new BrokeredMessageProperty object to the Properties collection of the incoming WCF Message.

[ServiceBehavior]
public class OrderService : IOrderService
{
    [OperationBehavior]
    public void ReceiveOrder(Order order)
    {
        // Get the BrokeredMessageProperty from the current OperationContext
        var incomingProperties = OperationContext.Current.IncomingMessageProperties;
        var property = incomingProperties[BrokeredMessageProperty.Name] as BrokeredMessageProperty;

        ...
    }
}

Because the Service Bus does not support IInputSessionChannel, all applications sending messages to session-enabled queues must use a service contract where the value of the SessionMode property is different from that of the SessionMode.Required. However, because the Service Bus WCF runtime supports IInputSessionChannel and other interfaces order to receive messages from a sessionful queue or subscription that uses WCF and NetMessagingBinding, applications must implement a session-aware service contract. The following code snippet provides an example of a WCF service that receives messages from a sessionful queue/subscription.

// ServiceBus does not support IOutputSessionChannel.
// All senders sending messages to sessionful queue must use a contract which does not enforce SessionMode.Required.
// Sessionful messages are sent by setting the SessionId property of the BrokeredMessageProperty object.
[ServiceContract]
public interface IOrderService
{
    [OperationContract(IsOneWay = true)]
    [ReceiveContextEnabled(ManualControl = true)]
    void ReceiveOrder(Order order);
}

// ServiceBus supports both IInputChannel and IInputSessionChannel. 
// A sessionful service listening to a sessionful queue must have SessionMode.Required in its contract.
[ServiceContract(SessionMode = SessionMode.Required)]
public interface IOrderServiceSessionful : IOrderService
{
}

[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession, ConcurrencyMode = ConcurrencyMode.Single)]
public class OrderService : IOrderServiceSessionful
{
    [OperationBehavior]
    public void ReceiveOrder(Order order)
    {
        // Get the BrokeredMessageProperty from the current OperationContext
        var incomingProperties = OperationContext.Current.IncomingMessageProperties;
        var property = incomingProperties[BrokeredMessageProperty.Name] as BrokeredMessageProperty;

        ...

        //Complete the Message
        ReceiveContext receiveContext;
        if (ReceiveContext.TryGet(incomingProperties, out receiveContext))
        {
            receiveContext.Complete(TimeSpan.FromSeconds(10.0d));
            ...
        }
        else
        {
            throw new InvalidOperationException("...");
        }
    }
}

Note that the ManualControl property of the ReceiveContextEnabled operation attribute is set to true. This setting makes the service explicitly invoke the ReceiveContext.Complete method to commit the receive operation. In fact, 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 either call Complete(TimeSpan) or Abandon(TimeSpan) to signal that the message has been received completely. Failure to call one of these methods results in the lock being held on the message until the lock timeout interval elapses. Once the lock is released (either by a call to Abandon(TimeSpan) or by a lock timeout) the message is dispatched again from the channel to the service. Calling Complete(TimeSpan) marks the message as successfully received.

Note also that the OrderService class sets the ServiceBehavior.InstanceContextMode property to InstanceContextMode.PerSession and the ConcurrencyMode property to ConcurrencyMode.Single. This way the ServiceHost creates a new service instance every time a new session is available in the specified queue or subscription, and the ServiceHost uses a single thread to receive messages sequentially from the queue or subscription. The SessionIdleTimeout property of the NetMessagingBinding controls the lifetime of the service. For more information on how to use WCF exchange messages through a sessionful queue, I strongly suggest you to look at the WcfServiceSessionSample sample included in the Windows Azure AppFabric SDK V1.5.

Community Additions

ADD
Show:
© 2014 Microsoft