Question

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.

Was it helpful?

Solution

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.

OTHER TIPS

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>));
    }
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top