There's a pretty simple answer:
System.Transactions.Transaction.Current != null
This works since Framework 2.0.
I'm not sure why the other answer goes to such depths to create IL that links to nonpublic fields.
문제
I am using:
public class TransactionUtils
{
public static TransactionScope CreateTransactionScope()
{
var TransactionOptions = new TransactionOptions();
TransactionOptions.IsolationLevel = System.Transactions.IsolationLevel.ReadCommitted;
TransactionOptions.Timeout = TimeSpan.MaxValue;
return new TransactionScope(TransactionScopeOption.Required, TransactionOptions);
}
}
to create all my transactions. The problem I am facing is when I nest 2 TransactionUtils.CreateTransactionScope()
I get an error: Time-out interval must be less than 2^32-2. Parameter name: dueTm
. I am assuming this is because it's trying to attach the child transaction to the parent one and the combined timeouts are to large.
Is there a way to tell if a newly created transaction will be a nested one so I can avoid setting a timeout?
The alternative is to pass a parameter to CreateTransactionScope()
so I can tell it that's it's nested and not set the timeout but I would rather find an automatic way of handling it.
해결책
There's a pretty simple answer:
System.Transactions.Transaction.Current != null
This works since Framework 2.0.
I'm not sure why the other answer goes to such depths to create IL that links to nonpublic fields.
다른 팁
Yep it is possible. I have the following code. I didn't make it myself but forgot where I got it. Kudos to the original author, but I do remember I just found it googling for it. I'm using it for .net 4.0, no idea how compatible this is with other versions (it depends on a specific class in a specific assembly).
Using the code below you can check if at some point in your code if you are executing 'inside' a transaction scope.
class TransactionScopeDetector {
private Func<TransactionScope> _getCurrentScopeDelegate;
public 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>));
}
}