OWIN / Katana 的未处理异常全局处理程序?
Posted
技术标签:
【中文标题】OWIN / Katana 的未处理异常全局处理程序?【英文标题】:Unhandled Exception Global Handler for OWIN / Katana? 【发布时间】:2015-06-18 14:46:06 【问题描述】:在 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 输出窗口确实包含以下内容:
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 上运行。
感谢所有想法。 谢谢。
【问题讨论】:
【参考方案1】:尝试编写自定义中间件并将其作为第一个中间件:
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
【讨论】:
那行不通。默认情况下会处理 Web API 异常。代码不会进入 catch 块。试试看。 @Dr Schizo:如果 web api 捕获到异常并且swallowed
(这意味着 web api 已经完成了恢复)。这段代码肯定不会进入 catch 块,就像任何正常的异常处理代码一样。如果您在堆栈跟踪中捕获异常并且不重新抛出它,则堆栈跟踪上方的代码将不会捕获任何异常。这是预期的行为。
@Dr Schizo: Web API exceptions are handled by default
=> 这意味着异常是handled
,因此它不会向上传播堆栈跟踪。这个全局中间件只处理 unhandled
异常,这很有意义,它不处理 handled
异常(通过 web api)。对于任何未处理(由其他中间件)抛出或在 web api 中重新抛出的异常,这个中间件应该能够捕获它们。
我的假设是,如果我有一个控制器在调用它的动作时抛出异常,我希望中间件(你已经描述过)捕捉到这个并且实现做它需要做的任何事情,即记录它等。麻烦的是中间件实际上并没有进入catch块,因此不知道引发的异常也不存在于字典中。我误会了吗?
@Khanh 在我启动并运行的基本示例中,我有一个控制器和一个引发异常的单个操作。除了我认为可以处理此问题的默认 Web API 行为外,其他任何地方都无法处理此问题。因此,中间件不做任何事情。您必须替换现有的全局异常处理程序 Web API,然后此中间件才能工作。请参阅我链接到的线程。【参考方案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());
【讨论】:
这应该是答案。【参考方案3】:@Khanh TO 的回答非常好;代码简洁,解释清楚。
它对我不起作用。我向我的一个 .NET MVC 控制器添加了一个测试异常,如下所示:
throw new Exception("Test GlobalExceptionMiddleware");
Invoke
方法中没有捕获到异常。
这很容易调试:
-
在测试异常上设置断点。
点击 F10 或跳过每一行,直到找到 处理异常的代码。
对我来说,有代码添加到 BaseController
覆盖 OnException
。此代码正在处理异常而不是重新抛出。我希望这是对@Khanh TO 答案的有用补充。
更新
好的,我意识到这个问题是用 Web API 标记的,我的用例是 .NET MVC,但是我在搜索 Owin 中间件时发现了这个问题。当我使用测试异常调试我的解决方案并在 Locals 视图中查看 $exception
时,当我返回 Owin 中间件时,异常已消失。因此,我没有在@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;
此答案将捕获应用程序启动时的任何异常以及控制器中的任何异常。这足以满足我的需求。
【讨论】:
【参考方案4】:您可以使用自定义异常过滤器属性。
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)
【讨论】:
以上是关于OWIN / Katana 的未处理异常全局处理程序?的主要内容,如果未能解决你的问题,请参考以下文章
The Open Web Interface for .NET (OWIN) 源码阅读
Kotlin 协程协程异常处理 ④ ( Android 协程中出现异常导致应用崩溃 | Android 协程中使用协程异常处理器捕获异常 | Android 全局异常处理器 )
Kotlin 协程协程异常处理 ④ ( Android 协程中出现异常导致应用崩溃 | Android 协程中使用协程异常处理器捕获异常 | Android 全局异常处理器 )