After a long time off from blogging, I have decided to resume. I will try to be more consistent with my posts over the next few months. I attended MEDC and it was very fascinating to see what people are building on the .NET Compact Framework. I met quite a number of people who were interested in the managed support we have provided for MSMQ on devices. It was also very interesting to be able to match faces with a lot of familiar names.

There were some questions asked about what level of transaction support was built into CE MSMQ which I would attempt to answer in this blog post. As a backgrounder, it is helpful to know what transactions mean in the context of Message Queuing. Basically, transactional messages are used to pair the sending or receiving of any message with an action in another operation. Using transactional messages you can ensure that the unit of work is carried out as an atomic operation—that is, the operation succeeds or fails as a whole. Transactional messages can also be used to ensure that a message is delivered only once, and to ensure that all messages sent from one computer to another are delivered in order. Positive and negative acknowledgments can be used to confirm that messages reached, or were retrieved from, the destination queue. 

As I mentioned in previous posts transaction support on Windows CE MSMQ is limited to a single message transaction. So the question then arises:

What is a single message transaction and when do I need to use it?

A single message transaction implicitly uses the internal transaction support provided by Message Queuing and does not require the use of an external distributed transaction coordinator (DTC). The destination queue for a single message transaction must be a transactional queue. It is important to differentiate between exact once delivery as guaranteed by single message transactions (SMT) and single message coherency.

In MSMQ (on CE and on the desktop), A message gets sent/received in its entirety or it does not get received at all. As an example if you are attempting to send a message over a flaky wireless connection where the TCP connection breaks from time to time, the single message is guaranteed to be delivered intact or not delivered at all. This is the concept of single message coherency.  You do not need transactions to achieve single message coherency in MSMQ. You are guaranteed that out of the box.

Single Message Transactions on MSMQ CE allows you to communicate with a transactional queue. Lets assume for a second that you attempt to send a message to a transactional queue and you do not know that the queue is transactional as such you send your message in a non-transactional manner; Because Active Directory lookup is not supported in CE MSMQ there is no way to check if the remote queue is transactional as such MSMQ proceeds to attempt to open a connection to the remote queue so that it can send the message. Attempting to open the connection will be unsuccessful so it will just keep retrying indefinitely (unless you specify a TimeToReachQueue or TimeToBeReceived property). This is similar to what will happen if you attempt to send a message to a non-existent queue (MSMQ will assume that the destination queue is offline and will keep retrying the send operation in an outgoing queue). However it is important to know that this is an Operating System service, so this is abstracted from the sending application. As far as the application is concerned the message has been sent. Under the hood however the message remains in the outgoing queue and keeps attempting to connect so that the message can be sent.

On NETCF, you will have to do 2 things to send a message to a transactional queue.

·        Append the XACTONLY flag to the queue’s format name

·         Send the message with the overload that accepts a MessageQueueTransactionType parameter.

If one of the above is missing, a MessageQueueException with error code TransactionUsage and message “The transaction usage is invalid” is thrown.

The correct way to do that is highlighted in the sample code below.

So why do I need to perform a transactional send operation then?

You might be in a situation where the remote queue is transactional and you want to be able to put a message into that queue (from your device) and have it read it in a transactional manner on the receiving side. Messages sent to a transactional queue have to be transactional.

I believe transactions should be used sparingly on device MSMQ applications and the scenario should be well planned. This is because MSMQ automatically sets the delivery mode of the transactional message to recoverable (the default delivery mode is express). This could potential cause a reduction in throughput but this way you are guaranteed that the messages will be delivered, even if a computer crashes while the message is en route to the queue.

So how does guaranteed delivery differ for transactional and non-transactional messages?

For a scenario in which there is no routing server, the story is exactly the same. A message is either delivered in its entirety or not delivered at all.

However routing adds a slightly different twist to it. Take for instance a case where you are using a routing server (e.g OutFRS queue that points to a Falcon Routing Server - which enables you to send messages to a public queue) if a non transactional message is sent and the routing server cannot deliver the message, the message is saved on the MSMQ server that cannot deliver the message, however if you use a transactional message and the message cannot be delivered the message is saved on the source machine where it originated and not on the machine that fails to deliver the message. This way transactional messaging can guarantee the delivery of routed messages.

Please let me know via your comments if there is any other aspect of MSMQ programming on NETCF you will like to see covered in this blog posts.

Now some bit of code:

using System;
using System.Messaging;

public class TransactionTest
{
  public static void Main()
  {
    string strDestQ = @"FormatName:Direct=OS:MyServerName\Private$\transq;XACTONLY";
     try
     {

         MessageQueue messageQueue = new MessageQueue();
         messageQueue.Path = strDestQ;

         Message m = new Message();
         m.Label = "Sample Message";
         m.Body = "Hello World";

         messageQueue.Send(m,MessageQueueTransactionType.Single);
         messageQueue.Close();
         Console.WriteLine("First Transactional Message sent!");
     
}
     catch(MessageQueueException mex)
     {
         Console.WriteLine("Message Queue Exception");
         Console.WriteLine("Error Code is {0}",mex.MessageQueueErrorCode);
         Console.WriteLine("Exception is {0}",mex.ToString());
     }
     catch (Exception ex)
     {
         Console.WriteLine(ex.ToString());
     }

   }
}