A few weeks ago I posted an article describing how my current team built a publish/subscribe message bus using WCF and MSMQ. At that time we had only deployed the application in a single-server test environment. While there were a few tricks to getting that working, once we tried deploying to a multiple server environment we found a whole lot of new challenges. In the end they were all quite solvable, but it seems that not a lot of people have attempted to use the MSMQ bindings for WCF, hosted in IIS 7 WAS, so there isn't a lot of help out on the web. The best source of information I'd found is an MSDN article, Troubleshooting Queued Messaging (which unfortunately I didn't find until after we'd already solved most of our problems). But even that article is a bit lacking, so I thought I'd share some of the things we learned about getting this all working.
The goal here is to set up reliable, asynchronous communication between a client application and a service, which may be on different machines. We will be using MSMQ as a transport mechanism, as it supports reliable queued communication. MSMQ will be deployed on a third server (typically clustered to eliminate a single point of failure). The client application will use WCF's NetMsmqBinding to send messages to a private queue on the MSMQ server. The service will be hosted in IIS 7, and will use Windows Activation Services (WAS) to listen for new messages on the message queue. This listening is done by a Windows Service called SMSvcHost.exe. When a message arrives, it activates the service within an IIS worker process, and the service will process the message. The overall architecture is shown in the following diagram.
Let's start simple by setting everything up on a single server, with no security or transactions to complicate things. This first instalment is a bit of a recap of my earlier post, but I'm including it again here as it will be an important foundation for the more complex steps shown in the next instalments.
Before writing any code, make sure you're running Windows Vista or Windows Server 2008, and that you've installed the following components (I've taken the names from Vista's "Windows Features" dialog; Windows Server 2008 has slightly different options but all should be there somewhere).
Of course, you'll also want Visual Studio 2005 or 2008 installed so you can write the necessary code.
As with all WCF applications, a great starting point is to define the service contract. The only real trick when building MSMQ services is to ensure that every operation contract is defined with IsOneWay=true. In my example we'll have just one very simple operation, but you could easily add more or use more complicated data contracts.
public interface IMsmqContract
[OperationContract(IsOneWay = true)]
void SendMessage(string message);
I won't bother with showing any sample client code to call the service, as this is no different from any other WCF client.
Message Queues don't just create themselves, so if you want to build a MSMQ-based application, you'll need to create yourself some queues. The easiest way to do this is from the Computer Management console in Windows Vista, or Server Manager in Windows Server 2008.
In general, message queues can be called whatever you want. However when you are hosting your MSMQ-enabled service in IIS 7 WAS, the queue name must match the URI of your service's .svc file. In this example we'll be hosting the service in an application called MsmqService with an .svc file called MsmqService.svc, so the queue must be called MsmqService/MsmqService.svc. Queues used for WCF services should always be private. While the term "private queue" could imply that the queue cannot be accessed from external machines, this isn't actually true - the only thing that makes a public queue public is that it is published in Active Directory. Since all of our queue paths will be coded into WCF config files, there really isn't any value in publishing the queues to AD.
In this first stage, we won't be using a transactional queue, so make sure you don't click the Transactional checkbox. Transactional queues can add some complexity, but they also provide significantly more reliability so we'll be moving to transactional queues later in the article.
At this time, it's a good idea to configure the security for the queue. You want to make sure that the account running the client is allowed to send messages to the queue, and the account running the service is able to receive messages from the queue. Since the service will be hosted in IIS, by default it will be using the NETWORK SERVICE account.
Now we know the name of the message queue, we can configure the client to send messages to the correct place. First you need to configure a suitable binding. We'll be using the NetMsmqBinding, which is normally the best option when both the client and service are using WCF. For now we will not be using and security or transactions, so we'll need to specify that in the binding (the exactlyOnce="false" attribute means it's non-transactional).
The endpoint definition is defined in the same way as any WCF client endpoint. One thing to look out for is the address syntax for MSMQ services. Rather than using the format name syntax that you may have used in other MSMQ applications, WCF has a new (and simpler) syntax. The key differences are that all slashes go forwards, and you use "private" instead of "private$". So the address for our locally hosted queue will be net.msmq://localhost/private/MsmqService/MsmqService.svc. Here's the complete config file for the client:
<?xml version="1.0" encoding="utf-8" ?>
<binding name="MsmqBindingNonTransactionalNoSecurity" exactlyOnce="false">
To create the service, start by setting up a new ASP.NET application, hosted in IIS - just as you would for a normal HTTP-based WCF service. This includes creating a .svc file for the service endpoint, and of course a class that implements the service contract. Again, I won't bother showing this code as it's not specific to MSMQ.
You'll also need to modify the service's web.config file to include the configuration details for your WCF service. Not surprisingly, this will look very similar to what we configured on the client.
<binding name="MsmqBindingNonTransactionalNoSecurity" exactlyOnce="false">
The last step is to configure IIS 7 to use WAS to listen to the message queue and activate your service when new messages arrive. There are two parts to this: first you need to activate the net.msmq listener for the entire web site, and second you need to enable the protocols needed for your specific application. You can perform both of these steps using either the appcmd.exe tool (located under C:\Windows\System32\Inetsrv) or by editing the C:\Windows\System32\Inetsrv\config\ApplicationHost.config file in a text editor. Let's go with the former, since it's a bit less dangerous.
To enable the net.msmq listener for the entire web site, use the following command. Note that the bindingInformation='localhost' bit is what tells the listener which machine is hosting the queues that it should listen to. This will be important when we want to start listening to remote queues.
appcmd set site "Default Web Site" -+bindings.[protocol='net.msmq',bindingInformation='localhost']
To enable the net.msmq protocol for our specific application, use the following command. Note that you can configure multiple protocols for a single application, should you want it to be activated in more than one way (for example, to allow either MSMQ or HTTP you could say /enabledProtocols:net.msmq,http).
appcmd set app "Default Web Site/MsmqService" /enabledProtocols:net.msmq
If all has gone to plan, you should be able to successfully send messages from the client to the service, and have the service process them correctly. However if you're anything like me, this probably won't work first time. Troubleshooting MSMQ issues can be somewhat of an art form, but I've listed a few techniques that I've found to be helpful to resolve issues.
That's it for the basics. In Part 2 of this article, we'll look at what's required to get this application deployed on multiple servers, and specifically focus on what you'll need to do for the security configuration.
PingBack from http://www.alvinashcraft.com/2008/07/12/dew-drop-july-12-2008/
.NET/C#/Functional Programming The very useful CR_Documentor 2.0 has been released with Sandcastle Preview
Previously, in MSMQ, WCF and IIS: Getting them to play nice: In Part 1 , we built a client and IIS-hosted
It better if there was a sample project with this.
EnjoyA nice series of articles by Tom Hollander Part 1 Part 2 Part 3   Enjoy ....
Raag - I've posted the finished sample code as an attachment to Part 3. Enjoy!
whilr trying to run the MsmqService Iam getting the following Error.
"The protocol 'net.msmq' is not supported"
Please giv me the solution.
And tell me the steps i need to do in the sample that u have attached with this Blog.
Thanks in Advance,
Bala - did you run the appcmd scripts to enable the net.msmq protocol for the web site and your specific application?
I had a problem with the appcmd command:
C:\Program Files\Microsoft Visual Studio 9.0\VC>appcmd set app "Default Web Site
ERROR ( message:Must use exact identifer for APP object with verb SET. )
What am I doing wrong?
Even if I do it for the whole site, I am getting that net.msmq is not supported:
C:\Program Files\Microsoft Visual Studio 9.0\VC>appcmd set site "Default Web Sit
SITE object "Default Web Site" changed
Server Error in '/' Application.
The protocol 'net.msmq' is not supported.
Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.
Exception Details: System.InvalidOperationException: The protocol 'net.msmq' is not supported.
I see now that you said, "Unfortunately there isn't any equivalent way to "browse" to an MSMQ service, so simple configuration errors can be very hard to track down. " So in the last reply, that's what I was trying to do.
After setting the whole site for net.msmq, I get messages in the MSMQ private queue. However, I don't think they are getting picked up by the service. I can't find a trace. Is it writing a trace somewhere? How can I tell if the service is getting the message?
Hi Sam -
Make sure you run both appcmd scripts successfully. The site-level one is required to enable the binding, and the app-level one to switch it on for that specific app. If you're getting a "protocol not supported" message it looks like you didn't successfully switch it on for the site.
If messages are not being picked up from the queue, then either your service isn't listening at all, or it's trying to listen but it's unable to receive for some reason (eg permissions). If you switch on WCF diagnostics (the normal way, using the <system.serviceModel><diagnostics> section) you may get some clues. If nothing is logged, it means the service may not be listening at all.
First thank you for such work, as hosting in WAS is not so frequent...
I have the same effect Sam has. Using sample adapted to fit Part I, my queue is filled, but nobody pick up the messages.
So I followed your "troubleshooting" section and activate http to check WCF config.
And funny part, when I browse the svc, the website starts running and ... the messages are picked up, trace.log generated and messages disappeared from the queue ! wonderful !
Each time I recycle the queue, or restart the website, I have the same effect: need to browse the svc to start the pumping mechanism.
I certainly miss something....
Thanks a lot if you have an idea...
Sam, do you notice the same effect ?
Tonight's slide deck is up here . After the presentation, Steve Andrews was kind enough to come all
Laurent - this probably means that the net.msmq listener service doesn't have permission to peek from the queue. The service itself is able to receive the messages, but it can't be woken up by the net.msmq listener. Make sure that the account that the net.msmq service runs under (NETWORK SERVICE by default) has the necessary permissions.