run - create async method c#
Obtener TransactionScope para trabajar con async/await (3)
async
integrar async
/ await
en nuestro bus de servicio. Implementé un SingleThreadSynchronizationContext
basado en este ejemplo http://blogs.msdn.com/b/pfxteam/archive/2012/01/20/10259049.aspx .
Y funciona bien, excepto por una cosa: TransactionScope
. Espero cosas dentro de TransactionScope
y rompe el TransactionScope
.
TransactionScope
no parece funcionar bien con async
/ await
, sin duda porque almacena cosas en el hilo usando ThreadStaticAttribute
. Obtengo esta excepción:
"TransactionScope anidado incorrectamente".
Traté de guardar los datos de TransactionScope
antes de poner en cola la tarea y restaurarla antes de ejecutarla, pero parece que no cambia nada. Y el código de TransactionScope
es un desastre, por lo que es realmente difícil entender lo que sucede allí.
¿Hay alguna manera de hacerlo funcionar? ¿Hay alguna alternativa a TransactionScope
?
En .NET Framework 4.5.1, hay un conjunto de nuevos constructores para TransactionScope que toman un parámetro TransactionScopeAsyncFlowOption .
De acuerdo con MSDN, permite el flujo de transacciones a través de continuaciones de subprocesos.
Según entiendo, está destinado a permitir que escribas 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();
}
Puede usar DependentTransaction creado por el 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();
}
Administrar la concurrencia con DependentTransaction
http://adamprescott.net/2012/10/04/transactionscope-in-multi-threaded-applications/
Un poco tarde para obtener una respuesta, pero estaba teniendo el mismo problema con MVC4 y actualicé mi proyecto de 4.5 a 4.5.1 haciendo clic derecho en el proyecto, vaya a las propiedades. Seleccione la pestaña de la aplicación, cambie el marco de destino a 4.5.1 y use la transacción de la siguiente manera.
using (AccountServiceClient client = new AccountServiceClient())
using (TransactionScope scope = new TransactionScope(TransactionScopeAsyncFlowOption.Enabled))
{
}