我想将异常处理连接到一个中间件组件中,如下所示:

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

然而,我想捕获的一些异常在我能够访问它们之前被Web API管道捕获并转换为HttpErrorResponse.在这个过程中,我丢失了很多关于错误的细节,因此在调试时,我无法获得有用的堆栈跟踪等(当抛出异常时,调试器甚至不会停止——我必须手动逐步判断代码,看看它在哪里失败……).

我try 使用以下实现添加自定义异常处理程序:

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<Exception>(Constants.ContextKeys.Exception);

still并没有给出我想要的所有细节,也没有在调试程序出现故障时停止.

有没有一种方法可以关闭all内置的错误处理,这样我自己的中间件就可以处理它?

Clarification,因为很多人似乎误解了我想要的是什么:

  • Web API中的内置错误处理捕获some个(但不是全部)异常,并将它们重写为500个响应.
  • 我想捕获all个异常,做一些日志(log)记录,then发出500个响应with the information I choose(对于大多数异常,请参阅下一个项目).
  • 还有一些发出业务逻辑错误信号的异常,对于这些异常,我希望返回40x错误.
  • 我希望它处于(应用程序)管道的顶端,即在请求生命周期中包装everything个其他应用程序
  • 我想使用OWIN来处理这个问题,使其可移植到future 可能的自托管场景中(也就是说,这个应用程序始终托管在IIS上并非一成不变——HTTP模块、Global.asax.cs等在这里不相关).

推荐答案

Update:I blogged about this.在研究这篇博客文章时,我发现了一些改进的潜力;我已经更新了这个答案的相关部分.有关我认为这比这里的所有其他建议或默认行为更好的原因的更多详细信息,请阅读整个帖子:)


我现在采用了以下方法,虽然不是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成为Web API IExceptionHandler服务:

    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);
    

我仍然会将赏金奖励给任何提出(赏金过期…)的人我仍在寻找更好的解决方案,例如,当抛出unhandled个异常时,该解决方案就会中断.(当我在处理程序中重新抛出异常时,这种方法会使VS中断,但原始调用堆栈会丢失;我必须在错误行设置一个断点,然后再次调试,以便在抛出异常时能够拦截状态.)

Asp.net相关问答推荐

'dotnet --version is returning您必须安装或更新.NET才能运行此应用程序.三十九岁;

Reaction-Native SignalR连接在调试模式下工作,在释放模式下失败

Thread.CurrentPrincipal 错误地声称是匿名的

jQuery隐藏字段

SignalR 不在服务器上使用 Session

为 Web 请求实现速率限制算法的最佳方法是什么?

ASP.NET 控件无法在 Visual Studio 2008 的代码隐藏中引用

从 RowDataBound 事件的 gridview 从单元格中获取值

这两种方法有什么区别?

System.Web.HttpContext 无法识别

从 JavaScript 读取 web.config

是否应该将 project.lock.json 文件签入源代码管理? (ASP.NET 核心 1.0)

等价于 ASP.NET Core 中的 Html.RenderAction

修改 web.config 时如何防止 ASP.NET 应用程序重新启动?

SQLServer 与 StateServer 的 ASP.NET 会话状态性能

当用户在文本框中按 Enter 键时执行按钮单击事件

ASP.NET Excel 导出编码问题

Ashx 文件中的 HttpContext.Current.Session 为空

哪个事件先调用?母版页 Page_Load 或内容页 Page_Load

Facebook 连接和 ASP.NET