• 如何使用IExceptionHandler接口更灵活的处理异常
  • 发布于 2个月前
  • 159 热度
    0 评论
背景
ASP.NET 8 中引入了 IExceptionHandler,我们可以针对某一类的 exception 做单独的处理,可以将不同类型的异常有不一样的逻辑做不同的处理,异常处理可以变得更加灵活。

例子
来看一个简单的示例:
我们可以实现 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;
         // 堆代码 duidaima.com
        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 中,不需要定义在一个地方,这样就灵活了许多,相当于中间件里套了一层中间件,套娃,嘿嘿。
用户评论