C# OWIN/Katana的未处理异常全局处理程序?
在Katana(OWIN)实现中实现全局异常捕捉器处理程序的正确方法是什么 在作为Azure云服务(工作者角色)运行的自托管OWIN/Katana实现中,我将以下代码放置在中间件中:C# OWIN/Katana的未处理异常全局处理程序?,c#,asp.net-web-api,exception-handling,owin,katana,C#,Asp.net Web Api,Exception Handling,Owin,Katana,在Katana(OWIN)实现中实现全局异常捕捉器处理程序的正确方法是什么 在作为Azure云服务(工作者角色)运行的自托管OWIN/Katana实现中,我将以下代码放置在中间件中: throw new Exception("pooo"); public class GlobalExceptionMiddleware : OwinMiddleware { public GlobalExceptionMiddleware(OwinMiddleware next) : base(next)
throw new Exception("pooo");
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
}
}
然后,我将此代码放在Startup类配置方法中,在事件处理程序中设置断点:
AppDomain.CurrentDomain.UnhandledException +=
CurrentDomain_UnhandledExceptionEventHandler;
和同一类中的事件处理程序(第一行设置了断点):
当代码运行时,不会命中断点。但是,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和handler移动到Worker角色OnStart方法,但仍然没有命中断点
我根本没有使用WebAPI,但确实查看了关于在那里做了什么的帖子,但我没有发现任何明确的内容,所以我在这里
在.NET Framework 4.5.2上运行,与2013年相比
所有想法都受到赞赏。
谢谢。尝试编写一个自定义中间件,并将其作为第一个中间件:
throw new Exception("pooo");
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
}
}
将其作为第一个中间件:
throw new Exception("pooo");
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
}
}
@Khanh TO的回答非常好;很好的简洁代码,解释得很好 这对我不起作用。我向一个.NET MVC控制器添加了一个测试异常,如下所示:
throw new Exception("Test GlobalExceptionMiddleware");
protected override void OnException(ExceptionContext filterContext)
{
if (filterContext.ExceptionHandled)
{
return;
}
var e = filterContext.Exception;
Log.Error("BaseController.OnException caught exception:", e);
filterContext.ExceptionHandled = true;
}
Invoke
方法中未捕获异常
这很容易调试:
BaseController
覆盖OnException
。此代码正在处理异常,而不是重新触发。我希望这是对@Khanh to答案的有益补充
更新
好的,我意识到这个问题是用WebAPI标记的,我的用例是.NETMVC,但我在搜索Owin中间件时发现了这个问题。当我调试带有测试异常的解决方案,并在Locals视图中查看$exception
时,当我回到Owin中间件时,异常就消失了。因此,我没有使用@Khanh TO答案中的代码。相反,我在我的Startup和Global.asax中添加了try/catch块。我的基本控制器中也有一个异常,如下所示:
throw new Exception("Test GlobalExceptionMiddleware");
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)
{
}
}
那不行。默认情况下会处理Web API异常。代码将不会进入catch块。试试看。@Schizo博士:如果异常被web api捕获并吞没(这意味着web api已经完成了恢复)。这段代码肯定不会进入catch块,就像任何正常的异常处理代码一样。如果您在堆栈跟踪中捕获了一个异常,并且没有重新抛出它,那么堆栈跟踪上方的代码将不会捕获任何异常。这是预期的行为。@Schizo博士:
Web API异常在默认情况下被处理
=>这意味着异常被处理,因此它不会向上传播堆栈跟踪。这个全局中间件只处理未处理的
异常,这使得它不处理已处理的
异常(通过web api)非常有意义。对于任何未经处理(由其他中间件)抛出的异常或web api内部重新抛出的异常,该中间件应该能够捕获它们。我的假设是,如果我有一个控制器在调用其操作时抛出异常,我希望中间件(您已经描述)能够捕获该异常,并且实现能够执行它需要执行的任何操作,问题是中间件实际上没有进入catch块,因此没有意识到引发的异常,也没有出现在字典中。我是否误解了?@Khanh在我启动并运行的基本示例中,我有一个控制器和一个引发异常的操作。除了默认的WebAPI行为之外,没有任何地方可以处理这个问题,我相信它可以处理这个问题。因此,中间件不做任何事情。您必须替换web API中的全局异常处理程序,然后该中间件才能工作。请看我链接到的线程。这应该是答案。