Getting Started with MSMQ


Posted on Sunday August 2011


I recently needed to know a little bit about MSQM, so I put together a very basic little prototype.

MSMQ has a number of features, but I think the obvious ones are:

  • it's a Microsoft product (not sure if that’s a feature, but what the hey)
  • It's included in the OS from XP onwards
  • It's wrapped up in .NET in the System.Messaging namespace
  • It's pretty easy to use

It may not be the fastest or the best, but I think that feature set makes it a good choice for dipping your toe in the world of message queues.

We can start by enabling MSMQ in the control panel (under Windows Features). This will start up a service and we will be good to go. First of all we want to create a source of messages. Here we just send a very basic string. In practice you may want to create a message class, perhaps with a message type, Id and maybe a serialized DTO payload.


    // create a queue
    if (!MessageQueue.Exists(_queueName))
    {
    	MessageQueue.Create(_queueName);
    }

    // send a bunch of messages
    for (int i = 0; i < 100; i++)
    {
    	// slow things down a bit so we can see what’s happening
    	Thread.Sleep(100);
    	SendPublic(i);
    }

    public static void SendPublic(int i )
    {
    	var myQueue = new MessageQueue(_queueName);

    	string body = string.Format("{0} Public queue by path name.", i);

    	var msg = new Message(body);

    	msg.Formatter = new MessageFormatter();

    	myQueue.Send(msg);
    	Console.WriteLine(body);
    	return;
    }

By default MSMQ uses an XML message formatter, and reading the message body is done through streams. This is sometimes a bit inconvenient. I’ve added a simple message formatter (nicked from MSDN) to ease things.


    public class MessageFormatter : IMessageFormatter
    {
    	public bool CanRead(Message message)
    	{
    		return true;
    	}

    	public object Read(Message message)
    	{
    		//Obtain the BodyStream for the message.
    		var stm = message.BodyStream;
    		stm.Position = 0;
    		//Create a StreamReader object used for reading from the stream.
    		var reader = new StreamReader(stm);

    		//Return the string read from the stream.
    		//StreamReader.ReadToEnd returns a string.
    		return reader.ReadToEnd();
    	}

    	public void Write(Message message, object obj)
    	{
    		//Declare a buffer.
    		byte[] buff = Encoding.UTF8.GetBytes(obj.ToString());

    		//Create a new MemoryStream object passing the buffer.
    		var stm = new MemoryStream(buff);

    		//Assign the stream to the message's BodyStream property.
    		message.BodyStream = stm;
    	}

    	public object Clone()
    	{
    		return new MessageFormatter();
    	}
    }

We can then start up several process, just simple console apps, to listen to the queue and read the messages. I was running three or four, and they would read the messages off the queue in a round robin fashion. I found that quite pleasing :)


    public static void MonitorQueue ()
    {
    	var myQueue = new MessageQueue(_queueName);

    	// enter an idle loop till a message is recieved
    	while (true)
    	{
    		var msg = myQueue.Receive();
    		// Process the journal message.
    		if(msg != null)
    		{
    			msg.Formatter= new MessageFormatter();

                // read the payload via the BodyStream
    			var rdr = new StreamReader(msg.BodyStream);
    			var str = rdr.ReadToEnd();
    			// or read it directly thanks to the message formatter
    			Console.WriteLine(msg.Body);
    		}
    	}
    }

I’m writing this at home and immediately discovered a few problems that are casting quite a few shadows on MSMQ.

It seems there a few limitations when running MSMQ when you aren’t on a domain (which would be pretty much everyone when they’re not at work, geeks excepted). At work (on a domain) I had no trouble. The messages were sent from one process and several listening processes merrily picked them up and ran with it. Life was good. At home (on a workgroup) my most trivial test does not work.

I’ve only barely scratched the surface here and I’m not sure I like what I’m smelling.

I’d strongly think twice before using MSMQ. If you’re rocking the “enterprise” and building things for a known environment then by all means. If you need to cross boundaries (network, OS, etc) or you want to run over the internet, you want it to “just work” – maybe look a little deeper. RabbitMQ, ZeroMQ, nServiceBus, maybe there is something else out there.

Update: So... I should have read the error message, but it was late. There were a couple of problems with WORKGROUP mode.

The first one I do not really understand (I guess I need to RTFM). If you "Manage" your computer you can see a Message Queuing node has been added. I created a queue directly there, copied the name (something like machinename\private$\testqueue) and used that. All good. Apparantly you can only use private queus in WORKGROUP mode and must reference them with a specific naming format. I found a few forum posts alluding to this, but no definitive answer anywhere. I'm sure it's mentioned somewhere in MSDN...

Alt text

Secondly, although you can't see it here :) I was also enumerating the public queues on my machine, as a check that the queue was created.

Calling MessageQueue.GetPublicQueues is not supported in WORKGROUP mdoe, which was a bit of red herring. I love the MSDN documentation which lists whether the method is available. Guess the answer is no?

Alt text