在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石头死亡。