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?
知道代码块是否在TransactionScope中最好的方法是什么?是事务。当前一种可实现的方法,还是有任何微妙之处?是否可以访问内部ContextData.CurrentData。有反射的当前范围(系统。事务)?如果是,如何?
2 个解决方案
#1
37
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
#2
4
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.
这里有更可靠的方法(如我所说,交易)。电流可以手动设置,并不总是意味着我们真的在TransactionScope中。也有可能通过反射获得这些信息,但是emiting IL的工作速度比反射快100倍。
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);
}
#1
37
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
#2
4
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.
这里有更可靠的方法(如我所说,交易)。电流可以手动设置,并不总是意味着我们真的在TransactionScope中。也有可能通过反射获得这些信息,但是emiting IL的工作速度比反射快100倍。
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);
}