Algo muy importante que deberíamos tener en cuenta en el desarrollo de nuestras aplicaciones es un correcto manejo de excepción. En varios de nuestros clientes notamos que no hacen uso de una forma correcta o directamente no es tenido en cuenta. Al ocurrir algún error dentro de una aplicación Asp.Net nos permite manejalo de varias formas de una manera simple y rápida.
Objetivo
El objetivo de esta publicación es tocar las posibles utilizaciones y alcance del manejo de errores propuesto por Asp.Net Core.
Audiencia
Este documento está dirigido a desarrolloradores que deseen conocer Asp.Net core o personas que desarrollan tareas de consultoría de desarrollo o que simplemente están interesados en leer e investigar sobre la tecnología alcanzada por esta publicación.
Desarrollo
Comencemos enumerando las diferentes tipos de excepciones, configuraciones y opciones que podemos utilizar:
- Página de excepción para desarrollo.
- Configurar excepciones personalizadas.
- Configurando código de estado para las páginas.
- Manejando código de excepciones.
- Manejando código de excepciones en el servidor.
- Manejo de excepción en el inicio de aplicación.
- Manejo de excepciones en Asp.Net MVC.
Página de excepciones para desarrollo
La configuración por defaults de la página de errores tal vez es poca. Por este motivos, para obtener una mayor cantidad de información podemos instalar el paquete Nuget Microsoft.AspNetCore.Diagnostics. Luego de instalar el paquete debemos hacer la inyección correspondiente en el método Configure que se encuentra en el archivo startup.cs de la siguiente manera.
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory){ loggerFactory.AddConsole(); env.EnvironmentName = EnvironmentName.Production; if (env.IsDevelopment()){ app.UseDeveloperExceptionPage(); }else{ app.UseExceptionHandler("/error"); } }
- Recordemos que esto solo debe estar activo cuando la aplicación esté corriendo en un entorno de desarrollo.
Para ver la página de excepción debemos correr la aplicación seteado en entorno de desarrollo y debemos agregar ?throw=true en la url. Podemos que la página incluye algunos tabs muy interesantes que contienen la información de la excepción y el request que hicimos. La primera solapa es Stack:
La solapa Query muestra los parámetros pasados por Query String si los hay.
La siguiente solapa es Cookies. Si hay cookies en el request van a aparecer en esta solapa.
Por último, tenemos la solapa de Headers donde podemos ver todos los encabezados enviados en el Request.
Configurar excepciones personalizadas
Cuando no estamos trabajando en un entorno de desarrollo es conveniente configurar un manejador especial.
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory){ loggerFactory.AddConsole(); env.EnvironmentName = EnvironmentName.Production; if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } else { app.UseExceptionHandler("/error"); } }
En Asp.Net MVC no tenemos un decorador de errores para que ejecute una acción dependiendo de un método http. Para solucionar esto debemos tener un Action que sea ruteado a el como podemos ver en el siguiente código:
[Route("/Error")] public IActionResult Index() { // Handle error here }
Configurando código de estado para las páginas
Nuestra aplicación, por default, no muestra ningun codigo de estado para un código de estado de HTTP como podría ser el error 500(Internal Server Error) o el 404 (Not Found). Podemos configurar StatusCodePagesMiddleware en el método Configure en el archivo startup.cs
app.UseStatusCodePages();
Este middleware agregara un texto simple como podemos ver en la captura
app.UseStatusCodePages() puede soportar varios tipos de métodos. Alguno pueden ser expresiones del tipo lambda o tipos de contenido o formato de textos como podemos ver en los siguientes codigos:
app.UseStatusCodePages(async context => { context.HttpContext.Response.ContentType = "text/plain"; await context.HttpContext.Response.WriteAsync( "Status code page, status code: " + context.HttpContext.Response.StatusCode); }); app.UseStatusCodePages("text/plain", "Status code page, status code: {0}");
En otros casos podemos redireccionar directamente a algún método que deseamos. por ejemplo, podemos devolver el error 302 al cliente pero también podemos redireccionarlo a un dirección url.
app.UseStatusCodePagesWithRedirects("/error/{0}"); app.UseStatusCodePagesWithReExecute("/error/{0}");
Si necesitamos desactivarlo por algún motivo simplemente debemos usar el siguiente código:
var statusCodePagesFeature = context.Features.Get<IStatusCodePagesFeature>(); if (statusCodePagesFeature != null) { statusCodePagesFeature.Enabled = false; }
Manejando código de excepciones.
A menudo es una buena idea para las páginas de error en producción para constan de contenido puramente estática. Hay que tener en cuenta que una vez enviado los encabezados en el response es posible cambiar el estado de la respuesta como tampoco ejecutar otra página de excepción. El response debe ser completado o la conexión abortada.
Manejando código de excepciones en el servidor.
Recordemos que además de manejar las excepciones, en el servidor donde se encuentra alojada la aplicación, realizara alguna gestión sobre esa excepción. Algunos puntos para tener en cuenta son: Si el servidor detecta un error 500 antes de que se envíe al cliente se enviará un error sin contenido. Si se detecta una excepción después de que los cabeceros se han enviado, se cerrara la conexión, por último, las solicitudes que no son manejadas por la aplicación serán manejadas por los servidores. Cualquier configuración que hagamos en el manejo de excepciones no modificarán el comportamiento del servidor.
Manejo de excepción en el inicio de aplicación
Todas las configuraciones y situaciones anteriores ocurren durante el ciclo de vida de la aplicación. En caso de ocurrir un error durante el inicio de la aplicación se disparará una excepción a nivel servidor.
Manejo de excepciones en Asp.Net MVC.
Asp.Ne MVC tiene algunas opciones mas para poder capturar errores como configurar excepción en los llamados filtros (filter) y validaciones en los modelos.
Exception Filters
Un filtro puede ser configurado de forma global o sobre un controller o action basado en MVC. Los filtros pueden capturar una excepción que no haya sido configurada con anterior mientras ocurre la ejecución de un controlado o acción. Inclusive en un filtro.
Handling Model State Errors
El Model Validation se ejecuta cuando el controlador y el action son invocados. Es posible invocarlo con el método ModelState.IsValid para verificar si el modelo está correct.
Conclusión
un buen manejo de errores puede evitarnos un dolor de cabeza muy grande cuando nuestra aplicación está fallando y no sabemos cuál es la causa.