Counting Messages in an MSMQ MessageQueue from C#

Surprisingly, this not as easy as MessageQueue.Count; When I searched for how to do this, I kept seeing solutions that required use of COM interop or Performance Counters. I didn’t really like either of those suggestions so I figured I’d just try Peek with a cursor. I was pleasantly surprised to find that this method was more than adequate for my needs. I ran this against a queue with 1000 (relatively small) messages and, including the time to open the queue, this took only 0.04 seconds. I was using private, transactional queues. I haven’t tested any other scenarios. But for my needs, this worked fine.

protected Message PeekWithoutTimeout(MessageQueue q, Cursor cursor, PeekAction action)
{
	Message ret = null;
	try
	{
		ret = q.Peek(new TimeSpan(1), cursor, action);
	}
	catch (MessageQueueException mqe)
	{
		if (!mqe.Message.ToLower().Contains("timeout"))
		{
			throw;
		}
	}
	return ret;
}

protected int GetMessageCount(MessageQueue q)
{
	int count = 0;
	Cursor cursor = q.CreateCursor();

	Message m = PeekWithoutTimeout(q, cursor, PeekAction.Current);
	if (m != null)
	{
		count = 1;
		while ((m = PeekWithoutTimeout(q, cursor, PeekAction.Next)) != null)
		{
			count++;
		}
	}
	return count;			
}

Enjoy.

About these ads

41 Responses to “Counting Messages in an MSMQ MessageQueue from C#”

  1. Stuart Clark Says:

    How about you use the MessageQueue.GetAllMessages() method which returns an Message[] then check the size of the array.

    Message[] messages = q.GetAllMessages();
    int count = messages.Count;

  2. jopincar Says:

    Two reasons. First, that will remove the messages from the queue. I just want a count. Second, if the messages were at all large, I would have to put the entire contents of the queue in memeory using this technique.

  3. jopincar Says:

    That last sentence isn’t clear now that I read it (if only you could edit comments). What I meant to say is that if the messages in the queue were large and/or there were a lot of them, I would have to allocate enough memory to hold the all of the messages, which would make getting the count much slower and more RAM intensive than it should be.

  4. ETL Says:

    Most helpful. Thanks!

  5. Tani Says:

    I was also looking for a solution other than COM or Performance Counters. Then, found your post and this is exactly what I was looking for! Thanks a lot!

  6. Tani Says:

    By the way, as you commented above, GetAllMessages() actually does not remove messages from the queue.

  7. Nick Says:

    Cheers, came in handy!

  8. abraham Says:

    The code came in handy. The discussion above was quite useful too.

    Thank you John….& Stuart.

  9. Paul Says:

    Here is another way to do it that may be useful to some. I’m not sure if it has the same overhead that GetAllMEssages() does.

    private int GetMessageCount(MessageQueue q)
    {
    int count = 0;
    System.Messaging.MessageEnumerator me = q.GetMessageEnumerator2();
    while (me.MoveNext(new TimeSpan(0, 0, 0))){
    count++;
    }
    //Cursor cursor = q.CreateCursor();

    return count;
    }

  10. MarkJoel60 Says:

    This was a huge help!

    Works like a charm — thanks…

  11. Man Nguyen Says:

    Awesomely done!

  12. Oliv Says:

    Thanks for you solution. I Prefer to test the property MessageQueueErrorCode of the MessageQueueException than to test if the exception message contains the string “timeout”.

    catch (MessageQueueException messageQueueException)
    {
    if (messageQueueException.MessageQueueErrorCode != MessageQueueErrorCode.IOTimeout)
    {
    throw;
    }
    }

  13. newbieLeo Says:

    woww thank a lot,
    it’s really helpful
    xD

  14. Tim Franklin Says:

    Great! Thanks. I converted it to VB and refactored a bit but it did exactly what I needed.

  15. Magnus Says:

    Thanks alot! I tried the original solution first but when doing a lot of counts on several queues sequentially I received a MessageQueueException.InvalidHandle sometimes. With Pauls solution I have not yet received any such exception.

    • Sharmanimus Says:

      Hi Magnus

      This is a reply to an old post, but I had trouble finding it online so though i’d post it here in case others want the solution to that problem you mentioned. I had this when working on big queues. The solution is to add a line:

      queue.EnableConnectionCache = False

      (queue = your MessageQueue object)

      This tells MSMQ not to rely on its cache and prevents those exceptions you (and I) got.

  16. Robert Sharp Says:

    I discovered this may work for generally static queues, but if you have services using these queues while you count, you run into trouble.

    The GetMessageEnumerator2 method appears to work even in a queue that is actively being used by other services. Plus, this method has the added benefit of not returning a Message to you when you don’t care about the messages themselves.

    • jopincar Says:

      Robert, I’ve been using this technique in a high-volume, production scenario since I published this and have not had any problems.

    • Adrian Says:

      Robert is correct, you shouldn’t be using a cursor to count messages, especially where the same service or another service may be receiving/removing messages from the queue. Cursors have restrictions related to messages being removed. Instead you could use GetAllMessages().Length, but the key is you’ll want to use a MessageReadPropertyFilter in order to basically filter out all the data to keep the foot print small.

      countFilter = new MessagePropertyFilter();
      countFilter.AdministrationQueue = false;
      countFilter.ArrivedTime = false;
      countFilter.CorrelationId = false;
      countFilter.Priority = false;
      countFilter.ResponseQueue = false;
      countFilter.SentTime = false;
      countFilter.Body = false;
      countFilter.Label = false;
      countFilter.Id = false;

      • Ngan Menegay Says:

        Hi Adrian,
        Can you please provide the full code of how your method works? I’m sorry that I’m not that familiar with coding with MessageQueue. So should I just combine the below code with the snippet you provided above? I don’t understand the correlation between MessageReadPropertyFilter object and GetAllMessages method :-(.

        Message[] messages = q.GetAllMessages();
        int count = messages.Count;

        Thanks!
        Angie

      • Adrian Says:

        I’ve actually switched to performance counters to monitor queue sizes since on really large queues, even doing a filtered count has a large performance penalty. I do this in a Try/Catch and if an exception occurs I revert to using the GetAllMessages method. This is roughly the code that I use.

        private MessagePropertyFilter _messageCountFilter;

        public YourClass()
        {
        _messageCountFilter= new MessagePropertyFilter();
        _messageCountFilter.AdministrationQueue = false;
        _messageCountFilter.ArrivedTime = false;
        _messageCountFilter.CorrelationId = false;
        _messageCountFilter.Priority = false;
        _messageCountFilter.ResponseQueue = false;
        _messageCountFilter.SentTime = false;
        _messageCountFilter.Body = false;
        _messageCountFilter.Label = false;
        _messageCountFilter.Id = false;
        }

        public int GetQueueCount(string queueName)
        {
        //try the performance counters, more efficient
        try
        {
        PerformanceCounter performanceCounter = new PerformanceCounter();

        performanceCounter.CategoryName = “MSMQ Queue”;
        performanceCounter.CounterName = “Messages in Queue”;
        performanceCounter.InstanceName = string.Format(“{0}\\{1}”, Environment.MachineName, queueName);
        performanceCounter.MachineName = Environment.MachineName;

        CounterSample counterSample = performanceCounter.NextSample();
        System.Threading.Thread.Sleep(100);

        return (int) CounterSample.Calculate(counterSample, performanceCounter.NextSample());
        }
        catch (Exception ex)
        {
        Logger.Debug(ex.Message);
        }

        //if performance counters failed, then use MSMQ object, less efficient
        try
        {
        MessageQueue messageQueue = new MessageQueue(Environment.MachineName + “\\” + queueName);
        messageQueue.MessageReadPropertyFilter = _messageCountFilter;

        return messageQueue.GetAllMessages().Length;
        }
        catch (Exception ex)
        {
        Logger.Error(ex);
        }

        return -1;
        }

      • Patrick Says:

        Hi Adrian,

        Using the filter/GetAllMessages method of counting I occasionally run into:
        System.Messaging.MessageQueueException: Message that the cursor is currently pointing to has been removed from the queue by another process or by another call to Receive without the use of this cursor.

        This is occurring because I have another service receiving messages from the Queue while the count is happening.

        How do you avoid this in your systems?

    • Adrian Says:

      Here’s some detailed information regarding cursors and MSMQ.

      http://support.microsoft.com/kb/178516

      • jopincar Says:

        MS should implement a Count method. It shouldn’t take more than one line of code to effeciently determine how many items are queued. The code you posted is hardly intuitive (although it does seem reasonable). Have you used this technique in a high-volume, production situation yet?

        FYI — I have two services asynchronously accessing the queue on which I’m using the published code. These queues see 65-100K messages a day with bursts of 50 messages per second.

      • Adrian Says:

        You are correct, it shouldn’t take more than one line of code. That’s why I’m the only person that sees this. My other developers work off my framework class that simplifies a lot of the MSMQ complexities that Microsoft didn’t bother to take the extra small step to really make it a complete and friendly interface.

        The production situation I designed/developed processes
        about 10 million messages a day with bursts up to 500 messages per queue per server, so yes it’s high volume. It consists of various services inserting and removing for process, routing messages, as well as the monitoring of these queues.

        I only ran across your article looking for information regarding a minor performance counter issue that’s been annoying me for a while, but thought I’d share my knowledge.

        If you want to test it yourself, simply create a queue, insert 10,000 messages with a large enough Body content (say 4K) and compare the performance. Yes, in a production environment you wouldn’t be inserting 4K messages, it’s simply to illustrate the performance impact of using cursors vs GetAllMessages with a filter.

        Using a cursor it takes 370ms, while using the method I posted only takes 162ms. You can test with larger messages or more messages, but the results are pretty much always the same, it takes twice as long or more using the cursors since they duplicate the message, where as with GetAllMessages you can control what is read through the filter, thus eliminating the Body from being read/duplicated.

  17. Prateek Tiwari Says:

    This was really a very nice article. Now my problem is I want to access the server from my local machine because the server is not having VS so I have to develop the code in my local machine. The steps which I need to follow are as follows:
    1. Open the server.
    2. Count the no. of messages in the private queue.
    3. Show the count on my application page.
    So this way, I can show the real time figures in my app.
    Step 2 can be achieved by the above method.
    Please assist. Thanks.

  18. Sharmanimus Says:

    Jopincar’s code works well and used to be the best method, but you should probably use the enumeration method mentioned by Adrian nowadays, as Microsoft say that otherwise you can have issues with messages that are removed or added to the queue. YMMV however. Really stupid that there is no .Count method.

  19. Hyunseok Says:

    I tried using GetMessageEnumerator2().MoveNext() function.
    This is fastest way to counting MSMQ.

  20. Emil's Lost & Found Archive » Retrieving the message count for MSMQ queues Says:

    […] blog posts suggest iterating over messages (e.g. Counting Messages in an MSMQ MessageQueue from C#) or doing it using WMI. WMI is the best alternative in my opinion and if you want a quick way of […]

  21. Marty Says:

    Your code doesn’t work reliably.

    Call it multiple times on the same, unchanged queue and each time you call it, the result is 2 smaller than the last time.

  22. engg Says:

    Thanks jopincar. I need to read messages one at a time, without deleting them. While I read, new messages keep coming in the queue in high volume and frequency. Will this approach work then? Is it static similar to GetAllMessages() or is it dynamic similar to GetMessageEnumerator2()? I have been using GetAllMessages() as I would prefer static, but it has been giving problems lately

    http://stackoverflow.com/questions/11349050/sporadic-error-while-getting-all-messages-in-windows-messagequeue

    Thanks.

  23. Qureshi Says:

    Hi All,

    I am agree with Adrian solution, i just modify it for easy understand

    private static int MessageQueueCount(MessageQueue msMq)
    {
    var messageCountFilter = new MessagePropertyFilter
    {
    AdministrationQueue = false,
    ArrivedTime = false,
    CorrelationId = false,
    Priority = false,
    ResponseQueue = false,
    SentTime = false,
    Body = false,
    Label = false,
    Id = false
    };
    msMq.MessageReadPropertyFilter = messageCountFilter;
    return msMq.GetAllMessages().Count();
    }

    Please let me know, if is there any drawback of using this solution or a better way then this.

  24. Qureshi Says:

    I think developer can also add some more properties to false in filter for faster performance.
    because he wants just the count not anything data/information about message.

    say msMq.GetAllMessages() if we go with without filtration its return all message with all related data & then count.
    but msMq.GetAllMessages() if we go with with maximum filtration then its first filter on server then return data which contain minimum information/data and my next step or target is count.

    msMq.GetAllMessages().Count()

    so go with filter as much as you can.

    please correct me if I am wrong.

  25. pelegk k Says:

    from http://msdn.microsoft.com/en-us/library/system.messaging.messagequeue.getallmessages.aspx
    “Because GetAllMessages returns a copy of the messages in the queue at the time the method was called, the array does not reflect new messages that arrive in the queue or messages that are removed from the queue.”
    if got 50K of messages in the Queue, this can be very slow.
    you can use Yoel Arnon’s
    blog : http://yoelarnon.wordpress.com/page/2/
    WMI PROVIDER FOR MESSAGE COUNT IN QUEUE

    http://yoelarnon.wordpress.com/2008/04/02/the-msmq-wmi-provider/

    • Adrian Says:

      If you read through the replies, you’ll see that using the performance counters is an easy way to get the message count. You don’t need a third party library to do this.

  26. Thinking Enterprise Solutions Says:

    […] Counting Messages in an MSMQ MessageQueue from C# […]


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.

%d bloggers like this: