Saltar al contenido

Artículos, tutoriales, trucos, curiosidades, reflexiones y links sobre programación web ASP.NET Core, MVC, Blazor, SignalR, Entity Framework, C#, Azure, Javascript... y lo que venga ;)

18 años online

el blog de José M. Aguilar

Inicio El autor Contactar

Artículos, tutoriales, trucos, curiosidades, reflexiones y links sobre programación web
ASP.NET Core, MVC, Blazor, SignalR, Entity Framework, C#, Azure, Javascript...

¡Microsoft MVP!
martes, 12 de junio de 2018
ASP.NET Core Aparte de las novedades que comentamos hace una semana, ASP.NET Core 2.1 incluye algunas sorpresas adicionales que, sin ser revolucionarias, nos harán más sencillo el día a día. En esta ocasión vamos a comentar una característica introducida en .NET Core 2.1 que aporta mejoras de legibilidad en las trazas de excepciones producidas en llamadas asíncronas, algo que obtendremos for free, por el mero hecho de utilizar la última revisión del framework.

Veamos muy rápidamente en qué consiste.

Un ejemplo de traza de excepción ilegible

Imaginemos el código de una aplicación de consola tan simple como la siguiente:
class Program
{
    static async Task Main(string[] args)
    {
        try
        {
            await DoSomethingAsync();
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex);
        }
    }

    static async Task DoSomethingAsync()
    {
        await DoAnotherThingAsync();
    }

    private static Task DoAnotherThingAsync()
    {
        throw new Exception();
    }
}
Si compilamos esta aplicación en .NET Core 2.0 o anteriores, o incluso en .NET Framework, y la ejecutamos, la salida por consola será más o menos la siguiente:
System.Exception: Exception of type 'System.Exception' was thrown.
   at ConsoleApp_20.Program.DoAnotherThingAsync() in C:\ConsoleApp-20\Program.cs:line 29
   at ConsoleApp_20.Program.<DoSomethingAsync>d__1.MoveNext() in C:\ConsoleApp-20\Program.cs:line 24
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at ConsoleApp_20.Program.<Main>d__0.MoveNext() in C:\ConsoleApp-20\Program.cs:line 12
El problema con esta traza es el ruido y la cantidad de información que muestra, que hace que no sea fácil de leer e interpretar. Aunque la línea donde se ha producido el error se puede ver con relativa claridad (línea 29, en DoAnotherThingAsync()), a partir de ahí no es sencillo ver por dónde ha ido pasando el flujo de ejecución.

Si esto es así en una aplicación de consola de pocas líneas, seguro que ya habréis sufrido lo complicado que es leerla cuando se trata de una aplicación de mayor calado, además montada sobre un framework complejo y puramente asíncrono como ASP.NET Core.

Trazas de excepciones legibles en .NET Core 2.1

Probemos ahora exactamente el mismo código, pero esta vez compilándolo y ejecutándolo sobre .NET Core 2.1. Sin hacer nada más, en esta ocasión la traza que obtenemos en pantalla es la siguiente:
System.Exception: Exception of type 'System.Exception' was thrown.
   at ConsoleApp_21.Program.DoAnotherThingAsync() in C:\ConsoleApp-21\Program.cs:line 29
   at ConsoleApp_21.Program.DoSomethingAsync() in C:\ConsoleApp-21\Program.cs:line 24
   at ConsoleApp_21.Program.Main(String[] args) in C:\ConsoleApp-21\Program.cs:line 12
Genial, ¿eh? Ahora sí que queda perfectamente claro dónde explotó la aplicación, y la traza completa de ejecución :)
Si estáis interesados, podéis leer más sobre esta feature en el post Stacktrace improvements in .NET Core 2.1 de uno de sus desarrolladores.

Hey, ¿y no podría conseguir lo mismo en .NET Framework o versiones anteriores de .NET Core?

Pues sí :) Afortunadamente, Ben Adams, Microsoft MVP y uno de los principales contributors de ASP.NET Core, además de trabajar en varios pull requests que implementaban esta característica en .NET Core 2.1, creó hace unos meses el proyecto Ben.Demystifier, que permite “desmitificar” los stack traces ilegibles dejándolos limpios de información no esencial, como en el ejemplo que vimos antes.

Para utilizarlo, basta con instalar el paquete desde Nuget, e invocar el método Demystify() para generar una excepción con las trazas retocadas:
try
{
    await DoSomethingAsync();
}
catch (Exception ex)
{
    Console.WriteLine(ex.Demystify());
}
Publicado en Variable not found.

Aún no hay comentarios, ¡sé el primero!