¿Por qué no puedo atrapar una excepción del código asíncrono?

Donde sea que lo lea dice que el siguiente código debería funcionar, pero no es así.

public async Task DoSomething(int x) { try { // Asynchronous implementation. await Task.Run(() => { throw new Exception(); x++; }); } catch (Exception ex) { // Handle exceptions ? } } 

Dicho esto, no estoy captando nada y obtengo una “excepción no controlada” que se origina en la línea ‘tiro’. No tengo ni idea aquí.

Tiene activada la opción “Just my code”. Con esto encendido, está considerando la excepción no controlada con respecto a “solo su código”, porque otro código captura la excepción y la inserta dentro de una Tarea, que luego se volverá a lanzar en la llamada aguardada y captada por su statement de captura.

Sin estar conectado en el depurador, se activará su instrucción catch y se ejecutará como espera. O puede continuar desde el depurador y se ejecutará como se esperaba.

Lo mejor que puedes hacer es desactivar “Solo mi código”. IMO, causa más confusión de lo que vale.

Como dijo SLaks, tu código funciona bien.

Sospecho que super simplificó su ejemplo y tiene un async void en su código.

Lo siguiente funciona bien :

 private static void Main(string[] args) { CallAsync(); Console.Read(); } public static async void CallAsync() { try { await DoSomething(); } catch (Exception) { // Handle exceptions ? Console.WriteLine("In the catch"); } } public static Task DoSomething() { return Task.Run(() => { throw new Exception(); }); } 

Lo siguiente no funciona :

 private static void Main(string[] args) { CallAsync(); Console.Read(); } public static void CallAsync() { try { DoSomething(); } catch (Exception) { // Handle exceptions ? Console.WriteLine("In the catch"); } } public static async void DoSomething() { await Task.Run(() => { throw new Exception(); }); } 

Ver http://msdn.microsoft.com/en-us/magazine/jj991977.aspx

Los métodos Async void tienen una semántica distinta para el manejo de errores. Cuando se descarta una excepción de una tarea asíncrona o un método de tarea asincrónica, esa excepción se captura y se coloca en el objeto Tarea. Con los métodos de anync void, no hay ningún objeto Task, por lo que cualquier excepción lanzada fuera de un método async void se generará directamente en el SynchronizationContext que estaba activo cuando se inició el método async void. La Figura 2 ilustra que las excepciones lanzadas desde los métodos de vacío asíncrono no se pueden capturar de forma natural.

Su código ni siquiera se comstackrá limpiamente en este momento, como el x++; statement es inalcanzable. Siempre preste atención a las advertencias.

Sin embargo, después de arreglar eso, funciona bien:

 using System; using System.Threading.Tasks; class Test { static void Main(string[] args) { DoSomething(10).Wait(); } public static async Task DoSomething(int x) { try { // Asynchronous implementation. await Task.Run(() => { throw new Exception("Bang!"); }); } catch (Exception ex) { Console.WriteLine("I caught an exception! {0}", ex.Message); } } } 

Salida:

 I caught an exception! Bang! 

(Tenga en cuenta que si prueba el código anterior en una aplicación WinForms, tendrá un punto muerto porque estaría esperando una tarea que necesitaba volver al hilo de la interfaz de usuario. Estamos bien en una aplicación de consola como la tarea se reanudará en una secuencia de subprocesos).

Sospecho que el problema es simplemente una cuestión de depuración: el depurador puede considerarlo no manejado, aunque se maneje.

En lugar de usar Task.Result , acceda a la propiedad Task.Result y try y Task.Result ese acceso. También puede seguir el ejemplo aquí y probar ese estilo.

Tenga en cuenta que todas las excepciones arrojadas dentro del contexto de una cadena de tarea están incluidas en una AggregateException .

La excepción no es cuaght. El motivo es – cuando se ejecuta la statement siguiente

 await Task.Run(() => { throw new Exception("Bang!"); }); 

está en un hilo separado. La excepción planteada en ese hilo no se detecta.

cámbielo para que se vea como a continuación

 await Task.Run(() => { try { throw new Exception("Bang!"); } catch (Exception ex) { Console.WriteLine(ex.Message); } });