OWIN/Katana未处理的异常全局处理程序?

Sno*_*owy 35 c# exception-handling asp.net-web-api owin katana

在Katana(OWIN)实现中实现全局异常捕获器处理程序的正确方法是什么?

在作为Azure云服务(工作者角色)运行的自托管OWIN/Katana实现中,我将此代码放在中间件中:

throw new Exception("pooo");
Run Code Online (Sandbox Code Playgroud)

然后我将此代码放在Startup类Configuration方法中,在事件处理程序中设置断点:

 AppDomain.CurrentDomain.UnhandledException += 
    CurrentDomain_UnhandledExceptionEventHandler;
Run Code Online (Sandbox Code Playgroud)

和同一个类中的事件处理程序(在第一行设置断点):

private static void CurrentDomain_UnhandledExceptionEventHandler(object sender, UnhandledExceptionEventArgs e)
{
    var exception = (Exception)e.ExceptionObject;
    Trace.WriteLine(exception.Message);
    Trace.WriteLine(exception.StackTrace);
    Trace.WriteLine(exception.InnerException.Message);
}
Run Code Online (Sandbox Code Playgroud)

代码运行时,不会触发断点.Visual Studio输出窗口确实包括此:

A first chance exception of type 'System.Exception' occurred in redacted.dll
A first chance exception of type 'System.Exception' occurred in mscorlib.dll
Run Code Online (Sandbox Code Playgroud)

我也尝试将连接和处理程序移动到Worker Role OnStart方法,但仍然没有命中断点.

我根本没有使用WebAPI,但确实查看过那里做的帖子,但我没有发现任何明确的内容,所以我在这里.

在.NET Framework 4.5.2,VS 2013上运行.

所有想法都赞赏.谢谢.

Kha*_* TO 40

尝试编写自定义中间件并将其作为第一个中间件放置:

public class GlobalExceptionMiddleware : OwinMiddleware
{
   public GlobalExceptionMiddleware(OwinMiddleware next) : base(next)
   {}

   public override async Task Invoke(IOwinContext context)
   {
      try
      {
          await Next.Invoke(context);
      }
      catch(Exception ex)
      {
          // your handling logic
      }
   }
 }
Run Code Online (Sandbox Code Playgroud)

将它作为第一个中间件:

public class Startup
{
    public void Configuration(IAppBuilder builder)
    {
        var config = new HttpConfiguration();

        builder.Use<GlobalExceptionMiddleware>();
        //register other middlewares
    }
}
Run Code Online (Sandbox Code Playgroud)

当我们将这个中间件注册为第一个中间件时,其他中间件(在堆栈跟踪中)发生的任何异常都会传播并被try/catch此中间件的块捕获.

并不是必须始终将其注册为第一个中间件,如果您不需要对某些中间件进行全局异常处理,只需在此之前注册这些中间件即可.

public class Startup
{
    public void Configuration(IAppBuilder builder)
    {
        var config = new HttpConfiguration();

        //register middlewares that don't need global exception handling. 
        builder.Use<GlobalExceptionMiddleware>();
        //register other middlewares
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 这不起作用.默认情况下处理Web API异常.代码不会进入catch块.试试吧. (26认同)
  • @Dr Schizo:`默认处理Web API异常`=>这意味着异常是`handling`,因此它不会传播堆栈跟踪.这个全局中间件只处理`unhandled`异常,这很有意义,它不处理`handle`异常(通过web api).对于任何未处理(由其他中间件)或在web api中重新抛出的异常,这个中间件应该能够捕获它们. (8认同)
  • @Dr Schizo:如果异常被Web api捕获并"吞噬"(这意味着web api已完成恢复).这个代码肯定不会进入catch块,就像任何正常的异常处理代码一样.如果在堆栈跟踪中捕获异常并且不重新抛出它,则堆栈跟踪上方的代码将不会捕获任何异常.这是预期的行为. (3认同)
  • 我在这里的假设是,如果我有一个控制器在调用它的动作时抛出一个异常我会期望中间件(你已经描述过)捕获这个以及执行它需要做什么,即记录它等等.麻烦就是中间件实际上并没有进入catch块,因此不知道引发的异常也不会出现在字典中.我误解了吗? (2认同)

Gre*_*lor 9

尝试这个:

public class CustomExceptionHandler : IExceptionHandler
{    
    public Task HandleAsync(ExceptionHandlerContext context, CancellationToken cancellationToken)
    {
      // Perform some form of logging

      context.Result = new ResponseMessageResult(new HttpResponseMessage
      {
        Content = new StringContent("An unexpected error occurred"),
        StatusCode = HttpStatusCode.InternalServerError
      });

      return Task.FromResult(0);
    }
}
Run Code Online (Sandbox Code Playgroud)

并在启动时:

public void Configuration(IAppBuilder app)
{
  var config = new HttpConfiguration();

  config.Services.Replace(typeof(IExceptionHandler), new CustomExceptionHandler());
}
Run Code Online (Sandbox Code Playgroud)