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 ;)

17 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, 24 de noviembre de 2015

ASP.NET CoreHace unos días comentábamos la desaparición de la sección <customErrors> en ASP.NET Core, y la forma de implementar páginas de error personalizadas en esta nueva versión del framework.

Sin embargo, hay una cosa que dejé en el tintero y que el amigo Max resaltó en los comentarios del post:
"[…] Cuando se hace la petición interna a la acción HomeController.Error ¿como puedo saber exactamente el error que se ha producido si quiero mostrar un mensaje de error concreto para cada caso? Por ejemplo imagínate que quiero mostrar vistas diferentes para cada tipo de excepción o que aparezca sólo el texto de la excepción pero sin mostrar más datos"
En otras palabras, cuando el middleware ExceptionHandlerMiddleware pasa el control a la acción que procesará el error, ¿cómo podemos obtener información sobre la excepción que se produjo, por ejemplo para poder mostrar vistas o mensajes de error un poco más específicos?

Qué pregunta tan interesante, ¿verdad?

La respuesta corta

Cuando ExceptionHandlerMiddleware genera la petición interna para procesar la excepción, introduce en la colección de features asociadas a dicha petición un objeto de tipo IExceptionHandlerFeature, en cuyo interior podemos encontrar el objeto Exception que provocó originalmente el error:
public IActionResult Error()
{
    var exceptionHandlerFeature = 
            HttpContext.Features.Get<IExceptionHandlerFeature>();
    var originalException = exceptionHandlerFeature?.Error;
    return View(originalException);
}
Ya analizando originalException podríamos determinar si retornar una vista u otra, o, como en el ejemplo anterior, enviar la excepción a la vista para mostrar información algo más detallada:
@model Exception
<h1 class="text-danger">Error.</h1>
<h2 class="text-danger">@Model?.Message</h2>

La respuesta algo más larga

Cuando una petición entra en el pipeline de ASP.NET Core, el servidor le asocia una colección de "features" que describen las funcionalidades o características que dicha petición puede soportar, y almacenan información de interés para su proceso. Esta colección está disponible en la propiedad HttpContext.Features del controlador, y es de tipo FeatureCollection.

FeatureCollection se implementa en forma de diccionario, siendo la clave una interfaz conocida, definida previamente por el framework o por algún middleware, y el valor una instancia que implementa dicha interfaz y que contiene información relacionada con la feature. Por ejemplo, en una petición normal podemos encontrar features como IQueryFeature, cuya instancia nos permite acceder a detalles de la query string, o IRequestCookiesFeature, que proporciona acceso a las cookies de la petición.

La siguiente captura de pantalla muestra el contenido de la propiedad HttpContext.Features de un controlador durante el proceso normal de una petición sin errores (ojo, las features pueden variar dependiendo de los middlewares que tengáis instalados):

HttpContext.Features en una petición normal
ASP.NET Core define varios de estos interfaces, aunque los middlewares pueden añadir sus propias features, como en el caso de ExceptionHandlerMiddleware. Cuando este componente captura una excepción, antes de introducir la nueva petición en el pipeline, añade a las features un objeto de tipo IExceptionHandlerFeature, en cuya propiedad Error introduce la excepción capturada para que pueda ser consultada por los módulos que procesarán la petición.

La siguiente captura muestra el contenido de la propiedad HttpContext.Features de un controlador durante el proceso de la petición generada tras producirse un error, hacia la ruta que indicamos en el momento de configurar el middleware ExceptionHandlerMiddleware:

HttpContext.Features en la petición generada internamente tras producirse un error

Por esta razón, cuando la ejecución llega a la acción que hemos implementado para procesar el error (HomeController.Error() en nuestro ejemplo), es posible obtener el objeto IExceptionHandlerFeature de esta colección y utilizarlo a nuestro antojo, como hacíamos en el ejemplo anterior:
public IActionResult Error()
{
    var exceptionHandlerFeature = 
            HttpContext.Features.Get<IExceptionHandlerFeature>();
    var originalException = exceptionHandlerFeature?.Error;
    return View(originalException);
}
¡Y eso es todo! Espero que al amigo Max le haya quedado resuelta su duda, y que a alguno más le haya sido de utilidad, sobre todo para ver un poco más de las interioridades de ASP.NET Core.

Publicado en Variable not found.

3 Comentarios:

Maxx dijo...

Quedó clarísimo, muchas gracias Jose.

Juan dijo...

Buen tema Jose.
Siguiendo con la captura de excepciones, esta vez en mvc6 como se podría captuar los códigos de estado como por ejemplo 404

José María Aguilar dijo...

Hola!

@maxx, gracias, espero que se haya solucionado tu inquietud ;-)

@juan, se hace con otro middleware distinto. Estoy preparando un post al respecto.

Saludos!