Web API系列 异常处理

Posted Cat in dotNET

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Web API系列 异常处理相关的知识,希望对你有一定的参考价值。

         在上一篇教程中我为大家介绍了Web API中Filter的开发使用,其中讲到ExceptionFilter时留了一个坑:ExceptionFilter只能截获并处理Action执行过程中发生的异常,在Action执行过程之外如果出现异常,ExceptionFilter是无能为力的。

      这些异常包括:

  1、  Controller构造方法中出现的异常

  2、  MessageHandlers中出现的异常

  3、  路由过程中出现的异常

  4、  Body在序列化/反序列化过程中出现的异常

  由此可以看出,ExceptionFilter只能解决ApiControler成功实例化后并执行Action期间出现的异常;为了解决这一个问题,在WEB API中除了ExceptionFilter外还引入了两个针对异常记录、处理的扩展点:

IExceptionLogger 和IExceptionHandler。

         而这两个扩展是作为Web API的管道组件进行注册管理的,并且,他们有不同的分工:

         IExceptionLogger作为异常日志记录组件,负责异常发生后的日志记录,他贯穿于整个Web API的生命周期中,在Web API框架里,任何一个请求周期中出现任何一个未被捕获/处理的异常都会首先进入这个异常日志记录管道进行异常Log记录,在Web API中可以注册多个IExceptionLogger实例负责不同的异常处理。

         IExceptionHandler作为异常处理组件,负责异常发生后的处理工作,他处于异常处理管道的最末端,当IExceptionLogger组件进行一场记录完毕、没有相关的ExceptoinFilter进行异常处理时,才会最终调用ExceptionHandler进行异常处理,在Web API中,有且仅有一个ExceptionHandler进行异常的处理。

         在Web API框架中给出了两个基类:ExceptionLogger和ExceptionHandler,在使用ExceptionLogger基类时,他提供了ShouldLog虚方法,该方法在基类中被调用,其作用在于避免同一个异常被同一个ExceptionLogger实例重复记录(如当后续的管道中该异常又被抛出,或者同一个ExceptionLogger对象不小心被注册了两次就会出现重复记录的可能)我们也能复写ShouldLog方法加入我们自己的异常记录判断逻辑以针对不同的场景进行不同的ExceptionLogger调用。如果有兴趣可以反编译一下ExceptionLogger基类看看,他使用了显示接口实现,挺有意思的一个技巧。下面我们来看一个ExceptionLogger使用的例子:

    public class ErroLogger : ExceptionLogger
    {
        public  async Task LogAsync(ExceptionLoggerContext context, CancellationToken cancellationToken)
        {
            var sb = new StringBuilder();
            //获取Log组件
            ILogger log = LogManager.GetCurrentClassLogger();

            var request = context.Request;

            sb.AppendLine("URL:");
            //获取URL
            var url = request.RequestUri.ToString();
            sb.AppendLine(url);
           
            log.Error(context.Exception,sb.ToString(),"");
        }

        public override bool ShouldLog(ExceptionLoggerContext context)
        {
            return context.Exception is DemoException && base.ShouldLog(context);
        }
    }

    在这个例子中,我们重写了ShouldLog,保证了这个ExceptionLogger只记录DemoException这个类型的异常,并且也调用了基类方法,保证不会重复记录同一个异常。在LogAsync方法中,我通过Log组件记录了导致异常的请求URL,也记录了异常信息。

接下来我们要对这个组件进行注册:

在App_Start/WebApiConfig.cs文件中的Register方法中写入

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

    这样,一个针对DemoException的异常记录组件就开发完成并注册完成了,当Web API执行管道中出现未处理的DemoException异常,均会调用则个组件进行记录。

    接下来我们来写一个ExceptionHandler,在整个Web API框架中,ExceptionHandler只能提供一个实例,与ExceptionLogger一样,我们可以继承ExceptionHandler基类来简化异常处理,在ExceptionHandler中也提供了ShouldHandle方法来判断该异常是否应该处理,避免重复处理管道中其他环节重复抛出的异常。我们也同样提供一个例子:

    public class ErrorHandler : ExceptionHandler
    {
        public override async Task HandleAsync(ExceptionHandlerContext context, CancellationToken cancellationToken)
        {
            if (context.Exception is DemoException)
            {
                context.Result = new ResponseMessageResult(context.Request.CreateResponse(HttpStatusCode.BadRequest,new {Message=context.Exception.Message}));
            }
            else
            {
                context.Result = new ResponseMessageResult(context.Request.CreateResponse(HttpStatusCode.InternalServerError,new {Message = "服务器已被外星人绑架"}));
            }
        }
}

    在这个例子中,我们判断了异常的类型,并根据不同的异常返回客户端不同的响应内容和不同的HTTP状态码。

    然后在配置中注册这个异常处理模块,在App_Start/WebApiConfig.cs文件中的Register方法中写入

config.Services.Replace(typeof(IExceptionHandler),new ErrorHandler());

以上是关于Web API系列 异常处理的主要内容,如果未能解决你的问题,请参考以下文章

Asp.Net Web API 2第七课——Web API异常处理

Web API统一异常处理 转载

具有未处理异常的 Nlog 事件属性的 .Net Core Web Api

扩展Python模块系列----异常和错误处理

全栈编程系列SpringBoot整合Shiro(含KickoutSessionControlFilter并发在线人数控制以及不生效问题配置启动异常No SecurityManager...)(代码片段

Web API系列教程3.8 — 实战:处理数据(显示条目细节)