2012-11-24 9 views
97

Sto cercando di integrare async/await nel nostro bus di servizio. Ho implementato un SingleThreadSynchronizationContext in base a questo esempio http://blogs.msdn.com/b/pfxteam/archive/2012/01/20/10259049.aspx.Ottieni TransactionScope per lavorare con async/attendi

E funziona bene, tranne che per una cosa: TransactionScope. Attendo materiale all'interno dello TransactionScope e interrompo lo TransactionScope.

TransactionScope non sembra di bel gioco con il async/await, certamente perché memorizzare le cose nel thread utilizzando ThreadStaticAttribute. Ricevo questa eccezione:

"TransactionScope annidato in modo errato.".

ho cercato di salvare i dati prima di fare la coda TransactionScope il compito e ripristinarlo prima di eseguirlo, ma non sembra cambiare nulla. E il codice TransactionScope è un disastro, quindi è davvero difficile capire cosa sta succedendo lì.

C'è un modo per farlo funzionare? C'è qualche alternativa allo TransactionScope?

+0

Ecco un codice molto semplice per riprodurre un errore di TransactionScope http://pastebin.com/Eh1dxG4a tranne che l'eccezione è qui transazione interrotta – Yann

+0

Potete nit basta utilizzare una transazione SQL regolare? O stai estendendo più risorse? –

+0

Sto attraversando più risorse – Yann

risposta

6

È possibile utilizzare DependentTransaction creato da Transaction.DependentClone() metodo:

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(); 
} 

Managing Concurrency with DependentTransaction

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

+1

L'attività figlio di esempio di Adam Prescott non è stata contrassegnata come asincrona. Se si sostituisce "fare cose transazionali" con qualcosa come "attendere Task.Delay (500)" questo modello fallirà anche con "TransactionScope annidato in modo errato" perché TransactionScope più esterno (non mostrato nell'esempio precedente) esce dall'ambito prima del compito figlio correttamente completa. Sostituisci 'await' con' Task.Wait() 'e funziona, ma poi hai perso i vantaggi di' async'. – mdisibio

+0

Questo è un modo più difficile per risolvere il problema. TransactionScope serve a nascondere tutto ciò che è idraulico. – Eniola

138

In .NET Framework 4.5.1, v'è un insieme di new constructors for TransactionScope che prendere un TransactionScopeAsyncFlowOption parametro.

In base a MSDN, abilita il flusso di transazioni attraverso continuazioni di thread.

mia comprensione è che esso è destinato a consentire di scrivere codice come questo:

// 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(); 
} 
9

po 'tardi per una risposta, ma ho avuto lo stesso problema con MVC4 e ho aggiornato il mio progetto 4,5-4,5 .1 facendo clic con il tasto destro sul progetto vai su Proprietà. Selezionare la scheda dell'applicazione per modificare il framework di destinazione su 4.5.1 e utilizzare la transazione come segue.

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