2012-07-26 9 views
5

Estoy tratando de ajustar las excepciones que puede lanzar una tarea asincrónica usando ContinueWith(). Si acabo de lanzar desde la acción de continuación, las cosas parecen funcionar, pero mi depurador afirma que la excepción no se ha manejado. ¿Estoy haciendo algo mal o es este un problema de Visual Studio? ¿Hay alguna manera más clara de hacerlo, o una forma de evitar que mi depurador se detenga en lo que finalmente es una excepción manejada?Disparando excepciones de ContinueWith

La siguiente prueba pasa e imprime "excepción envuelta capturada como se esperaba", pero cuando la depuro la línea throw new CustomException muestra como "no controlada por el código de usuario".

var task = DoWorkAsync().ContinueWith(t => { 
    throw new CustomException("Wrapped", t.Exception.InnerException); // Debugger reports this unhandled 
}, TaskContinuationOptions.OnlyOnFaulted | TaskContinuationOptions.ExecuteSynchronously); 

try { 
    task.Wait(); 
    Assert.Fail("Expected work to fail"); 
} catch (AggregateException ag) { 
    if (!(ag.InnerException is CustomException)) 
     throw; 
} 
Console.WriteLine("Caught wrapped exception as expected"); 

Respuesta

9

Cuando "Just My Code" está habilitado, Visual Studio en algunos casos saltará en la línea que arroja la excepción y mostrará un mensaje de error que dice "excepción no manejada por el código de usuario". Este error es benigno Puede presionar F5 para continuar y ver el comportamiento de manejo de excepciones que se demuestra en estos ejemplos. Para evitar que Visual Studio rompa el primer error, simplemente desmarque la casilla de verificación "Just My Code" en Herramientas, Opciones, Depuración, General.

De http://msdn.microsoft.com/en-us/library/dd997415.aspx

4

No parece ser "envolver" las excepciones con una continuación, que parecen estar lanzando la excepción en la continuación. Si DoWorkAsync es lo que puede lanzar una excepción, me gustaría "wrap" que, en la continuación de la siguiente manera:

DoWorkAsync().ContinueWith(t=>{ 
Console.WriteLine("Error occurred: " + t.Exception); 
}, TaskContinuationOptions.OnlyOnFaulted); 

Alternativamente, si quieres "manejar" la excepción fuera del método asíncrono, usted puede hacer esto:

var task = DoWorkAsync(); 

task.Wait(); 
if(task.Exception != null) 
{ 
    Console.WriteLine("Error occurred: " + task.Exception); 
} 

Si desea transformar la excepción lanzada, se podría hacer algo como esto:

var task = DoWorkAsync().ContinueWith(t=>{ 
if(t.Exception.InnerExceptions[0].GetType() == typeof(TimeoutException)) 
{ 
    throw new BackoffException(t.Exception.InnerExceptions[0]); 
} 
}, TaskContinuationOptions.OnlyOnFaulted); 

y se podía manejar eso BackoffException así:

+0

clave aquí, es que hay que acceder a la propiedad de excepción (o tienen la excepción re-lanzada dentro de un AggregateException accediendo a la propiedad de tareas .Result (si tiene una tarea ) ... –

+0

DoWorkAsync() puede arrojar un montón de excepciones diferentes, y estoy tratando de traducirlas a unos pocos niveles de "CustomException" que serán menos engorrosos de manejar en el código de llamada. Realmente no sé cómo para manejar completamente las cosas ahora. Así que estoy tratando de transformar una tarea fallida en otra tarea fallida donde el tipo de ex la recepción es diferente. – jtb

+0

Si lanza una excepción CustomException, el subsistema TPL simplemente ajustará eso en el mismo tipo de AggregateException que envolvería la excepción lanzada desde DoWorkAsync. –

Cuestiones relacionadas