在ASP.NET Web API 2中禁用*all*异常处理(为我自己腾出空间)?

Tom*_*han 42 c# asp.net asp.net-web-api owin

我想在中间件组件中连接异常处理,如下所示:

public override async Task Invoke(IOwinContext context)
{
    try
    {
        await Next.Invoke(context);
    }
    catch (Exception ex)
    {
        // Log error and return 500 response
    }
}
Run Code Online (Sandbox Code Playgroud)

但是,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);
}
Run Code Online (Sandbox Code Playgroud)

通过注册config.Services.Replace(typeof(IExceptionHandler), new MyExceptionHandler());在我的启动配置,但在执行后看着它Next.Invoke(context)通过

context.Get<Exception>(Constants.ContextKeys.Exception);
Run Code Online (Sandbox Code Playgroud)

仍然没有给我所有我想要的细节,以及没有在调试器的故障点停止.

有没有办法可以完全关闭所有内置错误处理,以便我自己的中间件可以处理它?

澄清,因为很多人似乎误解了我的追求:

  • Web API中的内置错误处理捕获了一些(但不是全部)异常,并将它们重写为500个响应.
  • 我想捕获所有异常,进行一些日志记录,然后使用我选择的信息发出500个响应(对于大多数异常,请参阅下一个项目符号).
  • 还有一些异常表示业务逻辑故障,我想为此返回40x错误.
  • 我希望它位于(app)管道的顶部,即包装请求生命周期中的所有其他内容
  • 我想使用OWIN来处理这个问题,以便将其移植到可能的未来自托管方案中(也就是说,这个应用程序将永远托管在IIS上 - 这些应用程序将永远存在于IIS - HTTP模块中,Global.asax.cs等不相关这里).

Tom*_*han 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;
        }
    }
    
    Run Code Online (Sandbox Code Playgroud)
  • 让该类替换IExceptionHandler Web API 的服务:

    config.Services.Replace(typeof(IExceptionHandler), new PassthroughExceptionHandler());
    
    Run Code Online (Sandbox Code Playgroud)
  • 创建一个中间件类,它做我想要的:

    public class ExceptionHandlerMiddleware
    {
        public override async Task Invoke(IOwinContext context)
        {
            try
            {
                await Next?.Invoke(context);
            }
            catch (Exception ex)
            {
                // handle and/or log
            }
        }
    }
    
    Run Code Online (Sandbox Code Playgroud)
  • 首先在堆栈中注册该中间件:

    app.Use<ExceptionHandlerMiddleware>()
       .UseStageMarker(PipelineStage.Authenticate)
       // other middlewares omitted for brevity
       .UseStageMarker(PipelineStage.PreHandlerExecute)
       .UseWebApi(config);
    
    Run Code Online (Sandbox Code Playgroud)

我还是会给那些想出来的人奖励(赏金过期......)我仍然在寻找一个更好的解决方案,例如,当一个未处理的异常被抛出时会中断.(当我在处理程序中重新抛出异常时,这种方法会使VS中断,但原始调用堆栈丢失;我必须在错误行处设置断点并再次调试,以便在抛出异常时拦截状态.)

  • 哇.你有很多乐趣!太奇妙了!可能值得一篇博文! (2认同)

归档时间:

查看次数:

6014 次

最近记录:

8 年,10 月 前