【踩坑】.NET 8.0 自定义IExceptionHandler不生效

中间件实现异常处理

在ASP.NET Core里,我们可以使用中间件(Middleware)实现全局的异常处理。 如内置的异常处理中间件 UseExceptionHandler

app.UseExceptionHandler(appError =>
{
appError.Run(async context =>
{
context.Response.StatusCode = (int)HttpStatusCode.InternalServerError;
context.Response.ContentType = "application/json";
var contextFeature = context.Features.Get<IExceptionHandlerFeature>();
if (contextFeature != null)
{
logger.LogError($"Something went wrong: {contextFeature.Error}");
await context.Response.WriteAsync(new ErrorDetails()
{
StatusCode = context.Response.StatusCode,
Message = "Internal Server Error."
}.ToString());
}
});
});

或者如下干脆完全自定义一个中间件

public class ExceptionMiddleware
{
private readonly RequestDelegate _next;
private readonly ILoggerManager _logger;
public ExceptionMiddleware(RequestDelegate next, ILoggerManager logger)
{
_logger = logger;
_next = next;
}
public async Task InvokeAsync(HttpContext httpContext)
{
try
{
await _next(httpContext);
}
catch (Exception ex)
{
_logger.LogError($"Something went wrong: {ex}");
await HandleExceptionAsync(httpContext, ex);
}
}
private async Task HandleExceptionAsync(HttpContext context, Exception exception)
{
context.Response.ContentType = "application/json";
context.Response.StatusCode = (int)HttpStatusCode.InternalServerError;
await context.Response.WriteAsync(new ErrorDetails()
{
StatusCode = context.Response.StatusCode,
Message = "Internal Server Error from the custom middleware."
}.ToString());
}
}

当然还可以使用过滤器(Filter)来实现,即IExceptionFilter, 这些都能很方便实现自定义的全局异常处理。

IExceptionHandler 实现异常处理

在.NET 8.0里,微软新引入的IExceptionHandler也可以实现同样的功能,看官方的异常处理文档IExceptionHandler似乎已经是最推荐的异常处理方法。
在微软新开的项目里,IExceptionHandler正被广泛使用,比如Semantic Kernel
image
下面是官方文档给的一个简单例子

using Microsoft.AspNetCore.Diagnostics;
namespace ErrorHandlingSample
{
public class CustomExceptionHandler : IExceptionHandler
{
private readonly ILogger<CustomExceptionHandler> logger;
public CustomExceptionHandler(ILogger<CustomExceptionHandler> logger)
{
this.logger = logger;
}
public ValueTask<bool> TryHandleAsync(
HttpContext httpContext,
Exception exception,
CancellationToken cancellationToken)
{
var exceptionMessage = exception.Message;
logger.LogError(
"Error Message: {exceptionMessage}, Time of occurrence {time}",
exceptionMessage, DateTime.UtcNow);
// Return false to continue with the default behavior
// - or - return true to signal that this exception is handled
return ValueTask.FromResult(false);
}
}
}

注册也很简单

builder.Services.AddExceptionHandler<CustomExceptionHandler>();

然而,坑来了,在按照文档实现完之后,你所期待的自定义异常处理并不会生效!这不是你的问题,你必须还要UseExceptionHandler并且添加一个空的lambda给它,必须是空的lambda,直接app.UseExceptionHandler()还没用,只有这样AddExceptionHandler才会生效 😃

app.UseExceptionHandler(o => { });

为什么会这样?请看这个issue https://github.com/dotnet/aspnetcore/issues/51888, 去年下半年就有人发现了,微软尝试去修复了https://github.com/dotnet/aspnetcore/pull/51898, 但是改动有breaking change被自己人给拒了,加上有上面提到的workaround,就一直搁置了。
image
虽然又不是不能用,但是看着难受,开头就介绍了,UseExceptionHandler是启用内置的异常处理中间件的方法,而AddExceptionHandler是用来注册.NET 8.0新引入的IExceptionHandler,这个workaround有点一言难尽...

最后

从这个神奇的workaround可以看出,IExceptionHandler这套其实本质也是用的中间件,看起来它的实现和现有的UseExceptionHandler有些冲突,导致注册的时候不伦不类,欢迎踊跃提交PR去fix,先到先得☺

posted @   马行空的博客  阅读(1492)  评论(9编辑  收藏  举报
相关博文:
阅读排行:
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· C# 集成 DeepSeek 模型实现 AI 私有化(本地部署与 API 调用教程)
· DeepSeek R1 简明指南:架构、训练、本地部署及硬件要求
· 没有源码,如何修改代码逻辑?
· NetPad:一个.NET开源、跨平台的C#编辑器
点击右上角即可分享
微信分享提示