When using Castle.Facilities.AutoTx
facility with [Transaction(TransactionScopeOption.RequiresNew)]
attribute, the expected new System.Transactions.CommittableTransaction
is not created.
You can easily test it with the following unit test
using System.Transactions;
using Castle.Facilities.AutoTx.Testing;
using Castle.MicroKernel.Registration;
using Castle.Transactions;
using Castle.Windsor;
using NUnit.Framework;
namespace Castle.Facilities.AutoTx.Tests
{
public class TransService
{
private readonly NewTransService _s2;
public TransService(NewTransService s2)
{
_s2 = s2;
}
[Transaction]
public virtual string DoInTrans()
{
var currentTransaction = System.Transactions.Transaction.Current;
Assert.That(currentTransaction != null, "The current transaction mustn't be null.");
string transId = currentTransaction.TransactionInformation.LocalIdentifier;
_s2.DoInNewTrans(transId);
return transId;
}
}
public class NewTransService
{
[Transaction(TransactionScopeOption.RequiresNew)]
public virtual string DoInNewTrans(string parentTransId)
{
var currentTransaction = System.Transactions.Transaction.Current;
Assert.That(currentTransaction != null, "The current transaction mustn't be null.");
string transId = currentTransaction.TransactionInformation.LocalIdentifier;
Assert.AreNotEqual(parentTransId, transId, "Ambient transaction must differ from parent");
return transId;
}
}
public class SingleThread_NewAmbient
{
private WindsorContainer _Container;
[SetUp]
public void SetUp()
{
_Container = new WindsorContainer();
_Container.AddFacility<AutoTxFacility>();
_Container.Register(Component.For<TransService>());
_Container.Register(Component.For<NewTransService>());
}
[TearDown]
public void TearDown()
{
_Container.Dispose();
}
[Test]
public void Automatically_Starts_New_CommitableTransaction()
{
using (var scope = new ResolveScope<TransService>(_Container))
scope.Service.DoInTrans();
}
}
}
Am I misunderstanding the purpose of [Transaction(TransactionScopeOption.RequiresNew)]
or is it a bug?
I have been digging into the Castle.Transactions
source code and I was able to fix the behavior by changing following piece of code in Castle.Transactions.TransactionManager.ITransactionManager.CreateTransaction(ITransactionOptions transactionOptions)
:
if (activity.Count == 0)
tx = new Transaction(new CommittableTransaction(new TransactionOptions
...
to
if (activity.Count == 0 || transactionOptions.Mode == TransactionScopeOption.RequiresNew)
tx = new Transaction(new CommittableTransaction(new TransactionOptions
...
Can someone from Castle experts / owners check this?