简体   繁体   English

有没有办法检查 MSMQ 队列中有多少消息?

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

I was wondering if there is a way to programmatically check how many messages are in a private or public MSMQ using C#?我想知道是否有一种方法可以使用 C# 以编程方式检查私有或公共 MSMQ 中有多少消息? 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.我有代码可以使用包含在 try/catch 中的 peek 方法检查队列是否为空,但我从未见过有关显示队列中消息数量的任何内容。 This would be very helpful for monitoring if a queue is getting backed up.这对于监控队列是否得到备份非常有帮助。

You can read the Performance Counter value for the queue directly from .NET:您可以直接从 .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());

There is no API available, but you can use GetMessageEnumerator2 which is fast enough.没有可用的 API,但您可以使用足够快的GetMessageEnumerator2 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 Peek方法似乎存在问题,引发异常

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:如果您需要快速方法(我的机器上每秒调用 25000 次),我推荐基于 MQMgmtGetInfo() 和 PROPID_MGMT_QUEUE_MESSAGE_COUNT 的 Ayende 版本:

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

for VB https://gist.github.com/Lercher/5e1af6a2ba193b38be29对于 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.起源可能是http://functionalflow.co.uk/blog/2008/08/27/counting-the-number-of-messages-in-a-message-queue-in/但我不相信这2008 年的实施不再有效。

We use the MSMQ Interop.我们使用 MSMQ 互操作。 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;

    }
            //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.您将在“C:\\Program Files (x86)\\Microsoft SDKs\\Windows”中获得 MSMQManagement 类引用,只需浏览此地址即可获得。 for more details you can visit http://msdn.microsoft.com/en-us/library/ms711378%28VS.85%29.aspx .有关更多详细信息,您可以访问http://msdn.microsoft.com/en-us/library/ms711378%28VS.85%29.aspx

I had real trouble getting the accepted answer working because of the xxx does not exist in the specified Category error.由于xxx does not exist in the specified Category错误xxx does not exist in the specified Category我在获得接受的答案时遇到了很大的麻烦。 None of the solutions above worked for me.上述解决方案都不适合我。

However, simply specifying the machine name as below seems to fix it.但是,简单地指定机器名称如下似乎可以解决它。

private long GetQueueCount()
{
    try
    {
        var queueCounter = new PerformanceCounter("MSMQ Queue", "Messages in Queue", @"machineName\private$\stream")
        {
            MachineName = "machineName"
        };

        return (long)queueCounter.NextValue();
    }
    catch (Exception e)
    {
        return 0;
    }
}

This worked for me.这对我有用。 Using a Enumarator to make sure the queue is empty first.首先使用枚举器确保队列为空。

   Dim qMsg As Message ' instance of the message to be picked 
        Dim privateQ As New MessageQueue(svrName & "\Private$\" & svrQName) 'variable svrnme = server name ; svrQName = Server Queue Name
        privateQ.Formatter = New XmlMessageFormatter(New Type() {GetType(String)}) 'Formating the message to be readable the body tyep
        Dim t As MessageEnumerator 'declared a enumarater to enable to count the queue
        t = privateQ.GetMessageEnumerator2() 'counts the queues 

        If t.MoveNext() = True Then 'check whether the queue is empty before reading message. otherwise it will wait forever 
            qMsg = privateQ.Receive
            Return qMsg.Body.ToString
        End If

The fastest method I have found to retrieve a message queue count is to use the peek method from the following site :我发现检索消息队列计数的最快方法是使用以下站点的 peek 方法:

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);
  {
     count = 1;
     while ((m = PeekWithoutTimeout(q, cursor, PeekAction.Next)) != null)
     {
        count++;
     }
  }
return count;
}

If you want a Count of a private queue, you can do this using WMI.如果您想要一个私有队列的计数,您可以使用 WMI 执行此操作。 This is the code for this:这是代码:

// You can change this query to a more specific queue name or to get all queues
private const string WmiQuery = @"SELECT Name,MessagesinQueue FROM Win32_PerfRawdata_MSMQ_MSMQQueue WHERE Name LIKE 'private%myqueue'";

public int GetCount()
{
    using (ManagementObjectSearcher wmiSearch = new ManagementObjectSearcher(WmiQuery))
    {
        ManagementObjectCollection wmiCollection = wmiSearch.Get();

        foreach (ManagementBaseObject wmiObject in wmiCollection)
        {
            foreach (PropertyData wmiProperty in wmiObject.Properties)
            {
                if (wmiProperty.Name.Equals("MessagesinQueue", StringComparison.InvariantCultureIgnoreCase))
                {
                    return int.Parse(wmiProperty.Value.ToString());
                }
            }
        }
    }
}

Thanks to the Microsoft.Windows.Compatibility package this also works in netcore/netstandard.感谢Microsoft.Windows.Compatibility包,这也适用于 netcore/netstandard。

The message count in the queue can be found using the following code.可以使用以下代码找到队列中的消息计数。

MessageQueue messageQueue = new MessageQueue(".\\private$\\TestQueue");
var noOFMessages = messageQueue.GetAllMessages().LongCount();

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM