在ASP.NET Web Api中捕获所有未处理的exception
如何捕获ASP.NET Web Api中发生的所有未处理的exception,以便我可以logging它们?
到目前为止我已经尝试过:
- 创build并注册一个
ExceptionHandlingAttribute
- 在
Global.asax.cs
实现一个Application_Error
方法 - 订阅
AppDomain.CurrentDomain.UnhandledException
- 订阅
TaskScheduler.UnobservedTaskException
ExceptionHandlingAttribute
成功处理控制器操作方法和操作filter中引发的exception,但是不处理其他exception,例如:
- 操作方法返回的
IQueryable
执行失败时抛出exception - 消息处理程序引发的exception(即
HttpConfiguration.MessageHandlers
) - 创build控制器实例时抛出exception
基本上,如果一个exception将导致500内部服务器错误返回给客户端,我希望它被logging。 实现Application_Error
在Web窗体和MVC中完成了这项工作 – 我可以在Web Api中使用什么?
现在可以使用WebAPI 2.1(请参阅新function ):
创build一个或多个IExceptionLogger的实现。 例如:
public class TraceExceptionLogger : ExceptionLogger { public override void Log(ExceptionLoggerContext context) { Trace.TraceError(context.ExceptionContext.Exception.ToString()); } }
然后注册你的应用程序的HttpConfiguration,在一个configurationcallback像这样:
config.Services.Add(typeof(IExceptionLogger), new TraceExceptionLogger());
或直接:
GlobalConfiguration.Configuration.Services.Add(typeof(IExceptionLogger), new TraceExceptionLogger());
回答我自己的问题,这是不可能的!
处理导致内部服务器错误的所有exception看起来像Web API应该具有的基本function,所以我已经向Microsoft发出了一个请求,要求提供Web API的全局error handling程序 :
https://aspnetwebstack.codeplex.com/workitem/1001
如果你同意,去那个链接并投票!
与此同时,优秀的文章ASP.NET Web APIexception处理显示了几种不同的方法来捕捉几个不同类别的错误。 它比应该更复杂,并没有捕捉到所有的内部服务器错误,但这是今天最好的方法。
更新:全局error handling现在已经实现,并在每晚的构build中可用! 它将在ASP.NET MVC v5.1中发布。 以下是它的工作原理: https : //aspnetwebstack.codeplex.com/wikipage?title=Global%20Error%20Handling
Yuval的答案是定制Web API捕获的未处理exception的响应,而不是logging,如链接页面所述 。 有关详细信息,请参阅页面上的何时使用部分。 logging器总是被调用,但只有当响应可以被发送时才调用处理器。 总之,使用logging器logging和处理程序来定制响应。
顺便说一句,我使用程序集v5.2.3和ExceptionHandler
类没有HandleCore
方法。 相当于我认为是Handle
。 但是,简单地inheritanceExceptionHandler
(如Yuval的答案)不起作用。 在我的情况下,我必须执行如下的IExceptionHandler
。
internal class OopsExceptionHandler : IExceptionHandler { private readonly IExceptionHandler _innerHandler; public OopsExceptionHandler (IExceptionHandler innerHandler) { if (innerHandler == null) throw new ArgumentNullException(nameof(innerHandler)); _innerHandler = innerHandler; } public IExceptionHandler InnerHandler { get { return _innerHandler; } } public Task HandleAsync(ExceptionHandlerContext context, CancellationToken cancellationToken) { Handle(context); return Task.FromResult<object>(null); } public void Handle(ExceptionHandlerContext context) { // Create your own custom result here... // In dev, you might want to null out the result // to display the YSOD. // context.Result = null; context.Result = new InternalServerErrorResult(context.Request); } }
请注意,与logging器不同,您通过replace默认处理程序来注册您的处理程序,而不是添加。
config.Services.Replace(typeof(IExceptionHandler), new OopsExceptionHandler(config.Services.GetExceptionHandler()));
您也可以通过实现IExceptionHandler
接口(或inheritanceExceptionHandler
基类)来创build全局exception处理程序。 这将是最后被调用的执行链,毕竟注册了IExceptionLogger
:
IExceptionHandler处理来自所有控制器的所有未处理的exception。 这是列表中的最后一个。 如果发生exception,则首先调用IExceptionLogger,然后调用ExceptionFilters控制器,如果仍未处理,则执行IExceptionHandler实现。
public class OopsExceptionHandler : ExceptionHandler { public override void HandleCore(ExceptionHandlerContext context) { context.Result = new TextPlainErrorResult { Request = context.ExceptionContext.Request, Content = "Oops! Sorry! Something went wrong." }; } private class TextPlainErrorResult : IHttpActionResult { public HttpRequestMessage Request { get; set; } public string Content { get; set; } public Task<HttpResponseMessage> ExecuteAsync(CancellationToken cancellationToken) { HttpResponseMessage response = new HttpResponseMessage(HttpStatusCode.InternalServerError); response.Content = new StringContent(Content); response.RequestMessage = Request; return Task.FromResult(response); } } }
更多在这里 。
我认为我的新的global.asax.Application_Error
方法并没有在我们的遗留代码中被一致地调用未处理的exception。
然后,我在调用堆栈的中间find一些try-catch块,在exception文本上调用Response.Write。 就是这样。 抛弃屏幕上的文字,然后杀死exception石头死亡。