【X23】 02 全局错误捕捉(Middleware)
前言
知识点:
ASP.NET Core 中基于工厂的中间件激活
目的: 利用 Middleware 自定义中间件捕捉程序全局错误
1 简单介绍
中间件是一种装配到应用管道以处理请求和响应的软件。 每个组件:
- 选择是否将请求传递到管道中的下一个组件。
- 可在管道中的下一个组件前后执行工作。
首先看看最重要的两张图,详细描述了中间件执行过程以及顺序。通俗来说,就是委托包委托,请求进来先按规定顺序执行多个中间件的方法,再依次倒着返回结果。
所以,我们可以通过自定义错误处理中间件,捕捉程序运行的错误!
2 编写错误中间件
中间件的编写方式有三种
在此,我采用了第二种基于工厂的中间件激活,因为第一种约定方式对编写理解不友好,第三种过于复杂。
简单来说,我们可以通过一个方法 RequestDelegate next 进行 try catch 住,然后扩展对错误的处理。
/// <summary>
/// 错误处理中间件
/// </summary>
public class ErrorHandlingMiddleware: IMiddleware
{
private readonly ILoggerFactory _loggerFactory;
public ErrorHandlingMiddleware(ILoggerFactory loggerFactory)
{
_loggerFactory = loggerFactory;
}
public async Task InvokeAsync(HttpContext context, RequestDelegate next)
{
try
{
await next(context);
}
catch (Exception ex)
{
await HandleExceptionAsync(context, ex, _loggerFactory);
}
}
private static Task HandleExceptionAsync(HttpContext context, Exception exception, ILoggerFactory loggerFactory)
{
var logger = loggerFactory.CreateLogger("HandleException");
logger.LogError(exception, exception.Message);
var code = HttpStatusCode.InternalServerError;
context.Response.StatusCode = (int)code;
return context.Response.WriteAsJsonAsync(new ResponseDto { Code = (int)code, ErrorMsg = exception.Message, StackTrace = exception.StackTrace });
}
}
3 注册使用该中间件
一般来说,中间件的注册使用如下,但是为什么别人都是 service.AddXXX()
和 app.UseXXX()
如此优雅呢?
services.AddTransient<ErrorHandlingMiddleware>();//注册
app.UseMiddleware<ErrorHandlingMiddleware>();//使用
改善后:
public static class AllMiddlewareExtensions
{
/// <summary>
/// 注册 异常处理中间件
/// </summary>
/// <param name="services"></param>
public static void AddErrorHandlingMiddleware(this IServiceCollection services)
{
services.AddTransient<ErrorHandlingMiddleware>();
}
/// <summary>
/// 使用 异常处理中间件
/// </summary>
/// <param name="builder"></param>
/// <returns></returns>
public static IApplicationBuilder UseErrorHandlingMiddleware(this IApplicationBuilder builder)
{
return builder.UseMiddleware<ErrorHandlingMiddleware>();
}
}
Now,你可以优雅的使用了!
services.AddErrorHandlingMiddleware();//注册
app.UseErrorHandlingMiddleware();//使用