web-dev-qa-db-fra.com

Existe-t-il un moyen de vérifier le nombre de messages dans une file d'attente MSMQ?

Je me demandais s'il existe un moyen de vérifier par programme combien de messages sont dans un MSMQ privé ou public en utilisant C #? J'ai du code qui vérifie si une file d'attente est vide ou n'utilise pas la méthode Peek intégrée dans un try/catch, mais je n'ai jamais rien vu sur l'affichage du nombre de messages dans la file d'attente. Cela serait très utile pour surveiller si une file d'attente est sauvegardée.

36
Justin

Vous pouvez lire la valeur du compteur de performances pour la file d'attente directement à partir de .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());
34
Gary Wright

Il n'y a pas d'API disponible, mais vous pouvez utiliser GetMessageEnumerator2 qui est assez rapide. Échantillon:

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

La mise en oeuvre

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

        return count;
    }
}

J'ai aussi essayé d'autres options, mais chacune a ses inconvénients

  1. Le compteur de performance peut lever l'exception "L'instance '...' n'existe pas dans la catégorie spécifiée."
  2. La lecture de tous les messages et la prise en compte est très lente, cela supprime également les messages de la file
  3. Il semble y avoir un problème avec la méthode Peek qui lève une exception
18
oleksii

Si vous avez besoin d'une méthode rapide (25 000 appels/seconde sur ma boîte), je vous recommande la version d'Ayende basée sur MQMgmtGetInfo () et PROPID_MGMT_QUEUE_MESSAGE_COUNT: 

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

pour VB https://Gist.github.com/Lercher/5e1af6a2ba193b38be29

The Origin était probablement http://functionalflow.co.uk/blog/2008/08/27/counting-the-number-of-messages-in-a-message-queue-in/ mais je suis pas convaincu que cette mise en œuvre de 2008 fonctionne plus.

7
Zartag

Nous utilisons le MSMQ Interop. En fonction de vos besoins, vous pouvez probablement simplifier ceci:

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

C’est plus rapide que celui que vous avez sélectionné . Vous obtenez un renvoi de classe MSMQManagement dans "C:\Program Files (x86)\Microsoft SDKs\Windows". Pour plus de détails, visitez http://msdn.Microsoft.com/en-us/library/ms711378%28VS.85%29.aspx

3
rhatwar007

J'ai eu de la difficulté à obtenir la réponse acceptée en raison de l'erreur xxx does not exist in the specified Category. Aucune des solutions ci-dessus n'a fonctionné pour moi.

Cependant, il suffit de spécifier le nom de la machine comme indiqué ci-dessous pour le corriger.

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

La méthode la plus rapide que j'ai trouvée pour récupérer un nombre de files d'attente de messages consiste à utiliser la méthode peek à partir du site :

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;
}
0
John Hunter

Cela a fonctionné pour moi. Utilisation d'un énumérateur pour vous assurer que la file d'attente est vide en premier. 

   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
0
Emmanuel Makaza