我想在中间件组件中连接异常处理,如下所示:
public override async Task Invoke(IOwinContext context)
{
try
{
await Next.Invoke(context);
}
catch (Exception ex)
{
// Log error and return 500 response
}
}
但是,我想捕获的一些异常正在被捕获并转换为HttpErrorResponse
在我能够访问它们之前,先通过 Web API 管道进行处理。在此过程中,我丢失了很多有关错误的详细信息,因此在调试等时无法获得有用的堆栈跟踪(抛出异常时调试器甚至不会停止 - 我必须手动单步执行代码并查看失败的地方......)。
我尝试使用以下实现添加自定义异常处理程序:
public Task HandleAsync(ExceptionHandlerContext context, CancellationToken cancellationToken)
{
var owinContext = context.Request.GetOwinContext();
owinContext.Set(Constants.ContextKeys.Exception, context.Exception);
return Task.FromResult(0);
}
注册通过config.Services.Replace(typeof(IExceptionHandler), new MyExceptionHandler());
在我的启动配置中,但是执行后查看它Next.Invoke(context)
through
context.Get<Exception>(Constants.ContextKeys.Exception);
still没有提供我想要的所有详细信息,并且无法使用调试器在故障点停止。
有什么办法我可以完全地关all内置错误处理,以便我自己的中间件可以处理它?
澄清,因为很多人似乎误解了我的目的:
- Web API 中的内置错误处理捕获some(但不是全部)异常并将其重写为 500 个响应。
- 我想抓住all异常,做一些日志记录,以及then发出 500 个响应与我选择的信息(对于其中大多数,请参阅下一个项目符号)。
- 还有一些异常表示业务逻辑错误,对此我想返回 40x 错误。
- 我希望它位于(应用程序)管道的顶部,即包装一切else 在请求生命周期中
- 我想使用 OWIN 来处理这个问题,使其可移植到未来可能的自托管场景(即,这个应用程序将始终托管在 IIS 上并不是一成不变的 - HTTP 模块、Global.asax.cs 等不相关)这里)。
Update: 我在博客上谈到了这个 http://www.jayway.com/2016/01/08/improving-error-handling-asp-net-web-api-2-1-owin/。在研究博客文章时,我发现了一些改进的潜力;我已经更新了这个答案的相关部分。有关为什么我认为这比此处的所有其他建议或默认行为更好的更多详细信息,请阅读整篇文章:)
我现在采用了以下方法,即使不是 100% 符合我正在寻找的内容,它似乎也可以正常工作:
-
创建一个类PassthroughExceptionHandler
:
public class PassthroughExceptionHandler : IExceptionHandler
{
public Task HandleAsync(ExceptionHandlerContext context, CancellationToken cancellationToken)
{
// don't just throw the exception; that will ruin the stack trace
var info = ExceptionDispatchInfo.Capture(context.Exception);
info.Throw();
return Task.CompletedTask;
}
}
-
让那个班级replace the IExceptionHandler
Web API服务:
config.Services.Replace(typeof(IExceptionHandler), new PassthroughExceptionHandler());
-
创建一个中间件类来执行我想要的操作:
public class ExceptionHandlerMiddleware
{
public override async Task Invoke(IOwinContext context)
{
try
{
await Next?.Invoke(context);
}
catch (Exception ex)
{
// handle and/or log
}
}
}
-
首先在堆栈中注册该中间件:
app.Use<ExceptionHandlerMiddleware>()
.UseStageMarker(PipelineStage.Authenticate)
// other middlewares omitted for brevity
.UseStageMarker(PipelineStage.PreHandlerExecute)
.UseWebApi(config);
我仍然会将赏金奖励给提出的任何人(赏金已过期...)我仍在寻找更好的解决方案,例如,当未处理的抛出异常。 (当我在处理程序中重新抛出异常时,这种方法会使 VS 中断,但原始调用堆栈丢失;我必须在故障行设置断点并再次调试,以便能够拦截抛出异常时的状态。)
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)