Welcome to MSDN Blogs Sign in | Join | Help

MSMQ, WCF and IIS: Getting them to play nice (Part 3)

Previously, in MSMQ, WCF and IIS: Getting them to play nice:

  • In Part 1, we built a client and IIS-hosted service application and got them communicating over MSMQ using WCF's NetMsmqBinding.
  • In Part 2, we deployed the same application across multiple servers, and enabled transport security for MSMQ.

In today's thrilling conclusion, we'll improve the resiliency of the solution by going transactional. Fasten your seat belts!

Going Transactional

Before we get started, let's spend a few minutes discussing the advantages and disadvantages of using transactional message queues. The advantages are all pretty nice:

  1. Messages will be delivered exactly once, and in order.
  2. Messages are persisted to disk, so they won't be lost if a server goes down.
  3. Sending and receiving messages can take place within a transaction. I've found this most useful on the receiving side: if you create a single transaction that encompasses both receiving the message and processing it, and a failure occurs during processing, the entire transaction will be rolled back. This means the message will be returned to the queue, rather than lost.

At this time you're probably thinking, "wow, that all sounds great - why wouldn't anyone want all of those?". The main reason is performance - using transactional message queues is typically many times slower than going with their non-transactional cousins. Also while the prospect of losing messages or getting duplicate messages sounds scary, in reality this would only happen under extremely rare and unfortunate circumstances. So the question here shouldn't really be "do you want the improved reliability that you get from transactional message queues", but rather "can you afford to live without it?".

That said, there are any number of scenarios where transactional message queues are justified - such as storing audit records, processing financial transactions or sending greetings in blog post samples. So let's get started!

Create a Transactional Message Queue

The first thing we need to do is create a shiny new transactional message queue. Even though we already have a non-transactional message queue with the correct name, you can't convert a non-transactional queue to a transactional one. So you'll need to unceremoniously delete the existing queue, and create a new private queue, still called MsmqService/MsmqService.svc. However this time make sure you select the Transactional checkbox.

Now, after all the effort we went through to set the ACLs on the previous queue, make sure you set them correctly on the new queue to avoid more painful permissions problems!

Reconfigure your WCF Bindings

Once again, we'll need to modify the WCF configuration in both the client and service to use a new binding. This time we'll be using the MsmqBindingTransactionalTransportSecurity, which will be defined as follows:

<binding name="MsmqBindingTransactionalTransportSecurity" exactlyOnce="true" receiveErrorHandling="Move">
  <security mode="Transport"/>
</binding>

The exactlyOnce="true" attribute is WCF-speak for using a transactional message queue. The receiveErrorHandling attribute is only needed on the service side (although it won't do any harm on the client side). This tells WCF what to do in the event that it discovers a "poison message". Poison messages are an important concept with transactional message queues. As discussed previously, if an error occurs while processing a transactional message, the transaction will be rolled back and the message will be returned back to its queue - ready to be picked up again by the same service. If the error was caused by a temporary glitch, the message may be processed successfully the next time around. However if the problem was due to a malformed message or a persistent problem with the application, the message is going to fail over and over again. WCF and MSMQ 4.0 have joined forces to provide support for poison message detection and handling. If the same message fails a number of times (3, by default), it will be considered "poison". What happens next depends on the value of the receiveErrorHandling attribute. If you set it to "Move" (my favourite choice!), it will be automatically put onto a sub-queue called "poison" where it can be manually dealt with by someone else.

So with our new binding beautifully configured, make sure you modify the endpoint definitions to refer to the new binding configuration name, and you're ready to move forward.

Add Transaction Attributes to your Service Implementation

If we want go get the advantage of executing the message receiving and processing in a single transaction, you'll need to tell .NET to enlist your code in the existing MSMQ transaction. This can be done in a single line of code, by decorating your service implementation methods with [OperationBehavior(TransactionScopeRequired=true)].

So far my sample service has consisted of a single line of code. While simplicity is normally a good thing in samples, it's not going to give me any opportunities to check the transactional behaviour or poison message handling. In order to make the scenario a bit more interesting, I've added some code that will let me easily create a poison message. My service class now looks like this:

    public class MsmqService : IMsmqContract
    {
        [OperationBehavior(TransactionScopeRequired=true)]
        public void SendMessage(string message)
        {
            if (message == "Bad")
            {
                throw new InvalidOperationException("Bad!");
            }

            Trace.WriteLine(String.Format("Received message at {0} : {1}", DateTime.Now, message));
        }
    }

 

As I'm sure you can tell, whenever I send the message "Bad", my service will fail. This will cause a exception to be thrown, and the transaction will be aborted. As a result the message will be returned back to the message queue, ready to be picked up again. Since the message has not been changed, it will continue to fail twice more, after which WCF will decide the message is poison and move it to the "poison" sub-queue.

Check DTC Configuration

Our epic journey is almost at an end. In fact if you're still playing along at home, you can try running the application with the transactional queues to see if it's working. If it's failing, one possible cause is problems with your Distributed Transaction Coordinator configuration. Here are a few things to try:

  1. Make sure that the DTC service is installed and running on all servers. If you're running Windows Server 2008, the feature may not be installed by default.
  2. Check your DTC security configuration. Under Windows Vista, launch comexp.msc, then expand Component Services\Computers\My Computer\Distributed Transaction Controller\Local DTC. Under Windows Server 2008 this is slightly easier to find, in Server Manager. In both cases, right-click on Local DTC, choose Properties and go into the Security tab. The exact choice of options probably depends on your scenario, but a good start is to switch on "Network DTC Access", "Allow Remote Clients", "Allow Inbound", "Allow Outbound" and "No Authentication Required'.
  3. Make sure that you allow DTC traffic through any firewalls. Again, if you run into problems, a good starting point is to temporarily disable all firewalls so you can find out whether that's the source of your problems.

Conclusion

In the last three posts I've documented pretty well everything I've learned over the past few months about getting MSMQ, WCF and IIS 7 playing nice, both on single machines and across multiple machines. Even though it took quite a while to figure all of this out, I still believe the architecture is both extremely flexible and simple to use - the total amount of code in this solution really is tiny. My only real complaint is that there isn't a lot of help available, either in the tools or on the web, to explain why things don't always work first time or how to go about fixing them. Through this post, I'm hoping my team's experiences will make the path a little smoother for you.

Update: By popular demand (OK, one person asked!), source code for the finished project is attached to this post.

Posted by tomholl | 3 Comments
Filed under: ,

Attachment(s): MsmqWcfBlog.zip

MSMQ, WCF and IIS: Getting them to play nice (Part 2)

Welcome back! In Part 1 of this tale, we'd successfully configured a WCF client and an IIS-hosted service to communicate via MSMQ on the same machine. But we're only half done. As you may recall, our goal here is to deploy the client, service and queues all on separate machines. We also want to secure the configuration so that only or client is permitted to send messages to the queue.

Before we dive in, a quick disclaimer. As I mentioned in the first article, at the time of writing there is very little information about how to get this scenario working correctly. As such, we had to use a lot of trial and error. While I hope all of the tips in this article are correct and helpful, keep in mind that I don't have the time or resources to test everything in a clean environment. If any of this advice turns out to be incorrect or if I've missed anything important, please let me know and I'll correct the article.

Going Multi-Server With No Security

The next phase of this journey is to get all of the components running on their own servers, as shown in the diagram below (yes, it's the same one I included in part 1). Since getting everything working can be a little fiddly, we're going to continue to take baby steps so we won't be switching to authenticated or transactional messages just yet.

Install the necessary components and applications

To get started, make sure you have your three servers, and configure the necessary Windows components on each as described in part 1. Then deploy the client app on the client app server, create the message queues on the MSMQ server, and deploy the service in IIS on the service app server. Other than the fact that the boxes are different, there really isn't any difference in this step to what you did in the single-server scenario.

Allow anonymous users to send to the queue

The first difference between the single-server and multi-server scenario is that MSMQ will normally reject unauthenticated messages from remote machines. When you use set the security mode to "None" (or "Message") in the NetMsmqBinding, all messages will be deemed to be sent from a pretend user called ANONYMOUS LOGON. As such, you need to set the ACLs on the message queue to grant the ANONYMOUS LOGON account "Send Message" permission. This step had me stumped for ages - I had assigned permissions to the actual account that my client app was running under, yet all messages ended up in the Dead Letter Queue with an "Access Denied" message. Hopefully this tip will save you the same pain!

Change the service's BindingInformation to point to the MSMQ Server

Remember how we needed to configure IIS using appcmd.exe to listen to the MSMQ protocol? Well one part of the cryptic command syntax was bindingInformation='localhost'. The meaning of the bindingInformation attribute varies for each protocol, but for net.msmq this refers to the server that hosts the queues that IIS should be listening to. In our multi-server scenario we will be putting our queues on a separate server called msmqserver. First, let's switch off the localhost binding we configured last time. Note that the only difference in syntax for adding and removing a binding is the use of -+ versus --.

appcmd set site "Default Web Site" --bindings.[protocol='net.msmq',bindingInformation='localhost']

Now let's switch on the net.msmq protocol for our remote msmqserver:

appcmd set site "Default Web Site" -+bindings.[protocol='net.msmq',bindingInformation='msmqserver']

If you're not joined to a domain, here's a top tip from the MSMQ Activation Sample on MSDN: "To enable activation in a computer joined to a workgroup, both the activation service and the worker process must be run with a specific user account (must be same for both) and the queue must have ACLs for the specific user account."

Update the queue address in config files

Hopefully the final step will be to modify the queue address in the config files for your client and service applications. The only change should be to replace localhost with msmqserver, leading to a queue URI like net.msmq://msmqserver/private/MsmqService/MsmqService.svc.

Switching on Transport Security

Now that everything is working properly across multiple machines, let's start hardening the solution by turning on Transport Security. The NetMsmqBinding has four security modes: None (which we've been using up until now), Transport (which specifies that we should be using MSMQ's built-in security features), Message (in which WCF provides security at the SOAP level), and Both (which combines Transport and Message modes). In this scenario we will be using Transport security, as it enables to administrators to use the standard MSMQ security features. Most importantly it will allow us to lock down the queue so only the account running our client is authorised to send messages to the queue.

Enable MSMQ Active Directory Integration

If you haven't done so already, go to Add/Remove Windows Components and enable MSMQ Active Directory integration. Using AD is the easiest way to get Transport Security working. It is possible to use Transport Security without AD if you use custom certificates, but I won't discuss this approach in this article (mainly because I've never tried it :-).

Configure the WCF bindings

In order to switch on Transport Security, we'll need to configure a new WCF binding. (Alternatively you can just change the configuration of your existing binding, but I like to make sure each binding's name describes what it actually does). Transport is the default security mode for NetMsmqBinding, but in order to avoid confusion I also like to configure this explicitly:

<netMsmqBinding>
  <binding name="MsmqBindingNonTransactionalTransportSecurity" exactlyOnce="false">
    <security mode="Transport"/>
  </binding>
</netMsmqBinding>

This needs to go in both your client and server's configuration files. Of course, you'll also need to update your endpoints to use the new MsmqBindingNonTransactionalTransportSecurity binding configuration.

Configure MSMQ Security

This step sounds simple, and in your case it may be. However in my environment I found there were a number of tricks required (probably mainly because I was using non-standard service accounts for my client).

The simple bit is to make sure the account running your client has permission to send to the message queue. If you're running the client app under your own account, this is probably already set. Once you've checked or set the ACLs, try the application and see if it works. If so, congratulations - you're done! If not, keep reading.

One error that we saw when attempting to send to the queue was "An error occurred while sending to the queue: Unrecognized error -1072824273 (0xc00e002f).Ensure that MSMQ is installed and running. If you are sending to a local queue, ensure the queue exists with the required access mode and authorization.". If you get this, it probably means that there is no certificate in Active Directory for your specific user account on a specific server. I'm not sure if you need a certificate for all three servers in the scenario, but it's probably better to be safe than sorry. To register the certificate, do the following:

  1. Log on to the relevant server using the user account that you will be sending messages under
  2. Open the Computer Management (Windows Vista) or Server Manager (Windows Server 2008) console.
  3. Find the Message Queuing node, right-click and choose Properties.
  4. Click on the User Certificate Tab
  5. Click the Register... button, choose the appropriate certificate (normally "DOMAIN\Username, ServerName") and click Register.
  6. If your client is running in IIS 7 under a user account other than NETWORK SERVICE, modify the configuration of your App Pool to load the user profile. This appears to be necessary to allow the client to access the certificate needed to authenticate.

After you've done this, try again - and again, hopefully you're done. One other trick we found may be necessary is to add the machine account of the client app server into the AD domain group called "Windows Authorization Access Group" - this is described in this TechNet article. I'm not positive of the exact situations when this is necessary, but if all else fails I'd suggest giving this a try.

If you're still having troubles getting communication across the boxes, one final thing to check is whether any of the MSMQ traffic is being blocked by a firewall. I'd suggest temporarily turning off all firewalls across the various boxes to see if this is an issue.

Hopefully by now you'll have a secure, multi-server deployment of your WCF client, server and message queues. In the final instalment we will go one step further and switch over to transactional queues to ensure your messages don't ever go walkabout.

Posted by tomholl | 1 Comments
Filed under: ,

MSMQ, WCF and IIS: Getting them to play nice (Part 1)

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 Scenario

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.

  image

The Basics

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.

Install the necessary Windows components

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).

  1. Microsoft Message Queue (MSMQ) Server > MSMQ Server Core and MSMQ Active Directory Domain Services Integration (needed for Transport Security in Part 2)
  2. Microsoft .NET Framework 3.0 > Windows Communication Foundation Non-HTTP Activation
  3. Internet Information Services > World Wide Web Services
  4. Windows Process Activation Service
  5. Distributed Transaction Controller (DTC) - Always installed with Windows Vista, may need to be added for Windows Server 2008

Of course, you'll also want Visual Studio 2005 or 2008 installed so you can write the necessary code.

Define the contract

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.

    [ServiceContract]
    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.

Create the Message Queue

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.

Configure the Client

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" ?>
<configuration>
  <system.serviceModel>
    <bindings>
      <netMsmqBinding>
        <binding name="MsmqBindingNonTransactionalNoSecurity" exactlyOnce="false">
          <security mode="None"/>
        </binding>
      </netMsmqBinding>
    </bindings>
    <client>
      <endpoint name="MsmqService"
                address="net.msmq://localhost/private/MsmqService/MsmqService.svc"
                binding="netMsmqBinding" bindingConfiguration="MsmqBindingNonTransactionalNoSecurity"
                contract="MsmqContract.IMsmqContract" />
    </client>
  </system.serviceModel>
</configuration>

Configure the Service

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.

  <system.serviceModel>
    <bindings>
      <netMsmqBinding>
        <binding name="MsmqBindingNonTransactionalNoSecurity" exactlyOnce="false">
          <security mode="None"/>
        </binding>
      </netMsmqBinding>
    </bindings>
    <services>
      <service name="MsmqService.MsmqService">
        <endpoint address="net.msmq://localhost/private/MsmqService/MsmqService.svc"
                binding="netMsmqBinding" bindingConfiguration="MsmqBindingNonTransactionalNoSecurity"
                contract="MsmqContract.IMsmqContract" />
      </service>
    </services>
  </system.serviceModel>

Enable the MSMQ WAS Listener

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

Troubleshooting Steps

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.

  • Check queue permissions. Make sure that you've correctly set the ACLs on your message queue so that the user accounts running the client and service are able to send and receive respectively.
  • Check the dead letter queues. In many circumstances, MSMQ will send messages to the Dead Letter Queue (or Transactional Dead Letter Queue) if it couldn't successfully be delivered for any reason. Often the details on the dead letter message will explain why it ended up there (for example, you tried sending a non-transactional message to a transactional queue). If you're using MSMQ across multiple machines, make sure you check the Dead Letter Queues on all servers, as it could end up in different places depending on what caused the delivery failure.
  • Enable Journaling. Sometimes it can be hard to tell whether a message never arrived at all, or if it arrived and subsequently got "lost". If you enable the "journal" feature on a message queue, you'll see a record of every message that passed through. However use this feature sparingly, as you can very easily end up with a huge number of journal messages after a few hours of testing.
  • Shut down the service listener. When troubleshooting, it can be useful to focus on just the client or just the service. For example, if you aren't sure if the client is sending messages properly, you may want to completely disable the service so you can see if the client's messages are arriving on the queue. To do this, you can shut down the IIS service or application pool, or shut down the Net.Msmq Listener Adapter Service.
  • Make sure the MSMQ storage isn't maxed out. MSMQ is designed to be resistant against all sorts of failures, such as temporary network outages. However it seems that if you reach the limit of MSMQ's allocated storage, messages will not be delivered at all. This has happened to us a few times after large amounts of messages ended up in the Dead Letter Queue, or when journaling has been left on for too long. It's easy enough to increase the storage limit, but normally when you reach the limit during testing the best thing to do is purge all of your queues.
  • Try pinging the service using the browser. When you are working on WCF services exposed through HTTP, you're probably used to hitting the .svc file in a web browser to check that you can receive the metadata correctly and that there are no configuration problems. Unfortunately there isn't any equivalent way to "browse" to an MSMQ service, so simple configuration errors can be very hard to track down. However if you enable the HTTP protocol for your site, you will be able to hit the .svc file in the browser, even if you haven't configured an HTTP endpoint for your service. If you get the standard WCF service page, that means the service is probably configured correctly.

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.

Posted by tomholl | 8 Comments
Filed under: ,

Windows Media Center - Is it still just for geeks?

I was impressed with Windows Media Center from the very first time I tried it. However when we got our first Media Center PC a number of years ago, it was quite a trying experience getting it all set up. Getting the PC to talk to the cable set top box through the "IR Blaster", getting a decent quality picture from the US-bought PC into the Australian-bought TV via a PAL SCART connector, arguing with the zoom settings to get a 16:9 picture with no letterboxing, getting the sound card to output Dolby Digital over the SPDIF optical connector - all of these problems were ultimately solved, but all were painful enough that it wasn't at all surprising that the only people I knew with Media Centers were geeks.

Still when it worked, it worked very well - the interface was beautifully simple to use, it had the right set of features, and the ongoing subscription cost of zero was pretty hard to beat. So we stuck with it, upgrading the original box to Vista, successfully getting it working in Australia (despite the TV networks trying their hardest to prevent the availability of an Electronic Program Guide), and eventually replacing it with a newer snazzier box. Over time the experience has gotten steadily better, and lately it's required very little tender loving care to keep it running. It's still not perfect, but one telling fact is that my parents now have one up running. Granted my parents are geekier than most, but their tolerance for misbehaving technology is much lower than mine.

We recently moved to a new house with two living areas. The Media Center PC is set up in the lounge room, but we've been spending most of our time in the family room (mainly to keep our new kittens away from the new leather couches in the lounge room!). The problem with this arrangement is that in the family room we had to watch shows at the time they were actually scheduled - and after 4 years of not knowing when anything was scheduled this was pretty hard to take. So last week we decided to try out a Media Center Extender - we went with the Linksys DMA2100. If you're unfamiliar with Media Center Extenders, these are essentially small set top boxes that communicate with an existing Media Center PC over a wired or wireless network, giving you access to the same interface and content from a TV in another room. I'd read good things about the Linksys device, but many people warned that you really need a wired network or 802.11n to get decent quality video streaming. We're running 802.11g, but I was prepared to undertake a cabling job if necessary.

But here's the amazing part of the story - pretty well everything about the entire experience was flawless. I would have got everything up and running in about 10 minutes, except unfortunately it required that I upgrade the PC to Vista SP1. That said, it told me exactly what was wrong and what I had to do, and once the upgrade was done the boxes introduced each other and got along fine. The video streaming over 802.11g was a little choppy at first, but some slight rearranging of the router sorted that out. So now we have a Media Center in each room, thanks to a ~$240 box that so far has done everything it promised with practically no fuss. At this rate, we can only hope that Windows Media Center could be an option for people without even the slightest geekiest tendencies before too long.

Posted by tomholl | 1 Comments

Building a Pub/Sub Message Bus with WCF and MSMQ

In recent years there has been a lot of talk about event-driven architecture as a technique to build more scalable and maintainable systems. I've found this to be a very interesting pattern that makes sense in a number of scenarios, but it's never been very well supported on the Microsoft platform, and many who have attempted it have found it painful. A number of years ago I worked on a system using a pub/sub message bus built on .NET Remoting, MSMQ and HTTP, and it wasn't at all pretty. Everything was difficult and required custom code, from hosting the queue listeners, encoding and decoding messages, dealing with reliability and managing subscriptions.

So it was with some apprehension that I made another attempt to adopt this pattern in my current project. However a lot has changed in the last few years, and I'm pleased to say that my experience was many, many times better than the one I'd been through all those years ago. Before I get on to the solution, I want to make clear that I'm describing just one approach to implementing this pattern, and there are other approaches that may be more appropriate for applications with different requirements. Specifically the application I'm working on is a largely green-field .NET application, so interoperability across platforms was not a consideration (lucky me!).

The solution we ended up with was built with .NET Framework 3.0 and makes extensive use of Windows Communication Foundation (WCF), Microsoft Message Queuing (MSMQ) 4.0 and Internet Information Services (IIS) 7.0, all hosted on Windows Server 2008. Here's what we did.

Defining the Service Contract

The first step was to define the contracts which the publisher would use to notify any subscribers that an interesting event occurred. In our case we had a number of different types of events, but in order to reuse as much code as possible we used a generic service contract:

[ServiceContract]
public interface IEventNotification<TLog>
{
    [OperationContract(IsOneWay = true)]
    void OnEventOccurred(TLog value);
}    

Now for any given event type, we can simply define a data contract to carry the payload (not shown here), and provide a derived service contract type as shown below:

[ServiceContract]
public interface IAccountEventNotification : IEventNotification<AccountEventLog>
{
}

Implementing the Publisher

One of the key aspects of a publisher/subscriber pattern is that there should be ultra-loose coupling between the publisher and the subscriber. Critically, the publisher should not know anything about the subscribers, including how many there are or where they live. Originally we tried using MSMQ's PGM multicasting feature to accomplish this - essentially this lets you define a single queue address that will stealthily route the same message to multiple destination queues. While this feature does work, it had a couple of limitations that made it inappropriate in our scenario. First, the only way to use multicast queue addressing with WCF is to use the MsmqIntegrationBinding, which is less flexible than the NetMsmqBinding. Second, multicast addressing only works with non-transactional queues, which would have had an unacceptable impact of the reliability of our system.

So we abandoned this option and decided to implement our own lightweight multicasting directly within the publisher code. While technically this breaches the golden rule of the publisher knowing nothing about the subscribers, the information about the subscribers is completely contained in a configuration file. This means we can add, change or remove subscribers before or after deployment with no impact on the application code.

We had already built a component we called the ServiceFactory (no relation to the p&p Web Service Software Factory) which is a simple abstraction for creating local or WCF instances via a configuration lookup. This component isn't publicly available, but you could easily substitute your favourite Dependency Injection framework and achieve similar results. In our case, the web.config for one of our web services may have its dependent services defined as follows:

<serviceFactory>
    <services>
        <add name="EmailUtility" contract="MyProject.IEmailUtility, MyProject" type="MyProject.EmailUtility, MyProject" mode="SameAppDomain" instanceMode="Singleton" enablePolicyInjection="false" />

       
<add name="SubsctiberXAccountEventNotification" contract="MyProject.Contracts.IAccountEventNotification, MyProject.Contracts" mode="Wcf" endpoint="SubsctiberXAccountEventNotification" />
        <add name="SubsctiberYAccountEventNotification" contract="MyProject.Contracts.IAccountEventNotification, MyProject.Contracts" mode="Wcf" endpoint="SubsctiberYAccountEventNotification" />
    </services>
</serviceFactory>

Previously we had used the ServiceFactory for creating individual instances, with code like this:

IEmailUtility email = ServiceFactory.GetService<IEmailUtility>();

 

As you can see from the configuration above, this would result in a singleton instance of a local class called EmailUtility being returned, but different configuration could result in a WCF proxy being returned instead. It was a simple matter to reuse this same ServiceFactory component to return all configured services matching a specific contract. We used this capability to build the NotificationPublisher class as follows:

public class NotificationPublisher<TInterface, TLog>
    where TInterface : class, IEventNotification<TLog>                    
{
    public static void OnEventOccurred(TLog value)
    {
        List<TInterface> subscribers = ServiceFactory.GetAllServices<TInterface>();

        foreach (TInterface subscriber in subscribers)
        {
            subscriber.OnEventOccurred(value);
        }
    }
}

With this class in place, all that is required for the publisher to publish event is to instantiate a NotificationPublisher with the appropriate generic parameters and call the OnEventOccurred method. Assuming we are using the IAccountEventNotification interface and the above configuration, this would result in the event being fired over WCF to the services defined by the SubscriberXAccountEventNotification and SubscriberYAccountEventNotification endpoints.

Configuring the Publisher

The final missing piece on the publisher side is the WCF configuration. As mentioned previously, we chose to use MSMQ to provide reliable, asynchronous message delivery. Programming with MSMQ used to be quite a painful experience, but with WCF the programming model is no different than for any other transport - all you need to do is configure the right bindings. In our case we chose the NetMsmqBinding, which provides full access to WCF functionality for core MSMQ features (as opposed to the MsmqIntegrationBinding, which provides richer MSMQ support at the cost of more limited WCF functionality).

Here's an example of the client-side WCF configuration.

<system.serviceModel>

    <bindings>
        <netMsmqBinding>
            <binding name="TransactionalMsmqBinding" exactlyOnce="true" deadLetterQueue="System" />
        </netMsmqBinding>
    </bindings>

    <client>
        <endpoint name="SubscriberXAccountEventNotification"
            address="net.msmq://localhost/private/SubscriberX/accounteventnotification.svc"
            binding="netMsmqBinding" bindingConfiguration="TransactionalMsmqBinding"
            contract="MyProject.Contracts.IAccountEventNotification" />

        <
endpoint name="SubscriberYAccountEventNotification"
            address="net.msmq://localhost/private/SubscriberY/accounteventnotification.svc"
            binding="netMsmqBinding" bindingConfiguration="TransactionalMsmqBinding"
            contract="MyProject.Contracts.IAccountEventNotification" />
      </client>
</system.serviceModel>

There's nothing too fancy in this - the key thing to note is the exactlyOnce="true" setting which is required for transactional queues. The other thing that my stand out is the unusual net.msmq:// addressing syntax, which is used by the NetMsmqBinding in lieu of the more familiar FormatName addresses. The queues themselves are private queues called "SubscriberX/accounteventnotification.svc" and "SubscriberY/accounteventnotification.svc". Why did I give the queues such silly names? Read on...

Hosting and Configuring the Subscribers

In the past, if building MSMQ clients was annoying, building MSMQ services was a nightmare. You had to build your own host (typically in an NT Service) or make use of the somewhat inflexible MSMQ Triggers functionality. You then had to do a whole lot of work to ensure your service didn't lose messages, and that it wasn't killed by "poison messages", which are messages that will constantly cause your service to fail due to a malformed payload or problems with the service.

Just like on the client side, WCF takes a lot of the hard work away on the service side - but it doesn't directly help with hosting the service and listening to the queue. Luckily this problem is solved beautifully by IIS 7.0 and Windows Activation Services (WAS), which is available on Windows Vista and Windows Server 2008. In a nutshell this enables IIS to listen to MSMQ, TCP and Named Pipes and activate your WCF service, just as IIS 6.0 does for HTTP. If this all sounds great, it is - but be warned that it can be a bit fiddly to set up.

First, you need to set up an "application" in IIS that points to your service, including the .svc file and the web.config file. This is no different to what you'd normally do for an IIS-hosted service exposed over HTTP.

Next, you need to create the message queue - you can do this with the Computer Management console in Vista or Server Manager in Windows Server 2008. The name of the queue must match the application name plus the .svc file name, for example "SubscriberX/accounteventnotification.svc" (this fact is unfortunately not well documented). Make sure you mark the queue as transactional when you create it, as you can't change this later. You'll also need to set permissions on the queue so that the account running the "Net.Msmq Listener" service (NETWORK SERVICE by default) can receive messages, and whatever account is running the client/publisher can send messages (NETWORK SERVICE by default, too).

Finally you'll need to configure IIS and WAS to enable the Net.Msmq listener for the web site, and for the specific application (make sure you've installed the Windows components for WAS and non-HTTP activation before you proceed!). The easiest way to do this is using appcmd.exe which lives in the \System32\InetSrv folder:

  • appcmd set site "Default Web Site" -+bindings.[protocol='net.msmq',bindingInformation='localhost']
  • appcmd set app "Default Web Site/SubscriberX" /enabledProtocols:net.msmq

With the IIS configuration in place, it's time to make sure the service's WCF configuration is correct. As you might expect, this looks pretty similar to the client configuration you saw earlier.

<system.serviceModel>
    <bindings>
        <netMsmqBinding>
            <binding name="TransactionalMsmqBinding" exactlyOnce="true" deadLetterQueue="System" receiveErrorHandling="Move"/>
        </netMsmqBinding>
    </bindings>

    <services>
        <service name="SubscriberX.NotificationService">
            <endpoint contract="MyProject.Contracts.IAccountEventNotification"
                bindingConfiguration="TransactionalMsmqBinding"
                binding="netMsmqBinding"
                address="net.msmq://localhost/private/SubscriberX/accounteventnotification.svc"/>
        </service>
    </services>  
</system.serviceModel>

One thing worth calling out here is the receiveErrorHandling="Move". This innocent-looking attribute probably saved us a month of work, as it tells WCF to move any messages that have repeatedly failed to be processed onto an MSMQ subqueue called "poison" and continue processing the next message, rather than the faulting the service. Note that subqueues, as well as the long-awaited ability to transactionally read from a remote queue, are some more new features in MSMQ 4.0 in Vista and Windows Server 2008.

Implementing the Subscribers

The only thing remaining is to implement the subscriber. Most of the code will of course be specific to the business requirements, so I'll only spend time describing the implementation of the service interface. In our system it is very important to make sure that no messages are accidentally lost. Since MSMQ can provide guaranteed delivery it may not be obvious how a message could just vanish. In fact most messages are lost after MSMQ has successfully delivered the message to the service. This can happen if the service receives the message and then fails before the message is successfully processed (possibly due to a bug or configuration problem). The best way of avoiding this problem is to use a transaction that spans receiving the message from the queue and any processing business logic. If anything fails, the transaction will be rolled back - including receiving the message from the queue! If the problem was a temporary glitch, the message may be successfully processed again. If the problem is permanent or caused by a malformed message, the message will be considered to be "poison" after several retries, and as mentioned earlier will be moved to a special "posion" subqueue where it can be dealt with manually by an administrator.

Making all of this work is surprisingly simple, since all of these capabilities are supported by MSMQ (provided you're using transactional queues) and WCF. All that you need to do is decorate your service implementation methods with a couple of attributes that state that your business logic should enlist in the transaction started when the message was pulled off the queue.

public class NotificationService : IAccountEventNotification
{
    [OperationBehavior(TransactionScopeRequired = true, TransactionAutoComplete = true)]
    public void OnEventOccurred(AccountEventLog value)
    {
        // Business-specific logic
    }
}

Conclusion

While this has been one of the longer blog posts I've done in a while, the solution is extremely powerful and surprisingly simple to implement thanks to some great advances in WCF, MSMQ and IIS. In the past, many people (including myself) have spent months trying to implement pub/sub patterns, often with less-than-spectacular results. But using these new technologies eliminates huge amounts of custom code - in fact the few code and configuration snippets in this post are really all that it takes to make this work.

Posted by tomholl | 15 Comments
Filed under: ,

Enterprise Library 4.0 - Get it while it's hot!

It's almost exactly a year since I handed in the keys to the Enterprise Library bus, but I'm still as excited as ever about the release of a new version. The team has just released Enterprise Library 4.0, which features all of the blocks you know and love updated for Visual Studio 2008, plus the shiny new Unity Application Block for dependency injection. As always, you can grab the new release from http://msdn.microsoft.com/entlib and participate in the thriving community at http://codeplex.com/entlib.

Congrats to the entire team for another great release:

  • Product Management: Grigori Melnik
  • Program Management: Scott Densmore, William Loeffler, Chris Tavares, and Grigori Melnik
  • Architecture: Chris Tavares, Scott Densmore  and Fernando Simonazzi
  • Development: Chris Tavares, Fernando Simonazzi, and Nicolas Botto
  • Test team: Hanz Zhang, Carlos Farre, Rohit Sharma, Naveen Guda, Pooja Parate, Pravin Pawar, Ronita Acharya, Sai Pasumarthi Venkata Appaji Sirangi and Vijaya Janakiraman
  • Documentation: Alex Homer
  • Edit team: Nelly Delgado, RoAnn Corbisier and Tina Burden McGrayne

Also thanks to everyone who worked on past releases who helped build such a strong foundation, and of course to everyone in the community who has supported this initiative and provided invaluable feedback.

Here's a summary of the official release notice from Grigori's blog:

What’s New in v4.0?

This release of Enterprise Library includes the following:

  • Integration with the Unity Application Block
  • Windows Management Instrumentation (WMI) 2.0 support and improved instrumentation
  • Performance improvements (particularly, in the Logging Application Block)
  • Pluggable Cache Managers
  • Visual Studio 2008 support
  • Bug fixes

Note: existing public APIs (v3.1) are still supported.

The Application Block Software Factory and the Strong Naming Guidance Package are not included in this release but are available as a separate download. Thus, there is no longer a dependency on Guidance Automation Extensions (GAX).

For the detailed list of all changes, see About This Release of Enterprise Library.

Enterprise Library by Numbers:

2003

Year when the first application block was released

2005

Year when v1 of Enterprise library was released.

1,290,000

Total number of downloads of Enterprise Library since the first release.

»470,000

Total number of visits to the community site (since Dec 2006 when the Codeplex site was launched)

»1,600

Number of discussion threads on the community site

54%

NPS (Net Promoter Score)

6

Number of Enterprise Library releases (v1.0, v1.1, v2.0, v3.0, v3.1, v4.0)

9

Number of Application blocks in Enterprise Library 4.0