devxlogo

WCF and MSMQ—Take a Message

WCF and MSMQ—Take a Message

he inherent advantages to introducing queues into an application architecture are well understood. Queues, when used properly, can:

  • Increase application robustness, as clients can send messages even when services are not running.
  • Increase application scalability, because multiple service instances can be used to process messages from a single queue.
  • Improve client responsiveness, which eliminates the need for clients to wait for a response from the service.
  • Reduce decencies between client and services, because all communication is indirect via queues.
  • Ensure the durability of messages, because they can survive service and system failures.

These are just a few of the advantages. Queues have been and will continue to be an essential component of effective application architectures.

If the basic concepts of a message and a service sound familiar, it’s because they happen to sync with WCF quite nicely. If you think of a message as a contract, the introduction of queues into a WCF-based design is a natural fit. Through the MsmqIntegrationBinding and NetMsmqBinding bindings, WCF has baked-in integration with Microsoft Message Queuing (MSMQ). Once again, WCF makes building applications simple. There are two scenarios in which you can use the integration between WCF and MSMQ:

  1. A WCF-client application can communicate with an existing MSMQ-based application using the MsmqIntegrationBinding binding. In essence, you can use a WCF-based client to place messages directly into an MSMQ queue. Another application can then process the message (you can call this process a service for the sake of simplicity).
  2. A WCF service or client can use an MSMQ queue as a message store via NetMsmqBinding. The WCF endpoints are unchanged. The key differentiator is that messages are placed into queues to await processing, rather than sent directly into the WCF runtime.

The first scenario is basically legacy integration, while the second is a full-on WCF solution that happens to use MSMQ. The remainder of this article explores the first scenario. The second scenario will be covered in a future article.

To explore leveraging MSMQ from a WCF client, it makes sense to start with a standard MSMQ application. Via the System.Messaging namespace, developers can use MSMQ to pass messages into queues. These messages are nothing more than serialized objects. Different applications can retrieve these serialized objects from the queue and rehydrate them for useful purposes. A typical message class might look something like this:

public class ApplicationMessage{    private string _message = string.Empty;    private DateTime _validUntil;    public string Message    {        set { _message = value; }        get { return _message; }    }    public DateTime ValidUntil    {        get { return _validUntil; }        set { _validUntil = value; }    }}

Essentially, the message class is a set of properties. No special MSMQ code is required. The class simply encapsulates a set of data that one application or component wishes to pass to another.

A client application could place an instance of this ApplicationMessage message class into an MSMQ queue using the following code:

public void SendMessage(){    System.Messaging.MessageQueue queue = new MessageQueue(@".Private$	estqueue");        ApplicationMessage msg = new ApplicationMessage();    msg.Message = "Hello World";    msg.ValidUntil = DateTime.Now;    System.Messaging.MessageQueueTransaction trans = new MessageQueueTransaction();                trans.Begin();    queue.Send(msg, trans);    trans.Commit();    queue.Close(); }
?
Figure 1. Computer Management Console: Queues can be created manually using the Computer Management Console.

The code assumes that a private, transactional queue was created on the local system. The queue can be constructed either through code or by using the Message Queueing section of the Computer Management Console (see Figure 1).

Finally, a server application could retrieve and process the message from the queue as follows:

public static void ReceiveMessage(){    MessageQueue queue = new MessageQueue(@".Private$TestQueue");    queue.Formatter = new XmlMessageFormatter(new Type[] { typeof(ApplicationMessage) });        Message message = null;    message = queue.Receive();    ApplicationMessage msg = (ApplicationMessage)message.Body;    queue.Close();    //Do some actual work with the message here    System.Console.WriteLine(msg.Message);    System.Console.WriteLine(msg.ValidUntil);    System.Console.ReadLine(); }

The code above represents a traditional MSMQ application (albeit somewhat simplified). By introducing WCF and the MsmqIntegrationBinding binding, a developer can actually create a WCF-based client application to communicate with the existing MSMQ-based server application. No changes to the service application are required.Because there is no existing WCF service endpoint, there is no way to automatically generate a proxy class. This means that you have to create the class manually. The first step is creating the contract:

[System.ServiceModel.ServiceContractAttribute(Namespace = "http://SendMessage")]public interface ISendMessage{    [OperationContract(IsOneWay = true)]    void SubmitMessage(MsmqMessage message);}

The Service Contract

The service contract for communicating with a MSMQ-hosted queue contains only a single send operation. This is a limitation specific to the MsmqIntegrationBinding binding. The single submit operation takes an MsmqMessage initialized with the type ApplicationMessage, which is the message class you created earlier. Also notice that the contract is set to one-way, indicating that no output message is expected. It is worth noting at this point that MsmqIntegrationBinding does not support message-level security. This makes sense because the MSMQ-based service, not being WCF or SOAP aware, would have no way to interpret the necessary information for message-based security. Transport-level security is supported.

After the contract is created, you can write WCF code directly, open a channel, and submit a message:

MsmqIntegrationBinding binding = new MsmqIntegrationBinding();binding.Security.Mode = MsmqIntegrationSecurityMode.None;EndpointAddress address = new EndpointAddress(@"msmq.formatname:DIRECT=OS:.private$TestQueue");ChannelFactory channelFactory = new ChannelFactory(binding, address);ISendMessage channel = channelFactory.CreateChannel();ApplicationMessage message = new ApplicationMessage();message.Message = "Hello from WCF!";message.ValidUntil = DateTime.Now;MsmqMessage msmqMsg = new MsmqMessage(message);using (TransactionScope scope = new TransactionScope(TransactionScopeOption.Required)){    channel.SubmitMessage(msmqMsg);    scope.Complete();}

As expected, the MsmqIntegrationBinding is used. Take special note of the format used for the endpoint address. This is what actually points WCF to the proper queue. Much like in the legacy MSMQ client, a new MsmqMessage is initialized with your ApplicationMessage message class. The key difference is that instead of using an MsmqTransaction, a System.Transactions.TransactionScope is used. You must use a transaction because the queue is transactional. By default, MsmqIntegrationBinding sets TransactionScopeRequired and TransactionAutoComplete to true. There is an alternative to the abundance of WCF client code. A service client that extends ClientBase can be created and the WCF settings can be moved into the configuration file:

public class SendMessageClient : System.ServiceModel.ClientBase, ISendMessage{    public void SubmitMessage(MsmqMessage message)    {       base.Channel.SubmitMessage(message);    }    public void SubmitMessage(ApplicationMessage message)    {        MsmqMessage msmqMsg = new MsmqMessage(message);        SubmitMessage(msmqMsg);    }}

Notice the additional overload of SubmitMessage. This new overload, while not required, allows the caller to use the WCF/MSMQ service without having to actually construct a MsmqMessage, further isolating it from the specific implementation details. The caller simply needs to instantiate an ApplicationMessage and the WCF client handles packaging it up into a MsmqMessage. The caller need never know that the ultimate destination for the message is a MSMQ queue.

The final step when extending ClientBase is moving the configuration out of code and into the application configuration file (see Listing 1).

Depending on the needs of the developer, either method (code or configuration based) can be used to create the WCF client. The MSMQ-based service application requires no changes. The advantage to this approach is that the client application is completely isolated from the details of the service. It has knowledge only of the contract. If, at some point, the MSMQ-based service were to be replaced with a WCF-based service, only the WCF-client configuration would need to change. The client application itself would remain the same. At this point, you have successfully isolated the things that change from the things that do not.

The next article in the series will explore how the MSMQ-based service created here can be transformed into a WCF-based service that uses queues.

devxblackblue

About Our Editorial Process

At DevX, we’re dedicated to tech entrepreneurship. Our team closely follows industry shifts, new products, AI breakthroughs, technology trends, and funding announcements. Articles undergo thorough editing to ensure accuracy and clarity, reflecting DevX’s style and supporting entrepreneurs in the tech sphere.

See our full editorial policy.

About Our Journalist