HOWTO: Using MSMQ Within an MTS Component in Visual Basic

ID: Q175726

The information in this article applies to:

SUMMARY

This article describes using Microsoft Message Queue Server (MSMQ) from within Microsoft Transaction Server (MTS) components written with Visual Basic. The two MSMQ transactional operations available are the Message Send and Receive operations.

MSMQ send operations can be included in MTS transactions. This action causes the Send operation to be either committed or rolled back along with the MTS transaction. As a result the message is not actually sent until the transaction commits. To include the Send operation in a transaction, use the MQ_MTS_TRANSACTION constant as the Transaction parameter of the MSMQMessage.Send method from within a transactional MTS component. MSMQ enlists the Send operation in the MTS transaction. The destination queue must be a transactional queue. Note that MQ_MTS_TRANSACTION is the default value of the optional Transaction parameter on Send/Receive; thus, it can be omitted to obtain MTS transaction behavior.

Transactional messages can be sent only to a transactional destination queue. If the MTS component is not participating in a transaction, the Send operation described above fails. This is because the message would be non-transactional, and you cannot send a nontransactional message to a transactional queue. You cannot always predict whether a component will participate in a transaction. Therefore, it is important to verify that the component is participating in the transaction and to use MQ_MTS_TRANSACTION in the MSMQMessage.Send to a transactional queue only if it is participating. If it is not participating, use the MQ_NO_TRANSACTION or MQ_SINGLE_MESSAGE constant with the appropriate queue type.

The component is participating in the transaction if it is marked as "Requires [new] Transactions" in MTS Explorer. The component is not participating in the transaction if it is marked as "Does Not Support Transactions."

When the MTS component is marked as "Supports Transaction," it also participates in a transaction if its caller participates. To send from such a component, you must dynamically check for the current transaction existence (use method ObjectContext.IsInTransaction)and use an appropriate Transaction flag and destination queue.

For a local MSMQ transactional queue receive operation, specifying MQ_MTS_TRANSACTION works regardless of whether the component is transactional or not. The receive operation is included in a transaction only if the component is transactional.

MORE INFORMATION

The following Visual Basic code demonstrates sending an MSMQ message containing a string from within an MTS component. The MTS context object is used to commit or abort the transaction. The context object's IsInTransaction() method is used to determine whether or not the component is transactional.

   Public Function MQSend(strSend As String) As String

   Dim qinfoSend As New MSMQQueueInfo
   Dim qSend As MSMQQueue
   Dim qmesMessage As New MSMQMessage

   On Error GoTo SendError

   Dim ctxObject As ObjectContext
   Set ctxObject = GetObjectContext

   ' Add code for database updates if needed.

   qinfoSend.PathName = ".\Localx"
   Set qSend = qinfoSend.Open(MQ_SEND_ACCESS, MQ_DENY_NONE)

   qmesMessage.Body = strSend
   qmesMessage.Label = "VB Sample Message"

   'Since you must send to a transactional MSMQ queue in order to
   'participate in a transaction, you must check to see if the component
   'is transactional and be sure to make the send operation
   'transactional in either case.

   If (ctxObject.IsInTransaction) Then
     qmesMessage.Send qSend, MQ_MTS_TRANSACTION
   Else
     qmesMessage.Send qSend, MQ_SINGLE_MESSAGE
   End If
   qSend.Close

   ctxObject.SetComplete
   Set ctxObject = Nothing
   Exit Function

   SendError:
   ctxObject.SetAbort
   Set ctxObject = Nothing

   MQSend = "SendFailure"
   End Function

The following Visual Basic code demonstrates receiving an MSMQ message containing a string from within an MTS component. The MTS context object is used to commit or abort the transaction.

   Public Function MQReceive(strReceive As String) As String

   Dim qinfoRcv As New MSMQQueueInfo
   Dim qRcv As MSMQQueue
   Dim qmesMessage As MSMQMessage

   On Error GoTo RcvError

   Dim ctxObject As ObjectContext
   Set ctxObject = GetObjectContext

   ' Add code for database updates if needed.

   qinfoRcv.PathName = ".\Localx"
   Set qRcv = qinfoRcv.Open(MQ_RECEIVE_ACCESS, MQ_DENY_NONE)

   Set qmesMessage = qRcv.Receive(Transaction:=MQ_MTS_TRANSACTION,
   ReceiveTimeout:=0)

   ' or since MQ_MTS_TRANSACTION is the default, simply:
   ' Set qmesMessage = qRcv.Receive(ReceiveTimeout:=0)

   If (Not qmesMessage Is Nothing) Then
     strReceive = qmesMessage.Body
     MQReceive = "MessageReceived"
   Else
     MQReceive = "NoMessage"
   End If
   qRcv.Close

   ctxObject.SetComplete
   Set ctxObject = Nothing
   Exit Function

   RcvError:
   ctxObject.SetAbort
   Set ctxObject = Nothing

   MQReceive = "ReceiveFailure"
   End Function

REFERENCES

For more details on using a single queue for send/receive and to avoid queue and component type mismatch, see the following Knowledge Base article:

   ARTICLE-ID: Q174387
   TITLE     : "INFO: Using a Single MSMQ Queue for an MTS Component"

Additional query words: viper falcon
Keywords          : kbcode MQProg MQVB 
Version           : WINDOWS:5.0; WINNT:1.0
Platform          : WINDOWS winnt
Issue type        : kbhowto

Last Reviewed: May 2, 1998