ASP.NET Core 全局异常处理

IAsyncExceptionFilter

在 ASP.NET Core 中,可以使用异常过滤器(Exception Filter)来捕获和处理应用程序中的异常。IExceptionFilter 接口和 IAsyncExceptionFilter 接口都可以用来实现自定义的异常过滤器。不过我更建议您考虑它的异步版本:IAsyncExceptionFilter。

public class CustomExceptionFilter : IAsyncExceptionFilter
{
    private readonly ILogger<CustomExceptionFilter> _logger;

    public CustomExceptionFilter(ILogger<CustomExceptionFilter> logger)
    {
        _logger = logger;
    }

    public async Task OnExceptionAsync(ExceptionContext context)
    {
        _logger.LogError(context.Exception, "An error occurred.");

        if (!context.ExceptionHandled)
        {
            context.Result = new ViewResult { ViewName = "Error" };
            context.ExceptionHandled = true;
        }

        await Task.CompletedTask;
    }
}

在这个示例中,我们创建了一个名为 CustomExceptionFilter 的自定义异常过滤器,它实现了 IAsyncExceptionFilter 接口。在 OnExceptionAsync 方法中,我们记录了异常并返回一个 ViewResult 对象来显示用户友好的错误信息。

要使用这个过滤器,只需要在 Startup.ConfigureServices 方法中注册它:

services.AddMvc(options =>
{
    options.Filters.Add<CustomExceptionFilter>();
});

中间件处理异常

新建一个中间件在管道中实现全局异常捕获。

public class MyExceptionMiddleware
{
	private readonly RequestDelegate _next;
	private readonly ILogger<MyExceptionMiddleware> _logger;

	public MyExceptionMiddleware(RequestDelegate next, ILogger<MyExceptionMiddleware> logger)
	{
		_next = next;
		_logger = logger;
	}

	public async Task Invoke(HttpContext context)
	{
		try
		{
			await _next(context);
		}
		catch (Exception ex)
		{
			_logger.LogError($"An exception occurred: {ex}");

			context.Response.ContentType = "application/json";
			context.Response.StatusCode = (int)HttpStatusCode.InternalServerError;

			var jsonResponse = System.Text.Json.JsonSerializer.Serialize(new { error = ex.Message });
			await context.Response.WriteAsync(jsonResponse);
		}
	}
}

然后在 Startup.cs 中,注册管道:

app.UseMiddleware<MyExceptionMiddleware>();

默认的AspNet Core异常处理

if (env.IsDevelopment())
{
	// dev环境,一旦报错就会跳转到错误堆栈页面
	app.UseDeveloperExceptionPage();
	app.UseSwagger();
	app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "DaXiong.Demo.WebApi v1"));
}
else
{
	// 非dev环境输出格式,个人根据实际情况扩展
	app.UseExceptionHandler(errorApp =>
	{
		errorApp.Run(async context =>
		{
			Console.WriteLine();
			// 处理异常并生成响应
			var exception = context.Features.Get<IExceptionHandlerPathFeature>().Error;
			var statusCode = (int)HttpStatusCode.InternalServerError;
			var message = "An error occurred while processing your request.";

			// 根据异常类型决定如何响应请求...

			// 生成响应
			context.Response.StatusCode = statusCode;
			context.Response.ContentType = "application/json";
			await context.Response.WriteAsync(JsonConvert.SerializeObject(new
			{
				statusCode,
				message
			}));
		});
	});
}

注意中间件的运行顺序

image
后添加的中间件返回数据会覆盖,前面的
image

一般情况使用默认的错误处理中间件也够了

image

有了异常中间件还需要异常过滤器(IExceptionFilter )吗

IExceptionFilter 作为MVC中间件之间的内容,它需要MVC在发现错误之后将错误信息提交给它处理,因此它的错误处理范围仅限于MVC中间件。所以,假如我们需要捕获MVC中间件之前的一些错误,其实是捕获不到的。 而对于ExceptionHandlerMiddleware中间件来说就很简单了,它作为第一个中间件,凡是在它之后的所有错误它都能够捕获得到。
但是,如果你想要在一个控制器或动作方法上执行特定的异常处理逻辑,仍然可以使用 IAsyncExceptionFilter。通过使用该接口,你可以在控制器或动作方法级别组织、记录和响应异常。在这种情况下,控制器或动作方法将优先于全局的 UseExceptionHandler 中间件。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章