I have a .NET TransactionScope that needs to contain both a MSSQL database and a IBM MQ queue.
I’m using .NET 4.0 (VS2010), SQL 2008R2, MQ Server 6.0, MQ Client 7.0.1.9 in fully managed mode. All components are running on different machines.
From what I’ve found the following pattern should work:
http://publib.boulder.ibm.com/infocenter/wmqv7/v7r1/index.jsp?topic=%2Fcom.ibm.mq.doc%2Fun11400_.htm
Implicit Transaction
The following piece of code describes how a WebSphere MQ .NET application puts a message using .NET implicit transaction
programming.Using (TransactionScope scope = new TransactionScope ()) { Q.Put
(putMsg,pmo); scope.Complete (); }Q.close(); qMgr.Disconect();}
In my code this looks like:
// mq properties
properties = new Hashtable();
properties.Add(MQC.TRANSPORT_PROPERTY, MQC.TRANSPORT_MQSERIES_MANAGED);
properties.Add(MQC.HOST_NAME_PROPERTY, HOSTNAME);
properties.Add(MQC.PORT_PROPERTY, PORTNUMBER);
properties.Add(MQC.CHANNEL_PROPERTY, CHANNELNAME);
_queueManager = new MQQueueManager(queueManagerName, properties);
_queue = _queueManager.AccessQueue(queueName, MQC.MQOO_INPUT_AS_Q_DEF + MQC.MQOO_FAIL_IF_QUIESCING);
_gmo = new MQGetMessageOptions();
_gmo.Options |= MQC.MQGMO_WAIT;
_gmo.Options |= MQC.MQGMO_SYNCPOINT;
_gmo.WaitInterval = 1000; // 1 seconds wait
// in a loop
using (TransactionScope t = new TransactionScope())
{
var message = new MQMessage();
try
{
_queue.Get(message, _gmo);
}
catch (MQException mqe)
{
message = null;
if (mqe.ReasonCode == 2033)
{
Console.WriteLine("No message available");
}
else
{
throw;
}
}
t.Complete();
}
//Afterwards:
if (_queue != null)
{
_queue.Close();
_queue = null;
}
if (_queueManager != null)
{
_queueManager.Disconnect();
_queueManager.Close();
_queueManager = null;
}
The problem with this is that all messages re-appear in the queue after the application is closed, while the work in the SQL database is committed.
If an exception happens inside the transactionscope, the SQL transaction rolls back while the messages in MQ appear to stay removed (until I restart the application).
Also, I don’t see any DTC activity between the .NET client and the MQ server (is that expected?)
I’m kind of lost here, any help is greatly appreciated.
- Which MQ client should I use? Managed, Unmanaged, XA ?
- Should I see DTC activity? How would I get the managed client to participate?
- Which objects should be created inside the transactionscope?
- Why do messages re-appear on the queue when the application ends even when I commit the transactionscope?
UPDATE
- I’ve had this working with 7.1 on both client and server, but to get that (server) version deployed on our production environment would take too long.
- So I need to work with version 7.0.x on the server side, clientside I can use whatever I need.
- Connecting to a MQ6 server using the 7.1 client fails with errorcode 2354
Well, you need to have at least WebSphere MQ v7.1, both client and queue manager, installed to run global transactions in fully managed mode using the TransactionScope. MS DTC will be the transaction coordinator in this case. The InfoCenter link you posted about is actually pointing to WebSphere MQ v7.1.
Update:
Prior to MQ v7.1, XA transactions are supported only in Unmanaged mode with MTS as the transaction coordinator. Sample code for distributed transaction in unmanaged mode is here. You will require an additional component, Extended Transaction Client(XTC) to be installed. As per latest announcements the XTC is available for free. The installable can be found in your MQ Server installation image.
When a MQ connection is disconnected (basically MQDISC is called), any uncommitted messages in a transaction will be rolled back. Because of this messages reappear on the queue.