Middleware y página de manejo de excepciones
Soy nuevo en el concepto de middleware y actualmente estoy luchando con la forma correcta de manejar las excepciones en mi proyecto MVC Core.
Lo que quiero que suceda es que se capture la excepción, se registre y luego envíe al usuario a una página de error amigable con un mensaje. Al principio, estaba tratando de administrar todo esto dentro del middleware, pero me di cuenta de que probablemente no lo estaba haciendo correctamente.
Entonces, si quiero que este flujo suceda, ¿debo usar mi middleware de registro de excepciones Y la aplicación. UseExceptionHandler ("/ Error") para que el middleware vuelva a lanzar la excepción a la página? Y si es así, ¿cómo obtengo los detalles de la excepción en la página Error? ¿Y es correcto que el mecanismo de manejo de excepciones que quiero interceptar primero sea el último en Configurar?
Todos los ejemplos que he encontrado tratan estrictamente de errores del Código de estado HTTP como 404; Estoy buscando manejar excepciones reales (y sus subclases). De esa forma, en mis páginas de Vista puedo lanzar mis propias Excepciones cuando corresponda (por ejemplo, si se proporciona una Vista nula para un campo obligatorio).
Fragmento de Startup.cs:
public void Configure(IApplicationBuilder app, IHostingEnvironment env,
ILoggerFactory loggerFactory, LoanDbContext context) {
loggerFactory.AddConsole(Configuration.GetSection("Logging"));
, loggerFactory.AddDebug();
app.UseStatusCodePages();
if (env.IsDevelopment() || env.IsEnvironment("qa")) {
app.UseDeveloperExceptionPage();
app.UseBrowserLink();
} else {
app.UseExceptionHandler("/Error");
}
app.UseMiddleware<MyExceptionHandler>(loggerFactory);
// ... rest of Configure is irrelevant to this issue
MyExceptionHandler.cs
using Microsoft.AspNetCore.Http;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using System;
using System.Data.SqlClient;
using System.Threading.Tasks;
namespace MyCompany.MyProject.Helpers
{
/// <summary>
/// A custom Exception Handler Middleware which can be re-used in other projects.
/// </summary>
public sealed class MyExceptionHandler
{
private readonly RequestDelegate _next;
private readonly ILogger _logger;
public MyExceptionHandler(RequestDelegate next, ILoggerFactory loggerFactory) {
_next = next;
_logger = loggerFactory.CreateLogger<MyExceptionHandler>();
}
public async Task Invoke(HttpContext context) {
try {
await _next(context);
} catch (Exception ex) {
HandleException(ex);
}
}
// I realize this function looks pointless, but it will have more meat to it eventually.
public void HandleException(Exception ex) {
if (ex is ArgumentException argEx) {
_logger.LogError(0, argEx, argEx.Message);
} else if (ex is InvalidOperationException ioEx) {
_logger.LogError(0, ioEx, "An Invalid Operation Exception occurred. This is usually caused by a database call that expects "
+ "one result, but receives none or more than one.");
} else if (ex is SqlException sqlEx) {
_logger.LogError(0, sqlEx, $"A SQL database exception occurred. Error Number {sqlEx.Number}");
} else if (ex is NullReferenceException nullEx) {
_logger.LogError(0, nullEx, $"A Null Reference Exception occurred. Source: {nullEx.Source}.");
} else if (ex is DbUpdateConcurrencyException dbEx) {
_logger.LogError(0, dbEx, "A database error occurred while trying to update your item. This is usually due to someone else modifying the item since you loaded it.");
} else {
_logger.LogError(0, ex, "An unhandled exception has occurred.")
}
}
}
}