Reputation: 3428
using System;
using System.Transactions;
namespace ConsoleApplication3
{
public class Program
{
public static void Main(string[] args)
{
var trans = new TransactionScope(TransactionScopeOption.RequiresNew);
try
{
if (!ProcessMessage(true))
{
MoveMessageToErrorQueue();
}
trans.Complete();
}
catch (Exception)
{
trans.Dispose();
}
}
private static bool ProcessMessage(bool throwError)
{
//write to database
var trans = new TransactionScope(TransactionScopeOption.Required);
try
{
if (throwError)
throw new Exception();
trans.Complete();
return true;
}
catch (Exception)
{
trans.Dispose();
}
return false;
}
private static void MoveMessageToErrorQueue()
{
var trans = new TransactionScope(TransactionScopeOption.Required);
trans.Complete();
}
}
}
How can I make the transaction scope inside the MoveMessageToErrorQueue method enlist in the main transaction, not in the one inside the ProcessMessage method?
When it is trying to create a new transaction inside the MoveMessageToErrorQueue I get an exception stating that the transaction has already been aborted.
UPDATE
I get the same result if I use a CommittableTransaction
using System;
using System.Transactions;
namespace ConsoleApplication3
{
public class Program
{
public static void Main(string[] args)
{
using (var trans = new CommittableTransaction())
{
try
{
if (!ProcessMessage(trans, true))
{
MoveMessageToErrorQueue(trans);
}
trans.Commit();
}
catch (Exception)
{
trans.Rollback();
}
}
}
private static bool ProcessMessage(Transaction trans, bool throwError)
{
//write to database
var transScope = new TransactionScope(trans);
try
{
if (throwError)
throw new Exception();
transScope.Complete();
return true;
}
catch (Exception)
{
transScope.Dispose();
}
return false;
}
private static void MoveMessageToErrorQueue(Transaction trans)
{
var transScope = new TransactionScope(trans);
transScope.Complete();
}
}
}
Basically if the transaction within the ProcessMessage method fails I want to be able to still use the same root transaction within the last method.
Thanks for any help.
UPDATE 2
"in DTC transactions (and transactions that use that pattern), failure is fatal and immediate. One the doomed flag is set: it is set."
This says it all. I thought the behaviour was different.
Upvotes: 1
Views: 2476
Reputation: 171178
With nested TransactionScopes there is still only one transaction. Nested scopes do not create a new transaction. Transactions cannot nest. System.Transactions does not support this. Neither does it support savepoints.
When you rollback a nested scope you doom the entire transaction.
I'm not sure how to get the behavior you want. With System.Transactions you have to avoid anything to doom the current transaction. Maybe you can use SQL Server's savepoints to undo the effects that a failing ProcessMessage had. Or, you can use a different DB connection for ProcessMessage and MoveMessageToErrorQueue.
Upvotes: 3
Reputation: 3428
"in DTC transactions (and transactions that use that pattern), failure is fatal and immediate. One the doomed flag is set: it is set."
Upvotes: 1