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.
No comments:
Post a Comment