检查现有的transactioncope是否处于活动状态

时间:2012-12-12 10:08:33

标签: c# transactions transactionscope nested-transactions

我正在使用:

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);
    }
}

创建我的所有交易。我遇到的问题是当我嵌套2 TransactionUtils.CreateTransactionScope()时出现错误:Time-out interval must be less than 2^32-2. Parameter name: dueTm。我假设这是因为它试图将子事务附加到父事务处理,并且组合的超时时间很长。

有没有办法判断新创建的事务是否是嵌套事务,这样我可以避免设置超时?

另一种方法是将一个参数传递给CreateTransactionScope(),这样我就可以告诉它它是嵌套的而不是设置超时但我宁愿找到一种自动处理它的方法。

2 个答案:

答案 0 :(得分:28)

有一个非常简单的答案:

System.Transactions.Transaction.Current != null

自Framework 2.0以来一直有效。

我不确定为什么另一个答案会如此深入,以创建链接到非公共领域的IL。

答案 1 :(得分:1)

是的,这是可能的。我有以下代码。我没有自己做,但忘记了我得到它的地方。感谢原作者,但我记得我刚发现它谷歌搜索它。我正在将它用于.net 4.0,不知道这与其他版本的兼容性(它取决于特定程序集中的特定类)。

使用下面的代码,您可以检查代码中的某个位置是否正在执行“内部”事务范围。

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>));
    }
}