Click here to Skip to main content
Click here to Skip to main content

Programming MSMQ in .NET - Part 2: Transactional Messaging

, 15 Jun 2003
Rate this:
Please Sign up or sign in to vote.
This article talks about transactional messaging with MSMQ and the implementation aspects wrt .NET
<!-- Add the rest of your HTML here -->

Introduction

In the previous article, we saw some very basics of MSMQ programming like creating a queue, sending and receiving simple messages etc. In this article, we shall consider an important aspect of programming MSMQ: Transactional messaging. We shall start off by understanding why you need transactional messaging, what it is,  followed by some simple code snippets showing how it can be done in .NET. Finally, we shall wrap up the article considering two case studies where transactional messaging with MSMQ has been applied.

Why Transactional Messaging?

Before plunging into transactional messasing, let us consider some problems with non-transactional messaging.

Messages can be lost

By default, MSMQ stores messages in memory when they are sent, received or routed across different servers. This is done only to boost performance as persisting messages on the disk is an extra overhead. So, if the MSMQ service crashes or the machine holding the messages goes down unexpectedly, then messages are bound to get lost.

As a work around to this problem, we can set the Recoverable property of the message to True. This property can also be set at the queue level by setting the DefaultPropertiesToSend property. The  code snippet shown below indicates the same.

Dim queue As New MessageQueue() 
queue.Path = ".\Private$\TestQueue" 
queue.DefaultPropertiesToSend.Recoverable = True 

'This method can also be used 
'Here, we use the Recoverable property of the message itself 
'Dim msg As New Message() 
'msg.Body = "My recoverable message" 
'msg.Label = "Some Label" 
'msg.Recoverable = True 
'queue.Send(msg) 

queue.Send("My recoverable message","Some Label") 
queue.Close()

Duplicate messages

In the above implementation, we solved the problem of messages being lost in transit. But still, this does not guarantee that the messages aren't duplicated. It is definitely not acceptable for a reliable application to process a message twice as it is to have lost messages.

Both the above problems are successfully solved by the usage of transactional messaging. Now, you may ask me, considering the above explanation, we may always end up using transactional messaging. Now, when do we actually use non transactional messaging and why? The answer to this question is simple. If reliability is not a concern for your application, that is, if your application is not affected by lost messages or the order of arrival of messages, use non transactional messaging. Remeber that the reliability offerered by transactional messaging comes at a cost: performance.

One rough analogy that immediately comes to my mind is usage of TCP as against the usage of UDP. UDP is analogous to non transactional messaging. UDP does not ensure that the packets arrive to the destination and they do in the same order. TCP on the other hand, ensures that the packets reach the destination and they arrive in the same order as they were sent. Therefore, TCP is analogous to non transactional messaging. Likewise, the choice between TCP and UDP is purely made based on the level of reliability and performance required for the networking application.

Creating a Transactional Queue

To implement transactional messaging, you would require to create a transactional queue first. This can be done either through the computer management console snap-in or programmatically.

Through the snap-in

Creating a transactional queue

Fig 1: Creating a transactional queue

Transactional queues are created just like normal queues. We just have to check the Transactional check box as shown in Fig 1.

Programmatically

To create a transactional queue programmatically, we need to use one of the overloads of Create method of MessageQueue class which takes a boolean parameter indicating whether the queue to be created is transactional or not. We should pass True here. For eg.

MessageQueue.Create("pc-manoj\Private$\MyTranQueue", True)

Note: The Transactional attribute of a queue cannot be changed after the queue is created.

Understanding Transactional Messaging

MSMQ supports two types of transactions: Internal and External. Let's have a look at them one at a time.

Internal Transactions

MSMQ facilitates sending and receiving multiple messages in a transaction through the MessageQueueTransaction class. The Send and Receive methods of the MessageQueue class have overloads that accept an instance of the MessageQueueTransaction class to indicate that the operation falls under a transaction. The transaction itself can be controlled using the Begin method (which starts a transaction) , Commit and Abort methods (which commits and rollbacks the transaction respectively). Let's consider an example to illustrate their usage:

        Dim mqTran As New MessageQueueTransaction()

        Dim queueA As New MessageQueue()
        queueA.Path = ".\Private$\TranQueueA"
        Dim queueB As New MessageQueue()
        queueB.Path = ".\Private$\TranQueueB"

        mqTran.Begin()
        Try
            queueA.Send("Message A", "Label A", mqTran)
            queueB.Send("Message B", "Label B", mqTran)
            mqTran.Commit()

        Catch ex As Exception
            mqTran.Abort()
        Finally
            queueA.Close()
            queueB.Close()
        End Try
    

In the above code snippet, we are sending two messages to two different queues in the same transaction.

Many a times, you may want to query on the status of a transaction and then take some action based on the status. The MessageQueueTransaction class exposes a Status property which gives you just that. It is exposed as an enumeration whose values are described below:

Value Description
Initialized The transaction has been initialized but not yet started. When a MessageQueueTransaction class is just instantiated, this will be the status.
Pending The transaction has not yet been committed or aborted. This will be the status when you begin a transaction using Begin method but not have committed or rolled back (called Commit or Abort methods).
Committed The transaction has been committed.
Aborted The transaction has been aborted.

Using the MessageQueueTransactionType enumeration

The Send and Receive methods of the MessageQueue class  also expose overloads which takes a parameter of type MessageQueueTransactionType which is an enumeration of certain values.  This basically specifies how you would like to interact with the queue (transactionally). We have not used it thus far, but is important to understand why and where this is used.

The enumeration contains three values:

Single

You might often come across situations where you want to have each queue operation in a separate internal transaction. That is, you may not want to use MessageQueueTransaction object to qualify each MSMQ operation. In such cases you can use the Single option. Here's an example:

Dim queueA As New MessageQueue()
queueA.Path = ".\Private$\TranQueueA"
queueA.Send("Single internal transactional message A", "Label A", _
    MessageQueueTransactionType.Single)
queueA.Close()

Understand that, to send a message to a transactional queue, you have to be in a transaction (internal or external), else an error will be thrown.

None

Using this option enables us to receive a message from a transactional queue, but outside a transaction. We can also use this option to send a transactional message to a non transactional queue. 

Automatic

This option is used in conjunction with external transactions. This directs the send or receive operation to use an already existing transaction context created by COM+, MTS etc. This is shown in the next section.

External Transactions

The above section dealt with doing multiple MSMQ operations within the same transaction. But, in a distributed application it is many a time required to include MSMQ operations as a part of an other transaction. For example, you may want to receive a message from a queue followed by doing some database operations; like updating a table etc. To cater to these needs, MSMQ supports DTC based transactions. Like other resource managers like Oracle and SQL Server, MSMQ can be enlisted in a distributed transaction. For example, in the below code snippet, I am doing an insert into a database table followed by a sending a message to a queue.

Dim conn As New SqlConnection( _
    "server=.;database=pubs;Trusted_connection=yes")
Dim cmd As New SqlCommand( _
    "Insert into Orders Values('OrderA','Manoj')", conn)
Dim queueA As New MessageQueue()

Try
    conn.Open()
    cmd.ExecuteNonQuery()

    queueA.Path = ".\Private$\TranQueueA"
    queueA.Send("OrderA for Manoj", "Order A", _ 
      MessageQueueTransactionType.Automatic)

    ContextUtil.SetComplete()
    Return True
Catch ex As Exception
    ContextUtil.SetAbort()
    Return False

Finally
    conn.Close()
    queueA.Close()
End Try

One thing to understand is that, when transactional messaging happens (internal or external), a message is not written to the queue until the transaction is committed. Likewise, if a message is received in a transaction, it is read right away, but is replaced back to the queue if the transaction aborts.

Also, be clear as to when, what type of transactional messaging should be used. External transactions are much slower that Internal transactions because of the overhead involved with respect to DTC. If you deal only MSMQ operations in your transaction, use Internal transactions as they are more efficient. Use External transactions if your transaction involves more than one resource manager like a database etc.

Case Study

Now, let's consider two cases where transactional messaging has been used. With these examples, the idea behind transactional messaging should become crystal clear.

Purchase Order Application

Purchase Order application

Fig 2 : A Purchase Order application

Given above is a very simplified diagram of a purchase order application. The application has two parts: One which places customer orders and the other which processes it. When a customer places an order, they are not processed immediately, but are processed at a later point during the day. The order processing application processes these orders in the same order they were placed and then confirms or rejects the delivery based on some conditions. The application has been implemented using MSMQ as the transport mechanism. Every time an order is placed by the customer, a message describing the same is placed on a queue and the processing application picks up these messages and processes them later. Now here, we would need transactional messaging because we need to ensure that:

  • The placed orders are not lost.
  • The orders are processed in the same order they were placed.

Note that we can not ensure the above requirements with non-transactional messaging.

Queued Components (QC)

Queued components are a service provided by COM+ that lets you call components asynchronously. The architecture of queued components is based on transactional messaging provided by MSMQ. I will not delve in depths of QC but will just tell very briefly how QC works.

When a queued component is instantiated  by the caller, the queued component itself is not actually instantiated. Instead, a component called QC recorder is instantiated. When method calls are made on the queued component, the recorder packages all these calls into an MSMQ message and posts it to a transactional queue. A listening application picks up this message from the queue and plays the message.  By playing, I mean instantiating the actual component and then calling all the methods in the order they were made by the caller.

So, by using transactional messaging, what has been ensured here is that the queued component is definitely called (the message is not lost) and the method calls are made only once (no duplication of messages). Therefore, though the calls are asynchronous, the queued component calls are a part of a logical transaction.

Conclusion

By now, you should have, hopefully, understood the idea of transactional messaging and where and how they can be applied. I am not done with MSMQ yet Smile | :) . In the next article, we shall consider some other interesting aspects of MSMQ programming like Message Formatters, Co-related messaging and so on.

 

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here

About the Author

Manoj G
Web Developer
India India
I am a software developer and have worked on Microsoft technologies for about five years now. I have always been fascinated by Microsoft technologies and with the advent of .NET , this fascination has reached new heights. I take a lot of interest reading technical articles and equally enjoy writing them. I really like to be called a .NET junkie and will surely try to live up to this name Smile | :)
 
I am .NET MVP and have also completed MCAD, MCSD(VS 6), MCDBA (SQL Server 2000), MCSA (Win 2K) and MCTS (Distributed Apps) certfications.

Comments and Discussions

 
GeneralCan't prioritise transactional messages PinprofessionalSprint896-Feb-14 0:17 
QuestionMsmq and java PinmemberAsha Arvind28-May-12 4:20 
GeneralMy vote of 3 PinmemberMember 6019422-Apr-12 0:54 
Generalusing a service on server side when a message is arrived Pinmemberraghava1881-Jun-10 8:31 
GeneralRe: using a service on server side when a message is arrived PinmemberMember 98697317-Aug-10 3:08 
GeneralError PinmemberKevmeister6822-Nov-08 11:39 
GeneralRemote MSMQ PinmemberSalman Badar12-Aug-08 10:31 
GeneralRe: Remote MSMQ Pinmembershahid.noor17-Aug-08 23:53 
Generalproblem with enableNotification method in MSMQ 3.0 Pinmembershahid.noor4-Aug-08 2:01 
GeneralMSMQ .Creating Public Queue [modified] PinmemberHeadBlood4-Mar-07 11:02 
GeneralRe: MSMQ .Creating Public Queue Pinmembershahid.noor4-Aug-08 22:28 
GeneralMessage resides in Outgoing Queue only. [modified] PinmemberSachin Gedam6-Oct-06 1:09 
GeneralRe: Message resides in Outgoing Queue only. PinmemberSundar.GSS30-Oct-06 21:34 
GeneralRe: Message resides in Outgoing Queue only. PinmemberSachin Gedam31-Oct-06 17:30 
QuestionHow to use username and password to MQ? PinmemberArmin Kaiser23-May-06 2:19 
QuestionDistributed Transaction using Queued Component PinmemberRavi Sher Singh20-May-06 2:09 
GeneralUsing Cursors Pinmemberbanka_ravi2-May-06 4:29 
GeneralDuplicate message Pinmembersellimuthu27-Mar-06 5:38 
GeneralGetting Ack from MSMQT Pinmemberchinnasrihari6-Dec-05 8:05 
GeneralThere is No MTS Object Context Available Pinmembermurliace16-Nov-05 4:00 
GeneralMSMQ in Distributed Application. Pinmemberrohangandhi8-Aug-05 21:38 
GeneralMessaging Between non-Transactional and Transactional Queues PinsussMorrislgn1-Dec-04 5:25 
Generalasdf PinsussAnonymous8-Nov-04 23:31 
GeneralMSMQ in disconnected environment PinsussAshish Mathur27-Jan-04 15:32 
GeneralQueued Components (VB.NET) PinsussThomas Mathews24-Jul-03 19:49 
GeneralRe: Queued Components (VB.NET) PinmemberManoj G25-Jul-03 23:34 
GeneralA Question Expanding on This PinmemberCedricBertolasio9-Jul-03 4:32 
GeneralRe: A Question Expanding on This PinmemberManoj G9-Jul-03 17:27 
GeneralRe: A Question Expanding on This PinmemberCedricBertolasio9-Jul-03 18:54 
GeneralRe: A Question Expanding on This PinmemberManoj G10-Jul-03 4:29 
GeneralRe: A Question Expanding on This PinmemberCedricBertolasio10-Jul-03 4:46 
GeneralRe: A Question Expanding on This PinmemberStan4th5-Jul-05 5:43 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web02 | 2.8.140721.1 | Last Updated 16 Jun 2003
Article Copyright 2003 by Manoj G
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid