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

时间:2010-10-06 01:56:04

标签: c# msmq

我想知道是否有办法以编程方式检查使用C#在私有或公共MSMQ中有多少邮件?我有代码使用try / catch中包含的peek方法检查队列是否为空,但我从未见过有关显示队列中消息数的任何信息。这对于监视是否正在备份队列非常有用。

10 个答案:

答案 0 :(得分:34)

您可以直接从.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());

答案 1 :(得分:22)

没有可用的API,但您可以使用足够快的GetMessageEnumerator2。样品:

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

实施

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

        return count;
    }
}

我也尝试了其他选项,但每个选项都有一些缺点

  1. 性能计数器可能抛出异常“实例'...'在指定的类别中不存在。”
  2. 读取所有消息然后进行计数非常慢,它还会从队列中删除消息
  3. Peek方法似乎存在抛出异常的问题

答案 2 :(得分:7)

如果您需要一种快速方法(我的盒子上每秒25k次调用),我推荐基于MQMgmtGetInfo()和PROPID_MGMT_QUEUE_MESSAGE_COUNT的Ayende版本:

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

对于VB https://gist.github.com/Lercher/5e1af6a2ba193b38be29

起源可能是http://functionalflow.co.uk/blog/2008/08/27/counting-the-number-of-messages-in-a-message-queue-in/,但我不相信2008年的实施工作不再适用。

答案 3 :(得分:4)

我们使用MSMQ Interop。根据您的需要,您可以简化这一点:

    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;

    }

答案 4 :(得分:3)

            //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();

这比你选择的要快。 你得到MSMQManagement类refferance" C:\ Program Files(x86)\ Microsoft SDKs \ Windows"只是在这个地址眉毛,你会得到它。有关详细信息,请访问http://msdn.microsoft.com/en-us/library/ms711378%28VS.85%29.aspx

答案 5 :(得分:1)

由于xxx does not exist in the specified Category错误,我确实无法接受已接受的答案。以上解决方案都不适合我。

但是,只需将机器名称指定如下即可解决问题。

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;
    }
}

答案 6 :(得分:0)

我发现检索邮件队列计数的最快方法是使用以下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;
}

答案 7 :(得分:0)

这对我有用。使用Enumarator确保队列先为空。

   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

答案 8 :(得分:0)

如果要对专用队列进行计数,则可以使用WMI进行。 这是代码:

// 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());
                }
            }
        }
    }
}

感谢Microsoft.Windows.Compatibility软件包,它也可以在netcore / netstandard中使用。

答案 9 :(得分:-1)

可以使用以下代码找到队列中的消息计数。

SELECT *
FROM Transaction
WHERE EXISTS
(
 SELECT 1 FROM Period WHERE txDate BETWEEN fromDate AND ToDate
)