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>));
    }
}
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top