Is there a way to check how many messages are in a MSMQ Queue?

40,260

Solution 1

You can read the Performance Counter value for the queue directly from .NET:

using System.Diagnostics;

// ...
var queueCounter = new PerformanceCounter(
    "MSMQ Queue", 
    "Messages in Queue", 
    @"machinename\private$\testqueue2");

Console.WriteLine( "Queue contains {0} messages", 
    queueCounter.NextValue().ToString());

Solution 2

There is no API available, but you can use GetMessageEnumerator2 which is fast enough. Sample:

MessageQueue q = new MessageQueue(...);
int count = q.Count();

Implementation

public static class MsmqEx
{
    public static int Count(this MessageQueue queue)
    {
        int count = 0;
        var enumerator = queue.GetMessageEnumerator2();
        while (enumerator.MoveNext())
            count++;

        return count;
    }
}

I also tried other options, but each has some downsides

  1. Performance counter may throw exception "Instance '...' does not exist in the specified Category."
  2. Reading all messages and then taking count is really slow, it also removes the messages from queue
  3. There seems to be a problem with Peek method which throws an exception

Solution 3

If you need a fast method (25k calls/second on my box), I recommend Ayende's version based on MQMgmtGetInfo() and PROPID_MGMT_QUEUE_MESSAGE_COUNT:

for C# https://github.com/hibernating-rhinos/rhino-esb/blob/master/Rhino.ServiceBus/Msmq/MsmqExtensions.cs

for VB https://gist.github.com/Lercher/5e1af6a2ba193b38be29

The origin was probably http://functionalflow.co.uk/blog/2008/08/27/counting-the-number-of-messages-in-a-message-queue-in/ but I'm not convinced that this implementation from 2008 works any more.

Solution 4

We use the MSMQ Interop. Depending on your needs you can probably simplify this:

    public int? CountQueue(MessageQueue queue, bool isPrivate)
    {
        int? Result = null;
        try
        {
            //MSMQ.MSMQManagement mgmt = new MSMQ.MSMQManagement();
            var mgmt = new MSMQ.MSMQManagementClass();
            try
            {
                String host = queue.MachineName;
                Object hostObject = (Object)host;
                String pathName = (isPrivate) ? queue.FormatName : null;
                Object pathNameObject = (Object)pathName;
                String formatName = (isPrivate) ? null : queue.Path;
                Object formatNameObject = (Object)formatName;
                mgmt.Init(ref hostObject, ref formatNameObject, ref pathNameObject);
                Result = mgmt.MessageCount;
            }
            finally
            {
                mgmt = null;
            }
        }
        catch (Exception exc)
        {
            if (!exc.Message.Equals("Exception from HRESULT: 0xC00E0004", StringComparison.InvariantCultureIgnoreCase))
            {
                if (log.IsErrorEnabled) { log.Error("Error in CountQueue(). Queue was [" + queue.MachineName + "\\" + queue.QueueName + "]", exc); }
            }
            Result = null;
        }
        return Result;

    }

Solution 5

            //here queue is msmq queue which you have to find count.        
            int index = 0;
            MSMQManagement msmq = new MSMQManagement() ;   
            object machine = queue.MachineName;
            object path = null;
            object formate=queue.FormatName;
            msmq.Init(ref machine, ref path,ref formate);
            long count = msmq.MessageCount();

This is faster than you selected one. You get MSMQManagement class refferance inside "C:\Program Files (x86)\Microsoft SDKs\Windows" just brows in this address you will get it. for more details you can visit http://msdn.microsoft.com/en-us/library/ms711378%28VS.85%29.aspx.

Share:
40,260
Justin
Author by

Justin

Updated on February 15, 2020

Comments

  • Justin
    Justin over 4 years

    I was wondering if there is a way to programmatically check how many messages are in a private or public MSMQ using C#? I have code that checks if a queue is empty or not using the peek method wrapped in a try/catch, but I've never seen anything about showing the number of messages in the queue. This would be very helpful for monitoring if a queue is getting backed up.

  • Justin
    Justin over 13 years
    Thanks, but where is the MSMQ.ManagementClass? I read in another post that you have to include a COM library called "MSMQ 3.0" but I don't see this on the Com tab (using .NET 3.5.)
  • My Other Me
    My Other Me over 13 years
    Do you have Interop.MSMQ.dll anywhere on your machine? We have it in our assembly collection.
  • Justin
    Justin over 13 years
    No I don't have that, nor do I see anywhere to download it online.
  • Justin
    Justin over 13 years
    System.Messaging.MessageQueueException: MQ_ACTION_PEEK_NEXT specified to MQReceiveMessage cannot be used with the current cursor position. at System.Messaging.MessageQueue.ReceiveCurrent(TimeSpan timeout, Int32 action, CursorHandle cursor, MessagePropertyFilter filter, MessageQueueTransaction internalTransaction, MessageQueueTransactionType transactionType) at System.Messaging.MessageQueue.Peek(TimeSpan timeout, Cursor cursor, PeekAction action)
  • Ali Mst
    Ali Mst about 12 years
    See this answer on how to add this reference: stackoverflow.com/a/8258952/16241
  • Randy Burden
    Randy Burden about 12 years
    Tried this method and got the following COMException which unfortunately I cannot resolve as this would require an infrastructure change: This operation is not supported for Message Queuing installed in workgroup mode. :(
  • Christian Fredh
    Christian Fredh almost 11 years
    Works fine for one queue, but for error queue I'm getting "Instance 'machinename\private$\error' does not exist in the specified Category.". Is that because the queue haven't had any items in queue for a while or do I need to write in a special way for error queue?
  • Christian Fredh
    Christian Fredh almost 11 years
    I added a message in the error queue and then the code works fine for that queue as well. I guess you need to catch this exception (InvalidOperationException) and then it's empty. Bad thing is, the queue could also be non-existent if you get this exception.
  • pasx
    pasx about 10 years
    I have found that a syntax like ".\private$\testqueue2" which is what I get from someQueue.Path will cause an exception. I ended up using someQueue.FormatName and extracting "machinename\private$\testqueue2" from its content. I also found this approach not to be 100 percent reliable when the queue is just being started or retrieved which made me think that I would be better off with an implementation based on the com dll but I hadn't had time to invest in more testing.
  • barrypicker
    barrypicker almost 10 years
    We are using this exact method, and find that the method GetMessageCount is failing because it is peeking while messages are consumed from the queue. By merely adding a 10ms thread.sleep command after count++ this operates much more smoothly but takes a lot longer. I still think there must be a better way to get count that to insistantly peek a million times... (are we there yet, are we there yet, are we there yet - doh)
  • Roger
    Roger over 9 years
    I am getting 'Category does not exist.' when attempting to instantiate the PerformanceCounter(). Must there be > 0 messages in the queue? Christian, did you find another work around? I cannot guarantee messages being in the queue in my case.
  • Per-Frode Pedersen
    Per-Frode Pedersen over 9 years
    This code will fail if the queue contains 0 messages, because it will try PeekWithoutTimeout with PeekAction.Next even though PeekWithTimeout with PeekAction.Current returned null. Added null check to answer
  • namford
    namford almost 9 years
    This is a C# question, your answer is VB
  • Jon List
    Jon List over 8 years
    Isn't there a race condition here? What happens if stuff is being added/removed while you are enumerating? Or if stuff is added/removed after you have counted? Is there a way to suspend all interaction with the queue while you count?
  • oleksii
    oleksii over 8 years
    This method seemed to be thread-safe in a sense it reflects dynamic changes to the queue. From doc "For example, the enumerator can automatically access a lower-priority message placed beyond the cursor's current position, but not a higher-priority message inserted before that position.". Personally I was testing it under load during inserts and deletes and didn't have threading issues. Obviously, this will reflect approx. count of messages if your queue is used. If you need to have exact count, you need to get a static snapshot by calling GetAllMessages
  • meraydin
    meraydin almost 8 years
    Don't look for another answer! Other than @Zartag's answer, any other method is either slow or unreliable (I have tested all of them, believe me!)
  • Jeroen Maes
    Jeroen Maes over 7 years
    The nuget package Rsft.Lib.Msmq.MessageCounter implements this.
  • Kirill Bestemyanov
    Kirill Bestemyanov almost 7 years
    In this case you get all messages from queue. It is too expensive.
  • maracuja-juice
    maracuja-juice over 5 years
    this is the fastest method of the ones I tested so far
  • maracuja-juice
    maracuja-juice over 5 years
    This is definitely not the fastest method. Highest Voted answer: 6x times faster. Second Highest Voted Answer: 3x times faster
  • maracuja-juice
    maracuja-juice over 5 years
    Slow is relative @meraydin But yes this is definitely the fastest.
  • maracuja-juice
    maracuja-juice over 5 years
    Where in the Windows folder exactly? There are 4 direct subfolders and each of the subfolders have more subfolders... What file do I have to search for?
  • maracuja-juice
    maracuja-juice over 5 years
    but also the one that requires the most (complicated) code
  • maracuja-juice
    maracuja-juice over 5 years
    Also @JeroenMaes unfortunately when calling the GetCount method of the library I get an exception.. Filed an issue on their repository.
  • Dave
    Dave over 3 years
    How can a question this "easy" be so hard to get right? I'm getting huge pauses or "does not exist in the specified category" error. So much for a "quick look at MSMQ" !!