views:

66

answers:

4

My program is successfully using .NET's MessageQueue class to read from an MSMQ. The queue is user configurable, and is sometimes on the local machine, and sometimes on a remote machine. The user can specify the remote machine either by name or IP address, and the queue name (and I'm only using "Private" queues).

I want to display to the user how many messages remain in the Queue, but haven't found a way to do this. The MessageQueue class does not seem to have a Count (or similar) property to give this to me easily.

I've been able to use the PerformanceCounter and PerformanceCounterCategory classes to get the count - but this only seems to work for me on the local machine (although I'm not completely sure I'm using these classes correctly).

My question is how to read the Count (number of messages) from an MSMQ on a remote machine?

A: 

This may be a solution for you: http://jopinblog.wordpress.com/2008/03/12/counting-messages-in-an-msmq-messagequeue-from-c/

Dr. Wily's Apprentice
Looks promissing. I'll have to try it.
Andy Jacobs
I tried a few methods on this page but kept getting System.Messaging.MessageQueueException with System.Messaging.MessageQueueErrorCode.RemoteMachineNotAvailable (even though the queue object seems to be able to actually read objects). I believe the methods on that page are intended for reading the local queue (which I already have working) - I'm trying to find a technique to read the count of a remote queue.
Andy Jacobs
Hmm, sorry that didn't work out for you. The gist of what I got from that page was that the method would count the messages in the queue by using a cursor to peek through all of the messages. It didn't seem like an ideal solution, since it was doing a lot of unnecessary reading, but it seemed like a potential solution. As you mentioned, perhaps that method of reading from the queue just doesn't work remotely.
Dr. Wily's Apprentice
A: 

This might be overkill, but you could possibly put a WCF service on the same machine hosting your queue, so you'd be able to retrieve the count using the performance counters in the WCF service and expose that functionality through a method of that service.

Dr. Wily's Apprentice
A: 

I would like to say several things here.

  • Before I get to my own answer, I would like to comment John Opncar's solution (in Dr. Wily's Apprentice answer). His code does work on remote machines. I used his code in our project at work to watch the queues on a remote cluster server and it works very well.

  • So, if get "RemoteMachineNotAvailable" errors, please check your configurations. Are all machines in the same network or - not to forget - are the queue's security permissions on the remote machine set up to allow others to read them? Do the users/ accounts have sufficient rights to read from other systems?

For example, we had to allow everyone on the clustered queues.

  • As far as I know the PerformanceCounters do indeed have problems to read message properties on remote machines. I tried to use them for queues in a Windows Server cluster environment, but was never able to get it working. I did some internet research at that time, but unfortunatelly I do not recall if this is due to security reasons or simply a bug. :-(

  • Now to the actual answer. If you do not like the Cursor-Method as described by John Opincar you could also use the MessageQueue.GetAllMessages() or MessageQueue.GetMessageEnumerator methods.

I never tried GetMessageEnumerator, but I can say that I would not recommend GetAllMessages().

We suffered from heavy performance issues when using it every second on a system with several queues that contain several thousands of messages. The method takes a snapshot of all messages in the queue, which can cause heavy loads in memory and network.

The cursor-methodis still somewhat slow. But, at least in our production environment, it feels more snappy than with the GetAllMessages() solution.

If counting the messages in your scenario does not need to be as often as one second and you have less messages to count than we do, then working with GetAllMessages() or GetMessageEnumerator() might be a possible solution for you.

Finally, it always comes down to your own individual needs.

Sensei76
Thank you for your additional input. It is possible that I made a mistake in my implementation (and I did have to convert the code to VB just in order to try it). But I know that we've set the queue to be readable by other machines. In fact, I thought I was calling the message counting code on the same object which was successfully reading messages from the remote queue. And I can display the remote queue size in Perfmon on the other machine.
Andy Jacobs
Also, my queue size is often over 10,000 (and sometimes over 1,000,000), so I'm also very skeptical that GetAllMessages would work for me. I'm even skeptical that the other methods will work in a reasonable amount of time (e.g., so I could display the new count every second). I'm just really surprised this is so hard - especially since Perfmon seems to do it, etc., and .NET could have just added a Count method to the class...
Andy Jacobs
A: 

The most reliable solution for getting the count of messages in a local queue is to use the MSMQ APIs using P/Invoke. There's a nice article here: Counting the number of messages in a Message Queue in .NET.

I don't know if it works with remote queues, but I wouldn't rely on it. Generally, the only thing you should do with a remote queue is to send a message. Trying to read messages or properties from a remote queue should be avoided, if possible. "Send remote and read local" will always give you the best performance and avoid all kinds of problems (e.g., what if the remote machine isn't available?)

bfallin
Looks promising - I'll give it a try when I get a chance. Thanks.
Andy Jacobs