ASP.NET 8 中的 ExceptionHandler
Intro
ASP.NET 8 中引入了 IExceptionHandler
,我们可以针对某一类的 exception 做单独的处理,
可以将不同类型的异常有不一样的逻辑做不同的处理,异常处理可以变得更加灵活
Sample
来看一个简单的示例:
我们可以实现 IExceptionHandler
来处理异常:
file sealed class ArgumentExceptionHandler : IExceptionHandler
{
public async ValueTask<bool> TryHandleAsync(HttpContext httpContext, Exception exception, CancellationToken cancellationToken)
{
httpContext.RequestServices.GetRequiredService<ILogger<ArgumentExceptionHandler>>()
.LogError(exception, "Exception handled");
if (exception is not ArgumentException) return false;
httpContext.Response.StatusCode = 400;
await httpContext.Response.WriteAsJsonAsync(new
{
exception.Message
}, cancellationToken);
return true;
}
}
只需要实现 TryHandleAsync
方法即可,返回值是 true
代表已经已经处理 ,无需后面的 exception handle 逻辑再处理,false
则需要后面的逻辑进行处理
完整的 web app 示例如下:
通过 AddExceptionHandler<THandler>()
来注册我们自定义的异常处理,可以注册多个,如果有多个要注意注册顺序,像中间件一样,先注册的 handler 会先执行
另外需要通过 UseExceptionHandler()
注册 ExceptionHandler 中间件
需要指定一下 exception handler 未处理的情况下的 exception 路由 ExceptionHandlingPath
或者 exception 处理逻辑 ExceptionHandler
var builder = WebApplication.CreateSlimBuilder(args);
builder.Services.AddExceptionHandler<ArgumentExceptionHandler>();
var app = builder.Build();
app.UseExceptionHandler(new ExceptionHandlerOptions()
{
// ExceptionHandlingPath = "/",
ExceptionHandler = context =>
{
context.Response.StatusCode = 500;
context.Response.WriteAsJsonAsync(new
{
title = "Internal Error",
traceId = context.TraceIdentifier
});
return Task.CompletedTask;
}
});
app.MapGet("/", () => "Hello .NET 8!");
app.MapGet("/exception", () =>
{
throw new InvalidOperationException("Oh no...");
});
app.MapGet("/argument-exception", () =>
{
throw new ArgumentException("Oh no...");
});
await app.RunAsync();
我们在示例中添加了三种效果,没有异常、InvalidOperationException
/ArgumentException
我们来看一下使用效果:
首先访问没有异常的 API:
再看下 ArgumentException
的情况:
可以看到此时返回的 response 是我们 exception handler 里的逻辑
再看下 InvalidOperationException
现在返回的是默认的 exception 的处理逻辑
这样我们可以把 exception 分层处理,不同的处理逻辑放在不同的 exception handler 中,不需要定义在一个地方,这样就灵活了许多,相当于中间件里套了一层中间件,套娃,嘿嘿
References
https://github.com/dotnet/aspnetcore/issues/46280
https://github.com/dotnet/aspnetcore/pull/47923
https://github.com/WeihanLi/SamplesInPractice/blob/master/net8sample/AspNetCore8Sample/ExceptionHandlerSample.cs