Transactional messaging is the process of sending and receiving messages in transactions. A transaction is a set of one or more messages. Transactional messages are grouped inside a transaction context, which keeps track of the transaction states.
Transaction processing ensures two things: that all messages bundled in a transaction either are delivered together in order or that none of the messages participating in a transaction are sent if there's a failure in transaction. The success of a transaction is called a committed transaction, and the failure of a transaction is called an aborted transaction.
In message queuing, there are two types of transactions: internal and external. In the internal transaction process, the message transfer happens between two queues belonging to a queuing server. On the other hand, an external transaction involves message transfer between a queue and other resources (not related to queuing) such as a database. This chapter discusses internal transactions only.
The MessageQueueTransaction class represents an internal transaction. This class has a property called Status, which represents the status of the transaction. The status of a transaction is of type MessageQueueTrasactionStatus enumeration type. It has four values: Aborted, Committed, Initialized, and Pending.
The Aborted value represents the transaction has been aborted, and there will be no changes in the current state of the messages. The Committed value indicates that the transaction has been committed and all message were sent as expected. The Initialized value indicates that the transaction has been initialized but not started yet. The Pending value represents that the transaction has been started and is still in process.
Besides the Status property, the MessageQueueTransaction has three methods: Abort, Begin, and Commit. The Abort method rolls back the pending transaction. The Begin method starts a transaction, and the Commit method saves the pending transactions.
To create an internal transaction, you can use the Create method of MessageQueueTransaction, and when you're sure you want to commit or roll back the transaction, you call Commit or Abort methods.
Do you remember when you created a new message queue in the Server Explorer using the Create Queue menu option? When you create a queue using the Server Explorer, there's a check box on the dialog box that allows you to create a transactional queue (see Figure 21-6).
Figure 21-6: Creating a transactional queue using the Server Explorer
Creating a transactional message queue programmatically is pretty simple. When you use the Create method of MessageQueue, you pass the second argument as true to create a transactional message queue. For example, the following code creates a transactional queue:
Dim mq as New MessageQueue mq =MessageQueue.Create(".\mcbTransQueue", True)
When creating a transactional queue, the Send and Receive methods of MessageQueue take the last argument as the transaction object. Listing 21-9 shows how to send and receive transactional messages. As you can see from this code, the transaction is only committed where there were no errors; otherwise, the transaction is aborted.
Listing 21-9: Sending and Receiving Transactional Messages
Imports System Imports System.Messaging Module Module1 Sub Main() 'SendTransactionalMessages() RecieveTransactionalMessages() End Sub Public Sub SendTransactionalMessages() Dim mq As MessageQueue = New MessageQueue() mq = MessageQueue.Create(".\Private$\mcbTQ", True) Dim tran As MessageQueueTransaction = _ New MessageQueueTransaction() Try tran.Begin() mq.Send("Body of first message", "Message1", tran) mq.Send("Body of second message", "Message2", tran) mq.Send("Body of third message", "Message3", tran) tran.Commit() Console.WriteLine("Transaction committed!") Catch tran.Abort() Console.WriteLine("Transaction Aborted!") End Try End Sub Public Sub RecieveTransactionalMessages() Dim mq As MessageQueue = New MessageQueue() mq.Path = ".\Private$\mcbTQ" Dim tran As MessageQueueTransaction = _ New MessageQueueTransaction() Try tran.Begin() Dim messages() As System.Messaging.Message messages = mq.GetAllMessages() ' Need a formatter to get the text of the message body. Dim stringFormatter As System.Messaging.XmlMessageFormatter = _ New System.Messaging.XmlMessageFormatter(New String() _ {"System.String"}) Dim index As Integer Dim msg As System.Messaging.Message For index = 0 To messages.Length - 1 messages(index).Formatter = stringFormatter msg = messages(index) Console.WriteLine(msg.Label + "," + msg.Body) Next tran.Commit() Console.WriteLine("Transaction committed!") Catch tran.Abort() Console.WriteLine("Transaction Aborted!") End Try End Sub End Module
Tip | Transactional processing is useful when you want to make sure that all messages in a transaction are delivered or none of them are. |