首页 文章

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

提问于
浏览
105

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

到目前为止,我尝试过:

  • 创建并注册ExceptionHandlingAttribute

  • Global.asax.cs 中实现 Application_Error 方法

  • 订阅 AppDomain.CurrentDomain.UnhandledException

  • 订阅 TaskScheduler.UnobservedTaskException

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

  • 由操作方法返回的 IQueryable 无法执行时抛出异常

  • 消息处理程序抛出的异常(即 HttpConfiguration.MessageHandlers

  • 创建控制器实例时抛出异常

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

5 回答

  • 16

    现在可以使用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());
    
  • 7

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

    处理导致内部服务器错误的所有异常似乎是Web API应具备的基本功能,因此我向Microsoft提出了一个请求 Global error handler for Web API

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

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

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

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

  • 18

    Yuval的答案是自定义对Web API捕获的未处理异常的响应,而不是针对日志记录,如链接page所述 . 有关详细信息,请参阅页面上的“何时使用”部分 . 始终调用 Logger ,但只有在可以发送响应时才调用处理程序 . 简而言之,使用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);
        }
    }
    

    请注意,与 Logger 不同,您通过替换默认处理程序而不是添加来注册处理程序 .

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

    您还可以通过实现 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 .

  • 0

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

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

相关问题