Dec 5, 2007

More on MSMQ

Recoverable messages:

MSMQ messages are stored in memory by default, hence there is a possibility of loosing them if the appdomain exits or the application crashes.
To create messages that get persisted to disk we use Recoverable messages.

Method 1:
Set the Recoverable property on the Message itself before sending it.

Message recoverableMessage = new Message();

recoverableMessage.Body = "Sample Recoverable Message";

recoverableMessage.Recoverable = true;


Method 2:
Use the "DefaultPropertiesToSend.Recoverable" property on MessageQueue itself to mark all messages sent via this queue as recoverable:

MessageQueue msgQ = new MessageQueue(@".\private$\Orders");

msgQ.DefaultPropertiesToSend.Recoverable = true;

msgQ.Send("This message will be marked as Recoverable");

=====================================================
Transactional Messages (Internal transactions)

MessageQueueTransaction msgTx = new MessageQueueTransaction();

MessageQueue msgQ = new MessageQueue(@".\private$\Orders");

msgTx.Begin();

try

{

msgQ.Send("First Message", msgTx);

msgQ.Send("Second Message", msgTx);

msgTx.Commit();

msgTx.Begin();

Message msg = msgQ.Receive(msgTx);

msgTx.Commit();

}

catch

{

msgTx.Abort();

}

finally

{

msgQ.Close();

}

================================================================

External Transactions (using MSDTC and COM+)

====================================================================

using System.EnterpriseServices;

using System.Messaging;

[assembly: ApplicationName("MSMQ_Example")]

[assembly: ApplicationActivation(ActivationOption.Server)]

[Transaction(TransactionOption.Required)]

public class Message : ServicedComponent

{

[AutoComplete()]

public void DoTransaction()

{

//Create the queue

MessageQueue msgQ = new MessageQueue(@".\private$\Orders");

Order incomingOrder;

//Configure the formatter with the expected type(s)

Type[] targetTypes = new Type[1];

targetTypes[0] = typeof(Order);

msgQ.Formatter = new XmlMessageFormatter(targetTypes);

//DB Connection setup code removed

SqlConnection sqlConn = new SqlConnection(connectionString);

SqlCommand insertLog = new SqlCommand(sqlString, sqlConn);

//Command setup code removed

try

{

//Receive new message, casting the result to the Order type

incomingOrder = (Order)(msgQ.Receive(new TimeSpan(0, 0, 30)).Body);

//Use ID from message to setup parameters for database insert

orderIDParam.Value = incomingOrder.ID;

receiveParam.Value = DateTime.Now;

insertLog.Parameters.Add(orderIDParam);

insertLog.Parameters.Add(receiveParam);

sqlConn.Open();

//Insert a new entry into the Log table

insertLog.ExecuteNonQuery();

//Mark the transaction as completing successfully... can be done using ContextUtil.SetComplete

}

catch (Exception ex)

{

//Remember to throw the exception, only then will AutoComplete() abort the transaction

// transaction can be aborted using ContextUtil.Abort if AutoComplete() atribute is not used

throw ex;

}

finally

{

//Always close the connection, regardless of success/failure

sqlConn.Close();

}

}

}


After you create the serviced component, it must be strongly named and then deployed to the GAC so as to work correctly as a COM+ application.


After the component has been installed into the COM+ application, clients can create and call your component just like any other .NET class, and your component will automatically run inside COM+ and act as part of a transaction.

kick it on DotNetKicks.com

No comments: