Click here to Skip to main content
15,867,568 members
Articles / Web Development / ASP.NET

WCF Queued Messaging

Rate me:
Please Sign up or sign in to vote.
4.63/5 (15 votes)
16 Mar 2009CPOL10 min read 81.3K   2.7K   47   13
Explains in detail how to use MSMQ with WCF via the NetMsmqBinding.

First Things First

Before you begin, I want to say sorry in advance for putting the configuration code as images. I tried all combinations of tags and could not get the XML code to display correctly. I must be doing something wrong, so any help for future articles would be appreciated :)

Who is this Article For?

This article is aimed at developers who work with messaging across distributed systems. It assumes familiarity with the following:

  • WCF
  • Messaging concepts
  • MSMQ

Introduction

Message Exchange Patterns (MEPs) are well known for seasoned developers. In a nutshell, messaging occurs in one of four modes:

  • One-Way: a client sends a message to a service without expecting a result back. The client will still be notified about message delivery, though, through acknowledgement.
  • Request-Response / Synchronous: a client sends a message to a service which responds directly via the same channel with a response message. Meaning, the client will block until it receives the data it is asking for in the form of another message.
  • Request-Response / Asynchronous: this is a variation of the synchronous mode where a client does not block waiting for the response from the service. The client continues working, and once the service finishes processing the request, it sends the response message back to the client on a separate thread.
  • Duplex: this is a case where both parties can initialize the conversation. System A can send a request for system B, in which case, A is the client and B is the service. On the other hand, system B can send a request for system A, in which case B is the client and A is the service.

One common requirement for all MEPs is message durability; that is the ability to preserve the message under all conditions and make sure that a message will arrive where it is supposed to.

Microsoft Message Queuing Service is a proven method to provide a queue for messages to reside inside until recipients are ready to pick them up. WCF offers implicit MSMQ integration through NetMsmqBinding, which is the topic of this article.

Scenario

This article will walk through implementing a scenario where a client sends a request for a service via MSMQ. The service processes the request and sends the response back, also via MSMQ; of course, all this through WCF NetMsmqBinding. The client is named “Client” and the service is named “Service”… not very creative, I know.

Step1: Creating the Queues

The first thing we will do is create the queues that the Service and the Client will talk to. MSMQ, in particular, is not the topic of this article, but I will highlight the points below:

  • MSMQ is part of Windows components, and can be reached from the Computer Management console (right click on My Computer --> Manage).
  • MSMQ queues come in two flavors: Private and Public. Private queues work when both the Service and the Client are on the same machine. Public queues are used when the Client and the Service are on different machines joined to a common Active Directory. This article works with private queues, but the same concept applies to public ones. Moreover, how public queues differ is explained later.

So, from the Computer Management console, create two private queues called “requestqueue” and “responsequeue”, as shown in the below image. Create both queues as transactional ones. Transaction code will be written in WCF as we will see later.

1.JPG

“requestqueue” will receive all Client requests to the Service. “responsequeue”, on the other hand, will receive all Service responses back to the Client.

Step 2: Creating the Service

The Service is self-hosted, and simply exposes an operation where the Client calls to ask for the credit limit of a certain ID (needless to say, a rather dummy scenario, but sufficient nonetheless).

Shown below is the simple code of the service contract:

C#
[ServiceContract]
public interface ICreditLimitRequest
{
    [OperationContract(IsOneWay = true)]
    void SendCreditLimitRequest(string id);
}

public class CreditLimitRequestService : ICreditLimitRequest
{
    public void SendCreditLimitRequest(string id)
    {
        double value;

        if (id == "1")
            value = 10;
        else if (id == "2")
            value = 20;
        else
            value = 0;
      
    }
}

One thing to note about the above code is that we have marked the operation as IsOneWay = true. This ensures that we are using the One-Way MEP (more on this later).

The service is hosted inside a Windows application with two buttons, one to start the service and the other to stop it. The code is shown below:

C#
private void button1_Click(object sender, EventArgs e)
{
    myServiceHost = new ServiceHost(typeof(CreditLimitRequestService));
    myServiceHost.Open();
    MessageBox.Show("Service Started!");
}

private void button2_Click(object sender, EventArgs e)
{
    if (myServiceHost.State != CommunicationState.Closed)
    {
        myServiceHost.Close();
        MessageBox.Show("Service Stopped!");
    }
}

Finally, the configuration of the Service is shown below:

12.JPG

A few important things to note about the configuration:

  1. The endpoint address specifies that the service will be listening to the private queue “requestqueue”.
  2. The endpoint binding is set to “netMsmqBinding”, which is the implicit WCF binding for working with MSMQ.
  3. The base address is set to “http://localhost:8020/msmqservice”. This is important in order to be able to use Visual Studio Add Service Reference (svcutil.exe) from the Client application in order to generate the proxy. As we will see later, once the Service is started, we can use the base address as the URL of the Service when generating the proxy.
  4. Finally, the MEX endpoint is exposed to enable metadata exchange through HTTP (again, for the Add Service Reference functionality).
Note: I created the sample on WinXP which books port 80 for its own usage. And, since the http.sys kernel is not present, I had to change the port to 8020 (or any other free port on your machine); you won’t face this case if you are using Win2003.

Step 3: Creating the Client

Well, the title is only 50% correct. From a business perspective, we are actually building the Client since it is the application requesting the credit limit from the Service; it is the one initializing the process driven by its need to get the limit.

However, from a technical perspective, you will see that the Client application exposes a service contract just like the Service application did; so, technically, the Client application is also a service. The entire cycle would be as follows:

  1. The Client calls the Service asking for the credit limit of a certain user ID. The Service exposes a service contract and an operation consumed by the Client via a generated proxy.
  2. The Client call is queued in the “requestqueue”.
  3. The Service picks up the message in the “requestqueue”.
  4. The Service processes the request and calls the Client to hand it the response. In this case, the Client has also exposed a service contract and an operation consumed by the Service via a generated proxy.
  5. The Service response is queued in the “responsequeue” (to be discussed next).
  6. The Client picks up the response message in the “responsequeue”.

The code below shows the service contract defined in the Client application:

C#
[ServiceContract]
public interface ICreditLimitResponse
{
    [OperationContract(IsOneWay = true)]
    void SendCreditLimitResponse(double limit);
}

public class CreditLimitResponseService : ICreditLimitResponse
{
    public void SendCreditLimitResponse(double limit)
    {
        System.Windows.Forms.MessageBox.Show(limit.ToString());
    }
}

Again, note that we have marked the operation as IsOneWay = true. This ensures that we are using the One-Way MEP (more on this later).

Similar to the Service application, the service in the Client application is hosted inside a Windows application to start and stop the service:

C#
private void button1_Click(object sender, EventArgs e)
{
    myServiceHost = new ServiceHost(typeof(CreditLimitResponseService));
    myServiceHost.Open();
    MessageBox.Show("Service Started");
}


private void button2_Click(object sender, EventArgs e)
{
    myServiceHost.Close();
    MessageBox.Show("Service Stoped");
}

Finally, the configuration of the Client application is shown below:

13.JPG

The above configuration is similar to the Service configuration. Note the usage of the “responsequeue” private queue which will receive the messages sent to the client.

Step 4: Generating the Proxies

OK, so now, we have created a Service application and a Client application. The Service application has a service contract and an operation defined which allows the Client to ask for the credit limit. The Client application on the other hand has also a service contract and an operation defined which allows the Service to send the response back to it. That’s cool, but how will the whole scenario happen?

Step 4.1: Service Proxy

First, we want the Client to send the request to the Service, so we need to generate a proxy at the Client application. Go ahead and run the Service application, and click on the button “Start”; the service will start as shown below:

2.JPG

Now, go to the Client application and add a Service Reference to the Service as follows (note, using the base address of the Service configuration file):

3.JPG

Now, we can use the generated proxy to request the credit limit from the Service. The code below does just that:

C#
private void button3_Click(object sender, EventArgs e)
{
    CreditLimitRequestClient proxy = new CreditLimitRequestClient();
    using (TransactionScope scope = 
           new TransactionScope(TransactionScopeOption.Required))
    {
        proxy.SendCreditLimitRequest("1");
        scope.Complete();
    }
}

Step 4.2: Client Proxy

Now, we want to add the code which will return the result back to the Client. Recall that the Client has exposed a service contract, so we will deal with it as a normal WCF service.

Run the Client application, and click on the “Start” button to start the service as shown below:

4.JPG

Now, go to the Service application and add a Service Reference to the Client as follows (note, using the base address of the Client configuration file):

5.JPG

Now, you can use the generated proxy to pass the result back to the Client application by updating the service contract. The full code of the service updated is shown below:

C#
public void SendCreditLimitRequest(string id)
{
    double value;

    if (id == "1")
        value = 10;
    else if (id == "2")
        value = 20;
    else
        value = 0;

    CreditLimitResponseClient proxy = new CreditLimitResponseClient();
    using (TransactionScope scope = 
           new TransactionScope(TransactionScopeOption.Required))
    {
        proxy.SendCreditLimitResponse(value);
        scope.Complete();
    }
}

Running the Sample

Now, to the fun stuff! Let's run the sample and examine the WCF queued messaging in action.

Run the Client application, and start the service by clicking on the “Start” button. Now, send a request to the Service by clicking on the “Send” button.

6.JPG

Note that we have yet to run the service of the Service application. As such, the message sent from the Client won’t be able to reach the Service. Where to find it? You guessed right… go to MSMQ and examine the “requestqueue” to find the message waiting there.

7.JPG

Now, we want to run the Service application in order to pick up the message; however, just before that, stop the service of the Client application by clicking on the “Stop” button… Stopping the Client application will allow us to view the response in the "responsequeue" since the Client won't be ready to pick it up.

Now, run the Service application and click on the “Start” button.

8.JPG

Go back to MSMQ, and you will find that the message has been successfully consumed by the Service application and it’s not in the “requestqueue” anymore:

9.JPG

However, recall that we have turned off the Client application. As such, the response which is supposed to be sent from the Service to the Client will also be pending in the “responsequeue”. Validate this by examining the MSMQ again:

10.JPG

Now, finally, go back to the Client application and start the service again. Immediately, the Client will pick up the message from MSMQ (it will disappear from the “responsequeue”), and you will get a message box displaying the result as an indication that the Client has received the response:

11.JPG

That’s message durability at its best!

What MEP We Just Used

Although it might seem a little bit odd, after all the work we have just done, we have only used the One-Way MEP. Recall that all operations are tagged with IsOneWay = true. After all, both the Service and the Client have exposed MSMQ bindings to talk to each other in a One-Way manner.

What about Public Queues?

This sample used the private MSMQ queues for implementation. As stated previously, queues can also be public, in which case, the Service and the Client can be on two different machines.

Our program won’t change when using public queues. Assume that the Client and Service from our sample are running in two different machines; in such a case, the scenario would go as follows:

  • The client will send a request to the Service. The request will “sit” in a private queue generated by MSMQ in the same machine.
  • This middle-queue will then send the request to the public queue we created on the other machine. The request is then picked by the Service application from there.
  • The opposite holds when the Service is communicating with the client.

Sample Program

You will find the solution attached which contains both the Client and the Service applications.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Architect
Lebanon Lebanon

Comments and Discussions

 
QuestionPerfect article Pin
Oleksiy Sokolovskiy10-Dec-20 12:21
Oleksiy Sokolovskiy10-Dec-20 12:21 
QuestionGreat article.... Pin
jithu891115-Sep-13 4:03
jithu891115-Sep-13 4:03 
SuggestionCode Hands on suggestion Pin
Malhotra Sameer24-Feb-13 4:43
professionalMalhotra Sameer24-Feb-13 4:43 
QuestionNot working Pin
pathak vikash16-Nov-12 1:30
pathak vikash16-Nov-12 1:30 
GeneralMy vote of 4 Pin
Vinod Kumar Gupta3-Apr-12 21:05
Vinod Kumar Gupta3-Apr-12 21:05 
GeneralGreat Article. Pin
argupta8219-Dec-10 11:35
argupta8219-Dec-10 11:35 
GeneralGood, but wrong on Public/Private Queues Pin
Member 98697317-Aug-10 3:36
Member 98697317-Aug-10 3:36 
GeneralGreat Article Pin
Sgt Mike25-May-10 13:05
Sgt Mike25-May-10 13:05 
GeneralGood article, but it lacked organization Pin
angstrey16-Mar-10 8:38
angstrey16-Mar-10 8:38 
GeneralGood article Pin
BigTuna16-Mar-09 11:32
BigTuna16-Mar-09 11:32 
GeneralRe: Good article Pin
mohamad halabi16-Mar-09 15:36
mohamad halabi16-Mar-09 15:36 
GeneralNice and Simple Article Pin
Saki Sachin16-Mar-09 10:51
Saki Sachin16-Mar-09 10:51 
GeneralRe: Nice and Simple Article Pin
tosh_oracle17-Aug-09 23:12
tosh_oracle17-Aug-09 23:12 
Hi,

I get the following error when I run the service

Service 'MSMQService.CreditLimitRequestService' has zero application (non-infrastructure) endpoints. This might be because no configuration file was found for your application, or because no service element matching the service name could be found in the configuration file, or because no endpoints were defined in the service element.

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.