Necesito llamar a un asyncmétodo en un catchbloque antes de lanzar nuevamente la excepción (con su seguimiento de pila) como este:
try
{
// Do something
}
catch
{
// <- Clean things here with async methods
throw;
}
Pero desafortunadamente no puedes usarlo awaiten un bloque catcho finally. Aprendí que es porque el compilador no tiene forma de retroceder en un catchbloque para ejecutar lo que está después de tu awaitinstrucción o algo así ...
Traté de usar Task.Wait()para reemplazar awaity obtuve un punto muerto. Busqué en la Web cómo podía evitarlo y encontré este sitio .
Como no puedo cambiar los asyncmétodos ni sé si se usan ConfigureAwait(false), creé estos métodos que toman un Func<Task>método que inicia un método asíncrono una vez que estamos en un hilo diferente (para evitar un punto muerto) y espera a que se complete:
public static void AwaitTaskSync(Func<Task> action)
{
Task.Run(async () => await action().ConfigureAwait(false)).Wait();
}
public static TResult AwaitTaskSync<TResult>(Func<Task<TResult>> action)
{
return Task.Run(async () => await action().ConfigureAwait(false)).Result;
}
public static void AwaitSync(Func<IAsyncAction> action)
{
AwaitTaskSync(() => action().AsTask());
}
public static TResult AwaitSync<TResult>(Func<IAsyncOperation<TResult>> action)
{
return AwaitTaskSync(() => action().AsTask());
}
Entonces mi pregunta es: ¿Crees que este código está bien?
Por supuesto, si tiene algunas mejoras o conoce un enfoque mejor, ¡lo escucho! :)
fuente

awaiten un bloque de captura está realmente permitido desde C # 6.0 (vea mi respuesta a continuación)Respuestas:
Puede mover la lógica fuera del
catchbloque y volver a lanzar la excepción después, si es necesario, usandoExceptionDispatchInfo.De esta forma, cuando la persona que llama inspecciona la
StackTracepropiedad de la excepción , aún registra dóndeTaskThatFailsse lanzó.fuente
ExceptionDispatchInfolugar deException(como en la respuesta de Stephen Cleary)?Exception, ¿perderás todo el anteriorStackTrace?Debe saber que desde C # 6.0, es posible usar
awaitincatchyfinallyblocks, por lo que de hecho podría hacer esto:Las nuevas características de C # 6.0, incluida la que acabo de mencionar, se enumeran aquí o en un video aquí .
fuente
Si necesita utilizar
asynccontroladores de errores, le recomiendo algo como esto:El problema con el bloqueo sincrónico en el
asynccódigo (independientemente del hilo en el que se esté ejecutando) es que está bloqueando sincrónicamente. En la mayoría de los escenarios, es mejor usarawait.Actualización: ya que necesita volver a lanzar, puede usar
ExceptionDispatchInfo.fuente
throw exception;en laifdeclaración, se perderá el seguimiento de la pila.Se extrajeron gran respuesta de hvd a la siguiente clase de utilidad reutilizables en nuestro proyecto:
Uno lo usaría de la siguiente manera:
Siéntase libre de mejorar el nombre, lo mantuvimos intencionalmente detallado. Tenga en cuenta que no es necesario capturar el contexto dentro del contenedor, ya que ya está capturado en el sitio de la llamada, por lo tanto
ConfigureAwait(false).fuente