我想在中间件组件中连接异常处理,如下所示:
public override async Task Invoke(IOwinContext context) { try { await Next.Invoke(context); } catch (Exception ex) { // Log error and return 500 response } }
但是,HttpErrorResponse
在我可以访问之前,我想要捕获的一些异常被Web API管道捕获并转换为s.在这个过程中,我丢失了很多关于错误的细节,所以在调试时我无法得到有用的堆栈跟踪(调试器在抛出异常时甚至不会停止 - 我必须手动单步执行代码并查看它失败的地方......).
我尝试使用以下实现添加自定义异常处理程序:
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)
通过
context.Get(Constants.ContextKeys.Exception);
仍然没有给我所有我想要的细节,以及没有在调试器的故障点停止.
有没有办法可以完全关闭所有内置错误处理,以便我自己的中间件可以处理它?
澄清,因为很多人似乎误解了我的追求:
Web API中的内置错误处理捕获了一些(但不是全部)异常,并将它们重写为500个响应.
我想捕获所有异常,进行一些日志记录,然后使用我选择的信息发出500个响应(对于大多数异常,请参阅下一个项目符号).
还有一些异常表示业务逻辑故障,我想为此返回40x错误.
我希望它位于(app)管道的顶部,即包装请求生命周期中的所有其他内容
我想使用OWIN来处理这个问题,以便将其移植到可能的未来自托管方案中(也就是说,这个应用程序将永远托管在IIS上 - 这些应用程序将永远存在于IIS - HTTP模块中,Global.asax.cs等不相关这里).
Tomas Aschan.. 18
更新:我在博客上写了这个.在研究博客文章时,我发现了一些改进的潜力; 我已经更新了这个答案的相关部分.有关为什么我认为这比其他所有建议或默认行为更好的详细信息,请阅读整篇文章:)
我现在已经采用以下方法,即使不是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; } }
让该类替换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() .UseStageMarker(PipelineStage.Authenticate) // other middlewares omitted for brevity .UseStageMarker(PipelineStage.PreHandlerExecute) .UseWebApi(config);
我还是会给那些想出来的人奖励(赏金过期......)我仍然在寻找一个更好的解决方案,例如,当一个未处理的异常被抛出时会中断.(当我在处理程序中重新抛出异常时,这种方法会使VS中断,但原始调用堆栈丢失;我必须在错误行处设置断点并再次调试,以便在抛出异常时拦截状态.)
更新:我在博客上写了这个.在研究博客文章时,我发现了一些改进的潜力; 我已经更新了这个答案的相关部分.有关为什么我认为这比其他所有建议或默认行为更好的详细信息,请阅读整篇文章:)
我现在已经采用以下方法,即使不是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; } }
让该类替换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() .UseStageMarker(PipelineStage.Authenticate) // other middlewares omitted for brevity .UseStageMarker(PipelineStage.PreHandlerExecute) .UseWebApi(config);
我还是会给那些想出来的人奖励(赏金过期......)我仍然在寻找一个更好的解决方案,例如,当一个未处理的异常被抛出时会中断.(当我在处理程序中重新抛出异常时,这种方法会使VS中断,但原始调用堆栈丢失;我必须在错误行处设置断点并再次调试,以便在抛出异常时拦截状态.)