Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to support async methods in a TransactionScope with Microsoft.Bcl.Async in .NET 4.0? [duplicate]

Tags:

I have a method similar to:

public async Task SaveItemsAsync(IEnumerable<MyItem> items) {     using (var ts = new TransactionScope())     {         foreach (var item in items)         {             await _repository.SaveItemAsync(item);         }          await _repository.DoSomethingElse();          ts.Complete();     } } 

This of course has issues because TransactionScope doesn't play nice with async/await.

It fails with an InvalidOperationException with the message:

"A TransactionScope must be disposed on the same thread that it was created."

I read about TransactionScopeAsyncFlowOption in this answer, which appears to be exactly what I need.

However, for this particular project, I have a hard requirement to support .Net 4.0 and cannot upgrade to 4.5 or 4.5.1. Thus the async/await behavior in my project is provided by the Microsoft.Bcl.Async NuGet Package.

I can't seem to find TransactionScopeAsyncFlowOption in this or any other OOB package. Am I just missing it somewhere?

If it is not available, is there an alternative for achieving the same result? That is - I would like the transaction scope to properly complete or rollback, despite crossing threads with continuations.

I added DoSomethingElse in the example above to illustrate that there may be multiple calls to make within the transaction scope, so simply passing all items to the database in one call is not a viable option.

In case it matters, the repository uses direct ADO.Net (SqlConnection, SqlCommand, etc) to write to a SQL Server.

UPDATE 1

I thought I had a solution which involved taking System.Transactions.dll from .Net 4.5.1 and including it in my project. However, I found that this worked only on my dev box because it already had 4.5.1 installed. It did not work when deploying to a machine with only .Net 4.0. It just gave a MissingMethodException. I'm looking for a solution that will work on a .Net 4.0 installation.

UPDATE 2

I originally asked this question in July 2014. .NET Framework 4.0, 4.5, and 4.5.1 reached end of life in January 2016. The question thus is no longer applicable and is here only for historical reference.

like image 847
Matt Johnson-Pint Avatar asked Jul 06 '14 05:07

Matt Johnson-Pint


1 Answers

It is not possible to achieve this in .NET Framework 4.0. Additionally, .NET Framework 4.0 reached end of life on 2016-01-12, and thus is no longer relevant.

To support transaction scope in async methods in .NET going forward (since .NET Framework 4.5.1), use TransactionScopeAsyncFlowOption.Enabled

public static TransactionScope CreateAsyncTransactionScope(IsolationLevel isolationLevel = IsolationLevel.ReadCommitted)     {         var transactionOptions = new TransactionOptions         {             IsolationLevel = isolationLevel,             Timeout = TransactionManager.MaximumTimeout         };         return new TransactionScope(TransactionScopeOption.Required, transactionOptions, TransactionScopeAsyncFlowOption.Enabled);     } 
like image 62
Henrik Hjalmarsson Avatar answered Oct 11 '22 14:10

Henrik Hjalmarsson