捕获ASP.NET Web Api中所有未处理的异常

时间:2013-04-16 04:41:12

标签: c# asp.net-web-api unhandled-exception

如何捕获 ASP.NET Web Api中发生的所有未处理的异常,以便我可以记录它们?

到目前为止,我已经尝试过:

  • 创建并注册ExceptionHandlingAttribute
  • Application_Error
  • 中实施Global.asax.cs方法
  • 订阅AppDomain.CurrentDomain.UnhandledException
  • 订阅TaskScheduler.UnobservedTaskException

ExceptionHandlingAttribute成功处理控制器操作方法和操作过滤器中引发的异常,但不处理其他异常,例如:

  • 操作方法返回的IQueryable无法执行时抛出的异常
  • 消息处理程序抛出的异常(即HttpConfiguration.MessageHandlers
  • 创建控制器实例时抛出的异常

基本上,如果异常将导致500内部服务器错误返回到客户端,我希望它被记录。实现Application_Error在Web窗体和MVC中做得很好 - 我可以在Web Api中使用什么?

5 个答案:

答案 0 :(得分:153)

现在可以使用WebAPI 2.1(参见What's New):

创建IExceptionLogger的一个或多个实现。例如:

public class TraceExceptionLogger : ExceptionLogger
{
    public override void Log(ExceptionLoggerContext context)
    {
        Trace.TraceError(context.ExceptionContext.Exception.ToString());
    }
}

然后在配置回调中注册您的应用程序的HttpConfiguration,如下所示:

config.Services.Add(typeof(IExceptionLogger), new TraceExceptionLogger());

或直接:

GlobalConfiguration.Configuration.Services.Add(typeof(IExceptionLogger), new TraceExceptionLogger());

答案 1 :(得分:19)

Yuval的答案是自定义对Web API捕获的未处理异常的响应,而不是用于记录,如链接page所述。有关详细信息,请参阅页面上的“何时使用”部分。始终调用记录器,但只有在可以发送响应时才调用处理程序。简而言之,使用logger来记录和处理程序来自定义响应。

顺便说一句,我使用的是程序集v5.2.3,而ExceptionHandler类没有HandleCore方法。我认为等价物是Handle。但是,简单地继承ExceptionHandler(如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);
    }
}

请注意,与记录器不同,您可以通过替换默认处理程序来注册处理程序,而不是添加。

config.Services.Replace(typeof(IExceptionHandler),
    new OopsExceptionHandler(config.Services.GetExceptionHandler()));

答案 2 :(得分:18)

要回答我自己的问题,这是不可能的!

处理导致内部服务器错误的所有异常似乎是Web API应具备的基本功能,因此我向Microsoft请求了一个 Web API的全局错误处理程序

https://aspnetwebstack.codeplex.com/workitem/1001

如果您同意,请转到该链接并投票支持!

与此同时,优秀的文章ASP.NET Web API Exception Handling显示了几种不同的方法来捕捉几种不同类型的错误。它比它应该更复杂,并且它不会捕获所有内部服务器错误,但它是目前可用的最佳方法。

更新:全局错误处理现已实施,并可在夜间版本中使用!它将在ASP.NET MVC v5.1中发布。以下是它的工作原理:https://aspnetwebstack.codeplex.com/wikipage?title=Global%20Error%20Handling

答案 3 :(得分:9)

您还可以通过实现IExceptionHandler接口(或继承ExceptionHandler基类)来创建全局异常处理程序。在所有已注册的IExceptionLogger

之后,它将是在执行链中被调用的最后一个
  

IExceptionHandler处理所有未处理的异常   控制器。这是列表中的最后一个。如果发生异常,则   首先调用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);
        }
    }
}

有关here的更多信息。

答案 4 :(得分:0)

我认为我的新global.asax.Application_Error方法并未在我们的遗留代码中一直调用未处理的异常。

然后我在调用堆栈的中间找到了几个try-catch块,它们在Exception文本上调用了Response.Write。就是这样。将文字倾倒在屏幕上然后杀死了异常石头。