What is the best way to know if the code block is inside TransactionScope?
Is Transaction.Current a realiable way to do it or there are any subtleties?
Is it possible to access internal ContextData.CurrentData.CurrentScope (in System.Transactions) with reflection? If yes, how?
The TransactionScope class provides a simple way to mark a block of code as participating in a transaction, without requiring you to interact with the transaction itself. A transaction scope can select and manage the ambient transaction automatically.
Ambient TransactionA transaction which automatically identifies a code block that needs to support a transaction without explicitly mentioning any transaction related things. An ambient transaction is not tied just to a database, any transaction aware provider can be used.
Definition: TransactionalScope makes your code block Transactional. You can easily maintain one transaction for multiple databases or a single database with multiple connectionstrings, using TransactionScope. When you use TransactionScope there is no need to close any Database connections in the middle.
Transaction.Current
should be reliable; I've just checked, at this works fine with suppressed transactions, too:
Console.WriteLine(Transaction.Current != null); // false using (TransactionScope tran = new TransactionScope()) { Console.WriteLine(Transaction.Current != null); // true using (TransactionScope tran2 = new TransactionScope( TransactionScopeOption.Suppress)) { Console.WriteLine(Transaction.Current != null); // false } Console.WriteLine(Transaction.Current != null); // true } Console.WriteLine(Transaction.Current != null); // false
Here is more reliable way (as I said, Transaction.Current can be set manually and it doesn't always mean we are really in TransactionScope). It's also possible to get this information with reflection, but emiting IL works 100 times faster than reflection.
private Func<TransactionScope> _getCurrentScopeDelegate; bool IsInsideTransactionScope { get { if (_getCurrentScopeDelegate == null) { _getCurrentScopeDelegate = CreateGetCurrentScopeDelegate(); } TransactionScope ts = _getCurrentScopeDelegate(); return ts != null; } } private Func<TransactionScope> CreateGetCurrentScopeDelegate() { DynamicMethod getCurrentScopeDM = new DynamicMethod( "GetCurrentScope", typeof(TransactionScope), null, this.GetType(), true); Type t = typeof(Transaction).Assembly.GetType("System.Transactions.ContextData"); MethodInfo getCurrentContextDataMI = t.GetProperty( "CurrentData", BindingFlags.NonPublic | BindingFlags.Static) .GetGetMethod(true); FieldInfo currentScopeFI = t.GetField("CurrentScope", BindingFlags.NonPublic | BindingFlags.Instance); ILGenerator gen = getCurrentScopeDM.GetILGenerator(); gen.Emit(OpCodes.Call, getCurrentContextDataMI); gen.Emit(OpCodes.Ldfld, currentScopeFI); gen.Emit(OpCodes.Ret); return (Func<TransactionScope>)getCurrentScopeDM.CreateDelegate(typeof(Func<TransactionScope>)); } [Test] public void IsInsideTransactionScopeTest() { Assert.IsFalse(IsInsideTransactionScope); using (new TransactionScope()) { Assert.IsTrue(IsInsideTransactionScope); } Assert.IsFalse(IsInsideTransactionScope); }
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With