Te damos la bienvenida a nuestro sitio web, en este lugar hallarás la respuesta a lo que necesitas.
Solución:
La programación asíncrona “crece” a través del código base. Se ha comparado con un virus zombie. La mejor solución es dejar que crezca, pero a veces eso no es posible.
He escrito algunos tipos en mi biblioteca Nito.AsyncEx para tratar con una base de código parcialmente asíncrona. Sin embargo, no existe una solución que funcione en todas las situaciones.
Solución A
Si tiene un método asíncrono simple que no necesita sincronizarse con su contexto, entonces puede usar Task.WaitAndUnwrapException
:
var task = MyAsyncMethod();
var result = task.WaitAndUnwrapException();
Tú haces no quiere usar Task.Wait
o Task.Result
porque envuelven excepciones en AggregateException
.
Esta solución sólo es adecuada si MyAsyncMethod
no se sincroniza con su contexto. En otras palabras, cada await
en MyAsyncMethod
debería terminar con ConfigureAwait(false)
. Esto significa que no puede actualizar ningún elemento de la interfaz de usuario ni acceder al contexto de solicitud de ASP.NET.
Solución B
Si MyAsyncMethod
necesita sincronizarse con su contexto, entonces puede usar AsyncContext.RunTask
para proporcionar un contexto anidado:
var result = AsyncContext.RunTask(MyAsyncMethod).Result;
*Actualización 14/04/2014: En las versiones más recientes de la biblioteca, la API es la siguiente:
var result = AsyncContext.Run(MyAsyncMethod);
(Está bien usar Task.Result
en este ejemplo porque RunTask
se propagará Task
excepciones).
La razón por la que puede necesitar AsyncContext.RunTask
en lugar de Task.WaitAndUnwrapException
se debe a una posibilidad de interbloqueo bastante sutil que ocurre en WinForms/WPF/SL/ASP.NET:
- Un método síncrono llama a un método asíncrono, obteniendo un
Task
. - El método síncrono hace una espera de bloqueo en el
Task
. - los
async
usos del métodoawait
sinConfigureAwait
. - los
Task
no se puede completar en esta situación porque solo se completa cuando elasync
el método ha terminado; losasync
El método no puede completarse porque está intentando programar su continuación hasta elSynchronizationContext
y WinForms/WPF/SL/ASP.NET no permitirá que se ejecute la continuación porque el método síncrono ya se está ejecutando en ese contexto.
Esta es una de las razones por las que es una buena idea usar ConfigureAwait(false)
dentro de cada async
método tanto como sea posible.
Solución C
AsyncContext.RunTask
no funcionará en todos los escenarios. Por ejemplo, si el async
El método espera algo que requiere un evento de interfaz de usuario para completarse, luego se interbloqueará incluso con el contexto anidado. En ese caso, podría iniciar el async
método en el grupo de subprocesos:
var task = Task.Run(async () => await MyAsyncMethod());
var result = task.WaitAndUnwrapException();
Sin embargo, esta solución requiere una MyAsyncMethod
eso funcionará en el contexto del grupo de subprocesos. Por lo tanto, no puede actualizar los elementos de la interfaz de usuario ni acceder al contexto de solicitud de ASP.NET. Y en ese caso, también puede agregar ConfigureAwait(false)
a su await
enunciados y use la solución A.
Actualización, 2019-05-01: Las “prácticas menos malas” actuales se encuentran en un artículo de MSDN aquí.
Agregar una solución que finalmente resolvió mi problema, con suerte ahorra tiempo a alguien.
En primer lugar, lea un par de artículos de Stephen Cleary:
- Asíncrono y en espera
- No bloquear en código asíncrono
De las “dos mejores prácticas” en “No bloquear en código asíncrono”, la primera no funcionó para mí y la segunda no era aplicable (básicamente si puedo usar await
¡Hago!).
Así que aquí está mi solución: envuelva la llamada dentro de un Task.Run<>(async () => await FunctionAsync());
y ojala no punto muerto ya no.
Aquí está mi código:
public class LogReader
ILogger _logger;
public LogReader(ILogger logger)
_logger = logger;
public LogEntity GetLog()
Task task = Task.Run(async () => await GetLogAsync());
return task.Result;
public async Task GetLogAsync()
var result = await _logger.GetAsync();
// more code here...
return result as LogEntity;
Microsoft creó una clase AsyncHelper (interna) para ejecutar Async como Sync. La fuente se parece a:
internal static class AsyncHelper
private static readonly TaskFactory _myTaskFactory = new
TaskFactory(CancellationToken.None,
TaskCreationOptions.None,
TaskContinuationOptions.None,
TaskScheduler.Default);
public static TResult RunSync(Func> func)
return AsyncHelper._myTaskFactory
.StartNew>(func)
.Unwrap()
.GetAwaiter()
.GetResult();
public static void RunSync(Func func)
AsyncHelper._myTaskFactory
.StartNew(func)
.Unwrap()
.GetAwaiter()
.GetResult();
Las clases base de Microsoft.AspNet.Identity solo tienen métodos Async y para llamarlos como Sync hay clases con métodos de extensión que parecen (uso de ejemplo):
public static TUser FindById(this UserManager manager, TKey userId) where TUser : class, IUser where TKey : IEquatable
if (manager == null)
throw new ArgumentNullException("manager");
return AsyncHelper.RunSync(() => manager.FindByIdAsync(userId));
public static bool IsInRole(this UserManager manager, TKey userId, string role) where TUser : class, IUser where TKey : IEquatable
if (manager == null)
throw new ArgumentNullException("manager");
return AsyncHelper.RunSync(() => manager.IsInRoleAsync(userId, role));
Para aquellos preocupados por los términos de licencia del código, aquí hay un enlace a un código muy similar (solo agrega soporte para cultura en el hilo) que tiene comentarios para indicar que tiene licencia MIT de Microsoft. https://github.com/aspnet/AspNetIdentity/blob/master/src/Microsoft.AspNet.Identity.Core/AsyncHelper.cs
Sección de Reseñas y Valoraciones
Nos encantaría que puedieras mostrar esta división si lograste el éxito.