在 Web 应用程序中处理异常可能很棘手,通常会导致未处理的异常和糟糕的用户体验。许多开发人员选择分散块等简单方法,这可能会导致不一致的错误处理和维护挑战。进入 ASP.NET Core 中不可或缺的功能 - 一个用于集中和强大错误处理的强大工具。在这篇博文中,我们将深入探讨在 ASP.NET Core 项目中使用此中间件的实现、集成和好处。您可以在以下 GitHub 存储库中找到完整的代码和项目结构:aspnet-core-global-exception-handler。try-catchGlobalExceptionHandlerMiddleware
以下是 our 及其集成到 ASP.NET Core 应用程序中的完整实现。我们将 Serilog 与内置功能一起使用,以利用 Serilog 的高级日志记录功能,例如记录到多个接收器(例如控制台、文件)和结构化日志记录。GlobalExceptionHandlerMiddlewareILogger
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using Serilog;
using System;
using System.Threading.Tasks;
public class GlobalExceptionHandlerMiddleware
{
private readonly RequestDelegate _next;
private readonly ILogger<GlobalExceptionHandlerMiddleware> _logger;
public GlobalExceptionHandlerMiddleware(RequestDelegate next, ILogger<GlobalExceptionHandlerMiddleware> logger)
{
_next = next ?? throw new ArgumentNullException(nameof(next));
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
}
public async Task InvokeAsync(HttpContext context)
{
try
{
await _next(context);
}
catch (Exception ex)
{
_logger.LogError(ex, "An unhandled exception occurred while processing the request.");
Log.Error(ex, "An unhandled exception occurred while processing the request.");
context.Response.StatusCode = StatusCodes.Status500InternalServerError;
context.Response.ContentType = "application/json";
var response = new
{
Message = "An unexpected error occurred. Please try again later."
};
await context.Response.WriteAsJsonAsync(response);
}
}
}
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Serilog;
using Serilog.Events;
var builder = WebApplication.CreateBuilder(args);
// Configure Serilog
Log.Logger = new LoggerConfiguration()
.MinimumLevel.Information()
.MinimumLevel.Override("Microsoft", LogEventLevel.Warning)
.Enrich.FromLogContext()
.WriteTo.Console()
.WriteTo.File("logs/log-.txt", rollingInterval: RollingInterval.Day)
.CreateLogger();
builder.Host.UseSerilog();
builder.Services.AddProblemDetails();
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/error");
}
app.UseMiddleware<GlobalExceptionHandlerMiddleware>();
app.MapGet("/", () => "Hello World!");
app.MapGet("/exception", () =>
{
throw new InvalidOperationException("Sample Exception");
});
app.Run();
构造函数使用 next 和 .使用 of 可确保提供两个依赖项,从而防止潜在的 null 引用问题。RequestDelegateILoggerArgumentNullException
public GlobalExceptionHandlerMiddleware(RequestDelegate next, ILogger<GlobalExceptionHandlerMiddleware> logger)
{
_next = next ?? throw new ArgumentNullException(nameof(next));
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
}
这就是魔法发生的地方。该方法拦截请求并将其包装在一个块中。如果发生异常,它会同时使用 和 记录错误,然后使用 500 状态代码和 JSON 错误消息进行响应。InvokeAsynctry-catchILoggerSerilog
public async Task InvokeAsync(HttpContext context)
{
try
{
await _next(context);
}
catch (Exception ex)
{
_logger.LogError(ex, "An unhandled exception occurred while processing the request.");
Log.Error(ex, "An unhandled exception occurred while processing the request.");
context.Response.StatusCode = StatusCodes.Status500InternalServerError;
context.Response.ContentType = "application/json";
var response = new
{
Message = "An unexpected error occurred. Please try again later."
};
await context.Response.WriteAsJsonAsync(response);
}
}
使用此中间件有几个主要好处:
一些开发人员认为,在整个代码中散布块就足够了。但是,这种方法通常会导致重复的代码和不一致的错误处理。例如,如果没有集中式错误处理,应用程序的不同部分可能会针对同一类型的异常返回不同的错误响应,从而导致混淆和维护麻烦。这提供了一种更简洁、更一致的方法。try-catchGlobalExceptionHandlerMiddleware
集成到 ASP.NET Core 应用程序中似乎是一个重大变化,但其好处远大于缺点。通过集中错误处理、增强日志记录和提供用户友好的响应,此中间件可确保您的应用程序健壮且可维护。立即开始在您的项目中实施它,以体验错误管理和应用程序稳定性的改进