Thursday, April 15, 2010

Accessing Outgoing Message Queues with C#

The point of sale application I work on, Ontempo Store, most commonly uses a Microsoft Message Queue (MSMQ) based component for moving data between POS’, and POS’ and servers. We’ve also decided to use ‘recoverable’ messages within MSMQ to provide an added layer of robustness on top of our own data transfer layer.
This works great in normal circumstances, but sometimes situations crop up where a problem occurs. Sometimes a PC’s static IP changes for some reason (changes to the networking such as different VPN software or vendors, change in ISP, or the retailers IT department introduces a new numbering system for the IP addresses etc.). Sometimes the wrong IP address was configured initially (i.e the wrong address was entered into our configuration database before the POS PC was actually installed).Obviously if the machines are addressed by name (and the name itself hasn’t changed), and the network supports DNS this isn’t a problem, but often this isn’t the case. Most of our clients don’t have DNS supported on their store networks and so just use static IP addresses.
In these cases there are now messages ‘stuck’ in a queue for an address that doesn’t exist, and while we could resend the original data from our own system, it' would be much nicer to have the system detect the address has changed and automatically resend (or more correctly, move) the undelivered messages to the correct queue. This is a feature I’ve been working on for the next release. I managed to write all the code to detect the address changing, gather the new and old address values and notify the appropriate components in our own architecture. The only thing left to do was write the code inside the MSMQ transport component to move the messages from the old outgoing queue and into the new one. Putting the messages in the new queue is simple enough, just create the queue and send to it like any other… but getting the messages from the old outgoing queue so I could do this proved to be a bit more challenging.
Neither the Visual Studio help, nor anything I could find on the internet clearly showed me how to read messages from the local outgoing queues using C# and the .Net System.Messaging namespace objects. There was one CodeProject article that showed a very rough way of achieving this but required using the COM based library which I wanted to avoid.
Then I found this web page on Ingo Rammer’s blog which talked about purging local outgoing queues. He says that accessing the local outgoing queues is possible using the MSMQ Win32 API (and presumably COM library) but not when using the .Net System.Messaging objects. He then provides code for purging an outgoing queue using the Win32 API, and follows that code with this comment;
“(The secret here lies in MQ_ADMIN_ACCESS which tells MSMQ that you'd like to work with the "outgoing queue" for the specified remote queue.)”
Despite the fact his article claimed you couldn’t use .Net to access the outgoing queue I decided to try it anyway, by opening the queue with ‘admin’ access specified… and as soon as I did that, it worked fine. Here’s a sample of the line needed to open the queue;
string queueFormatName = "FORMATNAME:DIRECT=TCP:\\PRIVATE$\\Queue Name";
MessageQueue sourceQueue = new MessageQueue(queueFormatName, QueueAccessMode.ReceiveAndAdmin);

(Note the should be replaced with the relevant IP address, and Queue Name should be the actual name of your queue, but the rest of the format name should be as is).

The key is the second parameter (QueueAccessMode.ReceiveAndAdmin) which specifies the access type, which must include ‘admin’ access. Once I opened the queue this way I was able to peek and receive the messages from the outgoing queue without getting the ‘The format name is invalid’ error I got previously when I had just specified receive access (out of the good habit of only ever requesting the minimum amount of permission required). I’ve tried this on an outgoing queue for an address that doesn’t actually exist and it still works, so I’m definitely accessing the local outgoing queue and not the remote version… besides which, I can see the messages being removed from the old queue and put in the new one using MSMQ explorer when I refresh the queues messages lists.

I haven’t tried purging the outgoing queue like Ingo was trying, since it’s not a requirement for me, but I would assume it is possible if the queue is opened this way.

So thanks to Ingo for providing the information that lead me to a solution, and if you’re wanting to open an outgoing queue make sure you specify admin access when opening the queue.

UPDATE : 16/04/2010 – Note that you cannot read messages from the local outgoing queue if you do not have administrative rights (that is you are running under a Windows administrator account and if you are on Vista/Weven with UAC enabled the account has been elevated).