WCF and MSMQ

It’s been a while since I blogged about one of my favorite topics, Windows Communication Foundation.

In this article I’ll explain how you can use MSMQ with WCF to really process messages asynchronously. It’s unbelievable how easy this is. Read my complete WCF series on how to set up your first service. The idea in this example is that we have to send some e-mails, but we don’t want that to be done immediately.

We’ll setup the service with a Console Application. In another post we’ll host our service using a Windows Service.

1: Make sure MSMQ is installed.

WindowsComponentsVista MSMQ must of course be installed. Check your Windows components to see if it’s installed. In Vista this is under “Control Panel” -> “Programs and Features” -> “Turn Windows features on or off”.

On the right you can see I’ve turned on everything. If it’s already installed you should be able to take a look at the queues. Right-click on the “Computer” icon and choose “Manage”. It’s under “Services and Applications”.

2: Setup a class library.

Create a new project and make it a class library. Add a really simple interface. Again, if you want to know the how and why, read my complete WCF series.

[ServiceContract(Namespace=“http://schemas.class-a.nl/msmq/example01/2008/02/”, SessionMode=SessionMode.NotAllowed)]

public interface ISendMail

{

  [OperationContract(Name = “SubmitMessage”, IsOneWay = true)]

  void SubmitMessage(MailMessage message);

}

Now we need an implementation for our service. In the code below I only output the message to the console. Normally you’d use tracing or logging for this, but in a bit we’ll build a console application to host everything.

public class SendMailService : ISendMail

{

  public void SubmitMessage(MailMessage message)

  {

    Console.WriteLine(“To      : “ + message.ToAddress);

    Console.WriteLine(“From    : “ + message.FromAddress);

    Console.WriteLine(“Subject : “ + message.Subject);

    Console.WriteLine(“Body    : “ + message.Body);

  }

}

As you can see I’m transferring a MailMessage. Here’s the datacontract for it.

[DataContract(Name=“MailMessage”, Namespace=“http://schemas.class-a.nl/msmq/example01/2008/02/”)]

public class MailMessage

{

  [DataMember(Name=“ToAddress”, IsRequired=true, Order=1)]

  public string ToAddress { get; set; }

  [DataMember(Name = “FromAddress”, IsRequired = true, Order = 2)]

  public string FromAddress { get; set; }

  [DataMember(Name = “CCAddress”, IsRequired = false, Order = 3)]

  public string CCAddress { get; set; }

  [DataMember(Name = “BCCAddress”, IsRequired = false, Order = 4)]

  public string BCCAddress { get; set; }

  [DataMember(Name = “Subject”, IsRequired = true, Order = 5)]

  public string Subject { get; set; }

  [DataMember(Name = “Body”, IsRequired = true, Order = 6)]

  public string Body { get; set; }

}

That’s our service, let’s get to hosting

3: Create a host

In a next post I will explain hosting this WCF service in a Windows Service. For now, a Console Application will do. It’s also much simpler to debug and test our application that way. Add a new Console Application to your solution.

First thing we need to do, is make sure we have a queue. First create a reference to the System.Messaging assembly. Then past the following code in your Main() method.

string queueName = ConfigurationManager.AppSettings[“SendMailQueueName”];

 

if (!MessageQueue.Exists(queueName))

  MessageQueue.Create(queueName, true);

As you can see, we’re getting the SendMailQueueName from the configuration and if it doesn’t exist yet, we’ll create it. For the configuration, just download the complete solution.

Now just create a ServiceHost and open it.

Type serviceType = typeof(SendMailService);

using (ServiceHost host = new ServiceHost(serviceType))

{

  host.Open();

}

Beside the fact we’ve checked for existence of the queue using System.Messaging, we did nothing so far concerning MSMQ. The only thing noticeable is setting the operation as a OneWay operation.

4: Setting up the host configuration

Let’s have a look at the services configuration. We’ve configured a single service, based on the SendMailService. It as two endpoints, but one’s for exchanging metadata (MEX endpoint). As you can see from the binding and the address of the other endpoint, this is the first time we’re specifying that we want to use MSMQ. We’re using the NetMsmqBinding and a private queue for our service.

<system.serviceModel>

  <services>

    <service behaviorConfiguration=MetadataBehavior name=EmailService.SendMailService>

      <endpoint

        address=net.msmq://localhost/private/ClassA_SendMail

        binding=netMsmqBinding

        contract=EmailService.ISendMail

        bindingConfiguration=SendMailNetMsmqBinding />

      <endpoint

        address=mex

        binding=mexHttpBinding

        contract=IMetadataExchange />

      <host>

        <baseAddresses>

          <add baseAddress=http://localhost:8080/SendMail/ />

        </baseAddresses>

      </host>

    </service>

  </services>

</system.serviceModel>

Pay attention to the ‘behaviorConfiguration’ attribute on the service and my ‘SendMailNetMsmqBinding binding configuration’. The behavior configuration isn’t interesting, it’s just enabling the MEX endpoint to work. The binding configuration for the endpoint is slightly interesting. As you can see below I’ve set the security to ‘None’. That’s because my laptop isn’t attached to a domain. By default it’s on transport security, meaning it’ll use Active Directory integration, which won’t allow me to connect in my situation. You’ll get a nice :

Binding validation failed because the binding’s MsmqAuthenticationMode property is set to WindowsDomain but MSMQ is installed with Active Directory integration disabled. The channel factory or service host cannot be opened.

The deadLetterQueue attribute is Windows version specific, because I can only set it to custom on Vista and Windows Server 2008. No need for a custom created queue here, it’ll just group the messages in the dead-letter queue, so you’ll know they’re yours. Read this article on MSDN for more info.

<bindings>

  <netMsmqBinding>

    <binding name=SendMailNetMsmqBinding deadLetterQueue=Custom>

      <security mode=None />

    </binding>

  </netMsmqBinding>

</bindings>

5: Creating a client

Normally our client is calling the service directly. We can’t do that, but we can get the metadata from our service, because we’ve set up a MEX endpoint. Add a new console application to your solution and create a service reference to the service. You can add a service reference by starting your service WITHOUT debugging. This way the option isn’t disabled in your console client.

Now open the proxy code and insert a message!

static void Main(string[] args)

{

  SendMailClient svc = new SendMailClient();

 

  MailMessage msg = new MailMessage();

  msg.ToAddress = [email protected];

  msg.FromAddress = [email protected];

  msg.Subject = “Test mail”;

  msg.Body = “Wow, is this going to work?”;

 

  svc.SubmitMessage(msg);

}

Isn’t that extremely simple?! The only difference is in the configuration. This proves a lot of what’s WCF is in the configuration.

Test MSMQ by stopping the service and just running the client. You can see the message in MSMQ. Start your host and it should disappear almost immediately.

Download the solution for a complete view on what we’ve done.

You may also like...

23 Responses

  1. Sharad says:

    Hi

    Is it possible to set MSMQ message priority at client?

    Thanks

  2. Nope, that’s only possible with the msmqIntegrationBinding. But know what you’re choosing for when selecting that binding. Is it really neccesary to set message priority?

  3. Tom says:

    The download does not work. Great article.

  4. Dennis van der Stelt says:

    Tom, thanks for the comment… I’ll look into it.

  5. Thanks for the article. It’s a nice summary on the subject. Hosting a service in a windows service is also the thing I’m after (that is, in windows server 2003).

  6. stan says:

    if you dont have vista/4.0, how can you know which messages are your’s when playing back a dead letter queue?

  7. shool says:

    I have a MSMQ and service, but the problem is the service is not picking up the message from MSMQ, i tried different security settings in config file but not able to figure it out..What should i be doing in this situation?

  8. Dennis van der Stelt says:

    @shool : I really have no idea with the info you’re giving, although it could be security indeed. Have you tried setting everything open? All rights to “Everyone”, running as administrator, run everything locally?

  9. sam says:

    Which is the best binding to use for heavy automatically reading messages from queues msmqIntegrationBinding or NetMsmqBinding?

    Should your sample work in the same way if we change the binding from the config file?

  10. Dennis van der Stelt says:

    @sam, msmqIntegrationBinding is for communication with MSMQ and clients that don’t use WCF. For example when a client that was build 3 years ago, who puts messages into MSQM, you want to retrieve those messages with WCF, because WCF is just plain cool! πŸ˜‰ That’s where you’d use msmqIntegrationBinding.

    For everything else, use netMsmqBinding. I have no idea of the other one could possibly be faster, but I doubt it. The idea is that there are messages in MSMQ and both WCF or you would have to deserialize the messages.

    netMsmqBinding is extremely easy to setup, I’d always prefer that binding.

  11. Peter Karouzos says:

    hi

    been looking at your example. when I run the client with no host, no messages are added to the queue.

    Im running on Windows XP. Everyone and my account have full control on the queue. running everything locally.

    Any thoughts?

    Thanks

  12. Dennis van der Stelt says:

    @Peter : Does this mean that running _with_ host are processed? My first thought is that you’re not running via MSMQ but still directly. That’d mean the client would not be able to connect and would crash.

    If you’re running via MSMQ, the messages should most definitely show up in the queue, especially with the host turned off. When the host is on, it might process messages faster than you can see them coming in πŸ™‚

  13. laxman says:

    @Peter : If you want to view a list of messages going through the queue, you might want to enable the “Journal” property.

    @Dennis : I am looking at developing a WCF based snmp agent which runs as a windows service. The snmp manager was built using Java and targeted for the Solaris 10 platform. Any suggestions on the architecture of the application?

  14. Dennis van der Stelt says:

    @laxman : an SNMP agent in WCF? I had to look up what SNMP actually is! πŸ™‚

    But this means tweaking WCF from top to bottom and that’s a LOT of work. I’ve done some tweaking, but never add protocols, encoders, etc. like you seem to need.

    I also don’t think from the requirements you specify I can give suggestions for an architecture. Is it for all clients connecting to the WCF SNMP agent, etc, etc. A lot of questions. What WCF concern, just start writing the binding, encoder, etc. And if I were you, I’d look into WAS (Windows Process Activation Services) that’s hosted in IIS. Much more capabilities than Windows Services.

  15. Rajesh Gour says:

    Hi Dear,

    Your code is very easy to understand and this make me possible to implement WCF and MSMQ in my application. Now i have good idea how it’s going to work.

    Thanks

    Rajesh Gour

  16. Pete says:

    Dennis,
    Bail me out! I suggested an architecture to my company which I will explain in a second but only examples I am seeing are doing the opposite of what I suggested. Basically we have a master queue where tasks for different systems are dumped and processed on that server. The server is not able to handle the load so I suggested we use WCF to split out the tasks to different queues on different servers. Makes sense, right? Except every client/server example I have seen have the host receive the messages from different clients instead of vice versa. You input is greatly appreciated.

  17. Dennis van der Stelt says:

    @Pete:
    Either I am, or you are mixing things up. Or I’m just not understanding your problem! πŸ˜‰

    Anyway, first you talk about a master queue where tasks are put into from different systems, and they are processed by one server. If that’s not client-server, I don’t know what it is.

    On the other hand, you’re talking about client/server and that it is not what you’re using. So you might either be talking about some service bus, or publish subscribe. I highly doubt you’re talking about pub/sub. That’s where a system is publishing messages, without knowing who picks these up. WCF can’t handle this scenario, it’s probably best to look at NServiceBus for lightweight scenarios and BizTalk for expensive, hard to build en huge distributed scenarios. πŸ˜‰

    The other thing is some sort of ServiceBus where you put messages onto a bus and a random system picks up these messages. It’s kind of like Pub/Sub, only it’s not. That scenario is more about some pipeline that messages get thrown on, and they might be modified or extended or so and might even be routed to some other system.

    – WCF can do routing since version 4.
    – Pub/Sub it cannot do.
    – Load balancing it cannot do either, you’ll have to build it yourself using WCF4 routing, or better use an existing implementation for dedicated Network Load Balancing (NLB) software/hardware.

    If you want more info, you’ll have to explain your situation a bit more.

    You can also email me via the contact form on this blog.

  18. Pete says:

    Dennis,

    Many thanks for replying. Basically I am thinking to run a service on the machine that has the master queue. That server depending on the kind of message it is will send it to a different server. The client running on that machine will save it to the local queue on that server. That way I will be able to split the tasks between different servers. If there a new task that the main service need to delegate I want to be able to add a config with the message parameters and the destination server queue and the service should be able to dynamically send those tasks there. I might have bitten off more than I can chew ’cause I am not seeing any examples that will help me do this. Thanks again for replying. Looking forward to your expert opinion.

  19. Pete says:

    Dennis,
    Please help me out. Here is my question rephrased :
    # I have a master queue (msmq) on Server A
    # I need to configure WCF to take messages depending on what kind they are and send them to different servers to split the load.
    # From the examples I am seeing this should require very little code. Problem is WCF abstract away a lot of code by providing configuration options in web/app.config. Problem is the WCF “host” that is running on Server A has to be able to send different messages to different servers (endpoints?). I am not sure if one service could have different endpoints. If this is not possible or too complicated maybe I would run multiple instances of this service each with a different endpoint all reading from the same queue.
    # All the examples I am seeing are of the “host” receiving the messages from clients on different servers. Am I doing something wrong?
    # I am also confused about WAS. What is it exactly? I know it is a feature in Windows Vista and all subsequent OSes. Does this mean I can’t run the sample on Win XP with IIS 6?

    Thanks

  20. S Kumar says:

    I need to set priority for the message. I tried with MSMQIntegrationBinding , but I can set the message priority but I am not getting the messages as per their priority level.

    At the receiving queue I am creating that with priority option opened like this
    MessageQueue q = new MessageQueue();
    q.MessageReadPropertyFilter.Priority = true;

    Even though i could not get the messages based on their priroity.
    Any help.

    thanks,
    – Kumar

  21. Tomek says:

    My jaw just dropped, this is awesome !!!
    Although I was trying to recreate everything (classes and apps) from article (I don’t like just running solutions) and there was nowhere mentioned needed references to System.Messaging etc.
    Great article, keep up good work.

  22. Joe says:

    This works great, but I have one question:

    Currently, the host takes the message out of the queue before the service’s method has finished running. Is there a way to make it so that the message queue transaction only completes after the service’s method has completed successfully?

    Thank you so much for the tutorial, helped me a ton!

    -Joe

  23. Dennis van der Stelt says:

    I’m not sure if I understand you correctly. You mean that the service takes out the message, the transaction fails, the message should still be in the queue, but it’s gone already???

Leave a Reply

Your email address will not be published. Required fields are marked *