Nested transaction areas created with object initialization result in an error

In my C # code, I use nested transaction areas. I have a utility class that creates TransactionScope objects the same way. Both external and internal volumes are constructed in exactly the same way.

If I create TransactionScope objects, such as the first example below, the nested transaction areas work well together:

public static TransactionScope CreateTransactionScope() { var transactionOptions = new TransactionOptions(); transactionOptions.IsolationLevel = System.Transactions.IsolationLevel.ReadCommitted; transactionOptions.Timeout = TransactionManager.MaximumTimeout; return new TransactionScope(TransactionScopeOption.Required, transactionOptions); } 

However, I get an exception if I create TransactionScope objects as follows:

 public static TransactionScope CreateTransactionScope() { var transactionOptions = new TransactionOptions { IsolationLevel = System.Transactions.IsolationLevel.ReadCommitted, Timeout = TransactionManager.MaximumTimeout }; return new TransactionScope(TransactionScopeOption.Required, transactionOptions); } 

The error reads: "The transaction specified for TransactionScope has a different IsolationLevel value than the value requested for the scope. Parameter name: transactionOptions.IsolationLevel."

Can someone explain to me why using object initialization leads to this behavior?

+4
source share
2 answers

This error occurs when the isolation level of an external transaction is different from the one you want to assign to the transaction scope. This means that calling your method and trying to assign the required isolation to the transaction manager detects the existence of an existing transaction with a different isolation level and throws an exception.

 var transactionOptions = new TransactionOptions { IsolationLevel = System.Transactions.IsolationLevel.ReadCommitted, Timeout = TransactionManager.MaximumTimeout }; return new TransactionScope(TransactionScopeOption.RequiredNew,TransactionOptions); 

Demand new strength to create a new internal transaction. I suggest doing this dynamic check, which is the current isolation with something similar to this:

 if (Transaction.Current != null && Transaction.Current.IsolationLevel != myIsolationLevel) { scopeOption = TransactionScopeOption.RequiresNew; } 
+2
source

Are you absolutely sure that only switching the above methods will throw an exception? They should be 100% functionally equivalent.

Just a dry run of both options in order:

 using (var aa1 = CreateTransactionScopeGood()) using (var aa2 = CreateTransactionScopeGood()) Console.WriteLine("this will be printed"); using (var aa1 = CreateTransactionScopeBad()) using (var aa2 = CreateTransactionScopeBad()) Console.WriteLine("this will be printed"); 

Could you provide a way to reproduce it?

However, I can only throw an exception when mixing different IsolationScope in one transaction, and this should really lead to an exception:

 using (new TransactionScope(TransactionScopeOption.Required, new TransactionOptions { IsolationLevel = IsolationLevel.Chaos })) using (new TransactionScope(TransactionScopeOption.Required, new TransactionOptions { IsolationLevel = IsolationLevel.Serializable })) Console.WriteLine("this will not be printed"); 
+1
source

All Articles