ASP.NET 8 中的 ExceptionHandler

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:

7b1c5069082cc3f531abfdf1dbe2ab76.png

hello

再看下 ArgumentException 的情况:

7fb9045a8b7a9fe264c29ba66d279578.png

ArgumentException

可以看到此时返回的 response 是我们 exception handler 里的逻辑

再看下 InvalidOperationException

6f861cff176c9552862ad2a27cc98cdd.png

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值