RSS Feed
Download our iPhone app
Browse DevX
Sign up for e-mail newsletters from DevX


MSMQ for .NET Developers, Part 2

Learn how to use MSMQ to send messages with complex messages types (not just strings), send MSMQ messages over HTTP, and explore several more useful queue and message properties as well as a few invaluable MSMQ tips and pitfalls.

art 1 of this article included an example that demonstrated how to read messages from a queue asynchronously. That example worked by first calling BeginReceive on the queue object and then setting a delegate called whenever a new message is received. The BeginReceive method call included a TimeSpan parameter that limited the time to wait for a new message to arrive in the queue to 15 seconds. Using this technique, if a message fails to arrive in the queue within the time allotted, the code calls the ReceiveCompleted delegate—in this case, raising an exception when the EndReceive method is called, signaling the application that no message was received before the timeout expired.

Here is the code used in the original example.

   ' connect to the queue
   myReceiveQueue = New _
   myReceiveQueue.Formatter = _
      New XmlMessageFormatter(New Type() _
   ' add a handler to tell MSMQ which method to call when a 
   ' message arrives
   AddHandler myReceiveQueue.ReceiveCompleted, _
      AddressOf MSMQ_ReceiveCompleted
   ' call the asynchronous version of Receive, 
   ' waiting no longer than 15 seconds
   myReceiveQueue.BeginReceive(New TimeSpan(0, 0, 15))

In response to Part 1, I received many requests for example code implementing a server application that would "listen" to a queue for incoming request messages. Such an application would receive a message, process the request, and begin listening for the next message immediately. The applications of such a listener are numerous. The example provided in part 1 of the article would not be practical, despite several messages suggesting otherwise. The original example has problems when you extend it to raise exceptions. In addition, as written, the example code doesn't stop "listening" to the queue when you pause or stop the application. Here's how you can solve those problems.

How to Stop "Listening" for Messages
All .NET developers, by now, should realize that you should rarely use exceptions to communicate common or frequently occurring error conditions within an application. Exceptions are far too costly to create. For example, when the sample calls BeginReceive with a TimeSpan parameter, thereby setting a timeout, the application will raise an exception when the timeout condition is reached before a message arrives in the queue—in other words, possibly frequently. Perhaps a better way to call BeginReceive is with no parameters, instructing the BeginReceive process to listen indefinitely. Doing that helps by limiting the number of exceptions raised, but also introduces a new dilemma: How do you stop the BeginReceive process?

To cancel the BeginReceive process you should need to call only the queue's Close method. However, just as I tried many times, many developers found that calling Close doesn't cancel the BeginReceive call. The ReceiveCompleted delegate would still be called when new messages arrived in the queue. The workaround is to disable the connection-caching property used by MSMQ. Unchecked caching of MSMQ's queue connections cause the queue objects to remain in memory unexpectedly, causing the condition described above. To prevent this problem, simply set the EnableConnectionCache property of the receive queue to False when creating the queue object. That change cancels the BeginReceive call as expected when you call the queue's Close method.

The only other requirement to make a "listener" server as described above is to re-enable listening each time a message is received. After receiving each message, you must call BeginReceive again to instruct MSMQ to start listening for the next message to arrive. You do not need to set the formatter or the ReceiveCompleted delegate again.

The code sample below shows the completed Listening Server solution. The following changes have been made to the original solution (these changes are included in the sample code).

  1. After creating the MessageQueue object, its EnableConnectionCache property is set to False.
  2. The code now calls BeginReceive without specifying a TimeSpan parameter.
       ' connect to the queue
       myReceiveQueue = New MessageQueue(comboQueueName.Text)
       ' IMPORTANT: disable the MSMQ connection cache
       myReceiveQueue.EnableConnectionCache = False
       ' set the formatter for the queue
       myReceiveQueue.Formatter = New XmlMessageFormatter( _
          New Type() {GetType(System.String)})
       ' add a handler to tell MSMQ which method to call 
       ' when a message arrives
       AddHandler myReceiveQueue.ReceiveCompleted, _
          AddressOf MSMQ_ReceiveCompleted
       ' call the asynchronous version of Receive - no time limit

  4. In the ReceiveCompleted method, re-enable listening by calling BeginReceive.
       ' receive the message
       myMessage = myReceiveQueue.EndReceive( _
       ' process the message
       ' re-enable 'listening' by calling BeginReceive again

  6. Cancel the BeginReceive call by calling the queue object's Close method.
   ' close the queue (as long as the EnableConnectionCache 
   ' property of the queue is set to false), this will cancel 
   ' the pending BeginReceive call

Close Icon
Thanks for your registration, follow us on our social networks to keep up-to-date