OWIN / Katana 未处理的异常全局处理程序?
Unhandled Exception Global Handler for OWIN / Katana?
在 Katana (OWIN) 实现中实现全局异常捕获器处理程序的正确方法是什么?
在作为 Azure 云服务(工作者角色)的自托管 OWIN/Katana 实现 运行 中,我将这段代码放在中间件中:
throw new Exception("pooo");
然后我把这段代码放在 Startup class 配置方法中,在事件处理程序中设置断点:
AppDomain.CurrentDomain.UnhandledException +=
CurrentDomain_UnhandledExceptionEventHandler;
和事件处理程序在同一个class(第一行设置断点):
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 输出 window 确实包含此内容:
A first chance exception of type 'System.Exception' occurred in redacted.dll
A first chance exception of type 'System.Exception' occurred in mscorlib.dll
我也尝试将 wireup 和处理程序移动到 Worker Role OnStart 方法,但仍然没有命中断点。
我根本没有使用 WebAPI,但确实查看了有关那里所做的事情的帖子,但我没有发现任何明确的地方,所以我来了。
运行 .NET Framework 4.5.2,VS 2013。
感谢所有想法。
谢谢
尝试编写自定义中间件并将其作为第一个中间件:
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
块捕获。
并不一定要把它注册为第一个中间件,如果你不需要对某些中间件进行全局异常处理,只需在这个中间件之前注册这些中间件即可。
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
}
}
@Khanh TO 的回答很好;代码简洁明了,解释得很好。
它对我不起作用。我向我的一个 .NET MVC 控制器添加了一个测试异常,如下所示:
throw new Exception("Test GlobalExceptionMiddleware");
Invoke
方法中没有捕获异常。
这很容易调试:
- 在测试异常上放置一个断点。
- 点击 F10 或跳过每一行,直到您到达 正在 处理异常的代码。
对我来说,BaseController
覆盖 OnException
添加了代码。此代码正在处理异常而不是重新抛出。我希望这是对@Khanh TO 回答的有益补充。
更新
好的,我知道这个问题是用 Web API 标记的,我的用例是 .NET MVC,但我在搜索 Owin 中间件时发现了这个问题。当我使用测试异常调试我的解决方案并在 Locals 视图中观察 $exception
时,当我返回到 Owin 中间件时异常是 gone。因此我没有使用@Khanh TO 的回答中的代码。相反,我在我的 Startup 和 Global.asax 中添加了 try/catch 块。我的基本控制器中也有 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;
}
此答案将捕获应用程序启动时的任何异常和控制器中的任何异常。这足以满足我的需求。
试试这个:
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());
}
您可以使用自定义异常过滤器属性。
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)
{
}
}
在 Katana (OWIN) 实现中实现全局异常捕获器处理程序的正确方法是什么?
在作为 Azure 云服务(工作者角色)的自托管 OWIN/Katana 实现 运行 中,我将这段代码放在中间件中:
throw new Exception("pooo");
然后我把这段代码放在 Startup class 配置方法中,在事件处理程序中设置断点:
AppDomain.CurrentDomain.UnhandledException +=
CurrentDomain_UnhandledExceptionEventHandler;
和事件处理程序在同一个class(第一行设置断点):
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 输出 window 确实包含此内容:
A first chance exception of type 'System.Exception' occurred in redacted.dll
A first chance exception of type 'System.Exception' occurred in mscorlib.dll
我也尝试将 wireup 和处理程序移动到 Worker Role OnStart 方法,但仍然没有命中断点。
我根本没有使用 WebAPI,但确实查看了有关那里所做的事情的帖子,但我没有发现任何明确的地方,所以我来了。
运行 .NET Framework 4.5.2,VS 2013。
感谢所有想法。 谢谢
尝试编写自定义中间件并将其作为第一个中间件:
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
块捕获。
并不一定要把它注册为第一个中间件,如果你不需要对某些中间件进行全局异常处理,只需在这个中间件之前注册这些中间件即可。
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
}
}
@Khanh TO 的回答很好;代码简洁明了,解释得很好。
它对我不起作用。我向我的一个 .NET MVC 控制器添加了一个测试异常,如下所示:
throw new Exception("Test GlobalExceptionMiddleware");
Invoke
方法中没有捕获异常。
这很容易调试:
- 在测试异常上放置一个断点。
- 点击 F10 或跳过每一行,直到您到达 正在 处理异常的代码。
对我来说,BaseController
覆盖 OnException
添加了代码。此代码正在处理异常而不是重新抛出。我希望这是对@Khanh TO 回答的有益补充。
更新
好的,我知道这个问题是用 Web API 标记的,我的用例是 .NET MVC,但我在搜索 Owin 中间件时发现了这个问题。当我使用测试异常调试我的解决方案并在 Locals 视图中观察 $exception
时,当我返回到 Owin 中间件时异常是 gone。因此我没有使用@Khanh TO 的回答中的代码。相反,我在我的 Startup 和 Global.asax 中添加了 try/catch 块。我的基本控制器中也有 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;
}
此答案将捕获应用程序启动时的任何异常和控制器中的任何异常。这足以满足我的需求。
试试这个:
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());
}
您可以使用自定义异常过滤器属性。
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)
{
}
}