J'essaie d'intégrer async
/await
dans notre bus de service. J'ai implémenté un SingleThreadSynchronizationContext
basé sur cet exemple http://blogs.msdn.com/b/pfxteam/archive/2012/01/20/10259049.aspx .
Et cela fonctionne très bien, sauf pour une chose: TransactionScope
. J'attends des trucs à l'intérieur du TransactionScope
et ça casse le TransactionScope
.
TransactionScope
ne semble pas jouer à Nice avec le async
/await
, certainement parce qu'il stocke les choses dans le thread en utilisant ThreadStaticAttribute
. Je reçois cette exception:
"TransactionScope imbriqué incorrectement.".
J'ai essayé de sauvegarder les données de TransactionScope
avant de mettre la tâche en file d'attente et de la restaurer avant de l'exécuter, mais cela ne semble rien changer. Et le code TransactionScope
est un gâchis, il est donc très difficile de comprendre ce qui se passe là-bas.
Existe-t-il un moyen de le faire fonctionner? Existe-t-il une alternative à TransactionScope
?
Dans .NET Framework 4.5.1, il existe un ensemble de nouveaux constructeurs pour TransactionScope
qui prennent un paramètre TransactionScopeAsyncFlowOption
.
Selon le MSDN, il permet le flux de transactions entre les suites de threads.
Ma compréhension est que cela est destiné à vous permettre d'écrire du code comme ceci:
// 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();
}
Un peu tard pour une réponse, mais j'avais le même problème avec MVC4 et j'ai mis à jour mon projet de 4.5 à 4.5.1 en cliquant avec le bouton droit sur le projet, accédez aux propriétés. Sélectionnez l'onglet d'application pour changer le cadre cible en 4.5.1 et utilisez la transaction comme suit.
using (AccountServiceClient client = new AccountServiceClient())
using (TransactionScope scope = new TransactionScope(TransactionScopeAsyncFlowOption.Enabled))
{
}
Vous pouvez utiliser la méthode DependentTransaction créée par la méthode 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();
}
Gestion de la concurrence avec DependentTransaction
http://adamprescott.net/2012/10/04/transactionscope-in-multi-threaded-applications/