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

时间:2015-06-18 14:46:06

标签: c# asp.net-web-api exception-handling owin katana

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

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

throw new Exception("pooo");

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

 AppDomain.CurrentDomain.UnhandledException += 
    CurrentDomain_UnhandledExceptionEventHandler;

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

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

当代码运行时,不会触发断点。但是Visual Studio Output窗口确实包含了这个:

A first chance exception of type 'System.Exception' occurred in redacted.dll
A first chance exception of type 'System.Exception' occurred in mscorlib.dll

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

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

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

所有想法都赞赏。 感谢。

4 个答案:

答案 0 :(得分:38)

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

1
0

将其设置为第一个中间件:

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
      }
   }
 }

当我们将这个中间件注册为第一个中间件时,其他中间件(在堆栈跟踪中)发生的任何异常都会传播并被此中间件的public class Startup { public void Configuration(IAppBuilder builder) { var config = new HttpConfiguration(); builder.Use<GlobalExceptionMiddleware>(); //register other middlewares } } 块捕获。

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

try/catch

答案 1 :(得分:2)

试试这个:

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

在启动时:

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

  config.Services.Replace(typeof(IExceptionHandler), new CustomExceptionHandler());
}

答案 2 :(得分:0)

@Khanh TO的回答非常好;很好的简洁代码,并且解释清楚。

这不适合我。我在我的一个.NET MVC控制器中添加了一个测试异常,如下所示:

throw new Exception("Test GlobalExceptionMiddleware");

Invoke方法没有捕捉到异常。

这很容易调试:

  1. 在测试例外中设置断点。
  2. 点击 F10 或跨过每一行,直到找到 处理异常的代码。
  3. 对我来说,代码已添加到BaseController覆盖OnException。此代码处理异常而不是重新抛出。我希望这是@Khanh TO答案的有用附录。

    更新

    好的,我意识到这个问题是用Web API标记的,我的用例是.NET MVC,但我在搜索Owin中间件时发现了这个问题。当我使用测试异常调试我的解决方案,并在Locals视图中观察$exception时,当我回到Owin中间件时,异常已消失。因此我没有在@Khanh TO答案中使用该代码。相反,我已将try / catch块添加到我的Startup和Global.asax中。我的基本控制器中还有OnException,如下所示:

    protected override void OnException(ExceptionContext filterContext)
    {
        if (filterContext.ExceptionHandled)
        {
            return;
        }
        var e = filterContext.Exception;
        Log.Error("BaseController.OnException caught exception:", e);
        filterContext.ExceptionHandled = true;
    }
    

    此答案将捕获应用程序启动时的任何异常以及控制器中的任何异常。这足以满足我的需求。

答案 3 :(得分:0)

您可以使用自定义异常过滤器属性。

public static class WebApiConfiguration
{
    public static void Register(HttpConfiguration config)
    {
        config.RegisterExceptionFilters();
    }
}

public static class HttpConfigurationFilterExtensions
{
    public static HttpConfiguration RegisterExceptionFilters(this HttpConfiguration httpConfig)
    {
        httpConfig.Filters.Add(new CustomExceptionFilterAttribute());

        return httpConfig;
    }
}

public class CustomExceptionFilterAttribute : ExceptionFilterAttribute
{
    public override void OnException(HttpActionExecutedContext context)
    {
        if (context.Exception is CustomException)
        {
            context.Response = new HttpResponseMessage((HttpStatusCode)CustomHttpStatusCode.CustomCode);
        }
    }
}

public class CustomException : Exception
{
    public CustomException(string message)
        : base(message)
    {
    }
}