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:10.10.10.10\\PRIVATE$\\Queue Name";
MessageQueue sourceQueue = new MessageQueue(queueFormatName, QueueAccessMode.ReceiveAndAdmin);


(Note the 10.10.10.10 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).








7 comments:

  1. Interesting article, I've been trying to do the same for quite a while, but without success.

    Actually, if I copy your example, I get "Format Name is invalid", because I think you forgot a "TCP:" in the string. Issue is, if I put the missing TCP (i.e. "DIRECT=TCP:10.10.10.10\private$\Queue Name") I end up connecting to the receiving queue.

    In short, I haven't been able to connect to an Outgoing Queue no matter what. Is there anything in particular I should be checking? Thanks.

    ReplyDelete
  2. Hi,

    Thanks for the comment, Diego. You are correct, I left out the TCP: by accident. I have updated the post so it is correct now.

    So long as I run this on the PC where the outgoing queue is located, and as an administrator, and with the specified security option it seems to work fine. I'm not sure what your problem might be.

    If you send me some sample code then perhaps I could take a look at it for you.

    Good luck !

    ReplyDelete
  3. It worked very well for me. Thanx.

    ReplyDelete
  4. Thanks for leaving a comment, I'm glad the post helped.

    ReplyDelete
  5. Hi,

    Please help.

    I am working on one production issue where web service sends messages to a remote queue on remote server. As remote server is not physically located in the office I use RDC to connect to it. After connecting to the remote server, I am not able to see private queues where web service sends messages although all apps are running fine.
    I also ran WireShark to make sure that it is sending messages to that server and respective message queue.
    Why I am not able to see Private Queues on the remote server?

    ReplyDelete
  6. Hi,

    I'm afraid I haven't seen that symptom before, and do not know why you can't see the queues. I assume when you say you can't see them you mean you are looking for them with the MSMQ Explorer app in computer management ?

    My best guesses are;

    1. Some kind of security issue (are you an administrator on the remote machine ?) preventing you from seeing the queues because you don't have permission.

    2. You're not RDPed into the actual machine the queues are on.

    Sorry I can't be much more help.

    ReplyDelete
  7. Very nice. Thanks for the info on how to do this. It is much cleaner than having to deal with the COM api and having to write interop code.

    ReplyDelete