Obtenha o TransactionScope para trabalhar com async / await

Estou tentando integrar async / await no nosso barramento de serviço. Implementei um SingleThreadSynchronizationContext base neste exemplo http://blogs.msdn.com/b/pfxteam/archive/2012/01/20/10259049.aspx .

E funciona bem, exceto por uma coisa: TransactionScope . Aguardo o material dentro do TransactionScope e ele quebra o TransactionScope .

TransactionScope parece não funcionar bem com o async / await , certamente porque armazena coisas no thread usando ThreadStaticAttribute . Eu recebo esta exceção:

“TransactionScope nested incorretamente.”

Tentei salvar os dados do TransactionScope antes de enfileirar a tarefa e restaurá-la antes de executá-la, mas isso não parece mudar nada. E o código TransactionScope é uma bagunça, então é muito difícil entender o que está acontecendo lá.

Existe uma maneira de fazer isso funcionar? Existe alguma alternativa ao TransactionScope ?

    No .NET Framework 4.5.1, há um conjunto de novos construtores para o TransactionScope que usam um parâmetro TransactionScopeAsyncFlowOption .

    De acordo com o MSDN, ele permite o stream de transactions nas continuações do thread.

    Meu entendimento é que isso significa que você pode escrever código como este:

     // transaction scope using (var scope = new TransactionScope(... , TransactionScopeAsyncFlowOption.Enabled)) { // connection using (var connection = new SqlConnection(_connectionString)) { // open connection asynchronously await connection.OpenAsync(); using (var command = connection.CreateCommand()) { command.CommandText = ...; // run command asynchronously using (var dataReader = await command.ExecuteReaderAsync()) { while (dataReader.Read()) { ... } } } } scope.Complete(); } 

    Pouco atrasado para uma resposta, mas eu estava tendo o mesmo problema com MVC4 e atualizei meu projeto de 4.5 para 4.5.1 clicando com o botão direito do mouse no projeto ir para propriedades. Selecione a guia de aplicativo para alterar a estrutura de destino para 4.5.1 e use a transação da seguinte forma.

     using (AccountServiceClient client = new AccountServiceClient()) using (TransactionScope scope = new TransactionScope(TransactionScopeAsyncFlowOption.Enabled)) { } 

    Você pode usar o DependentTransaction criado pelo método Transaction.DependentClone () :

     static void Main(string[] args) { // ... for (int i = 0; i < 10; i++) { var dtx = Transaction.Current.DependentClone( DependentCloneOption.BlockCommitUntilComplete); tasks[i] = TestStuff(dtx); } //... } static async Task TestStuff(DependentTransaction dtx) { using (var ts = new TransactionScope(dtx)) { // do transactional stuff ts.Complete(); } dtx.Complete(); } 

    Gerenciando a simultaneidade com o DependentTransaction

    http://adamprescott.net/2012/10/04/transactionscope-in-multi-threaded-applications/