Sunday, November 2, 2008

Getting the message count from an MSMQ Queue

While at KaizenConf (http://www.kaizenconf.com) today, I was attending a session held by Chris Patterson (twitter: @PhatBoyG) & Dru Sellers (twitter @drusellers) on ESBs and MassTransit, their ESB implementation.

During the session, Dru complained that there wasn't a good way to get the message count from an MSMQ queue.  Of course, I was required to take that as a challenge, since that's the kind of guy I am :).  I found that as of the 3.0 API for MSMQ (apparently, that's the XP / Server 2003 vintage), there's a few ways to get the message count for a queue.

The available methods (that I found) for asking for the count of messages in a Queue were:

  • Call MQMgmtGetInfo API to query the queue for the PROPID_MGMT_QUEUE_MESSAGE_COUNT property.
  • Load up a MSMQManagement COM object, call it's Init method to associate with a Queue, and then ask for it's MessageCount property value.

It appears that the first method (which is an API call) is actually just a proxy for the second, so I'm not going to talk about it.  Calling the COM object from .NET is much easier than calling the API anyway, since it's not exactly a 'pretty' API for P/Invoke purposes.

Since I'm not really interested in investing a lot of time in this blog post, I'm just going to paste the code here and let you do with it as you please...  Here goes...

var path = @".\Private$\foo";
MessageQueue mq = MessageQueue.Exists(path)
? new MessageQueue(path)
: MessageQueue.Create(path);
try
{
// try to insert a few items into the queue...
mq.Send("foo");
mq.Send("bar");
mq.Send("foo");

var msmqMgmt = new MSMQManagement();
object machine = null; // mq.MachineName;
object queuename = mq.Path;
object formatname = null; //mq.FormatName;
msmqMgmt.Init(ref machine, ref queuename,
ref formatname);
int messageCount = msmqMgmt.MessageCount;

MessageBox.Show(string.Format("Queue has {0} items",
messageCount));
}
finally
{
string path2 = mq.Path;
mq.Close();
MessageQueue.Delete(path2);
}

Of course, this code requires a reference to the COM type library - namely the "Microsoft Message Queue 3.0 Object Library" on the COM list in VS2008 when you have MSMQ installed on your dev box.

I had some weird problems trying to test this code on my machine, hence the commented machinename and formatname.  I think the problem was probably related more to the configuration of my machine than it was the code.  I suspect, however, that there may be some complexities that require you to specify machine name, queue name, and format name differently depending on whether you are working with a local queue or a remote one.

I found that for a local queue, the easy way to reference it was the code snippet above (don't specify machine, don't specify format name, supply the "path").  For a remote queue, I suspect that it will be easier to pass the machine name, the format name, and omit (pass null for) the path.  Note, the API states that you should NOT pass both the format name and the path name, or it will give an exception.

As always, if you have questions regarding this code, please don't hesitate to contact me via the comments or my email.

Saturday, November 1, 2008

.NET wish list...


  • Generics that can support 'text-like' replacement at runtime, where you can basically say that "I know that type T actually has a method called Foo with the signature bool Foo(int) but may not implement some particular interface (since you may not control the implementation of T)". I'd like to be able to call Foo from my generic class even if I can't change T to implement an interface that supports Foo. I'm thinking something like:
    public static void DoSomething(T target)
    where T: class having bool Foo(int)
    {
    if(target.Foo(0))
    Console.WriteLine("Woohoo");
    }
  • A way of marking objects that MUST be used in a 'using' expression (i.e. they only make sense there) and having the C# compiler enforce it. For instance, an attribute would work for me (similar to how 'FlagsAttribute' indicates special semantics on enums). My reasoning for this is that I'd like to use IDisposable for some C++-style RAII-like stuff, but there's no way to guarantee that the objects are used correctly.
  • A way of injecting simple code / hooking "before" and "after" property notifications on 'automatic properties' in C#. For instance, if I do an automatic property, I'd love to be able to say "any time this changes, call this method", or something like that. It could be useful for INotifyPropertyChanged, but also for other things as well.