webapi框架搭建-webapi异常处理

webapi框架搭建系列博客

前言

  上一篇我们已经完成了项目的日志管理,在项目开发中日志会经常记录程序中的异常,供后续问题排查使用。本篇讲如何在webapi里加入异常处理机制。

目的和原则

  1、程序任何地方都不能catch掉异常,如果要catch也请重新throw异常或是将异常记录到日志里。避免异常被“吃掉“,导致无法排查程序的bug。

  2、webapi接口的”请求成功“和”请求失败“以一定的标准规范提供给外部

    我的规范为:

    所有的成功请求返回200(response的status为200),返回的结果以json封装

    所有的失败请求返回非200,错误以json返回,错误的内容为Message的值,如{"Message":"这里是异常的内容描述"}

  3、如果为已知异常(即我们代码里写的throw异常)可简单的记录到日志,但如果是未知异常(我们不知道是哪里抛出的异常,往往也是程序的bug)则记录到特殊的日志文件里,如上篇的log/error目录下。

参考

微软webapi异常处理:https://docs.microsoft.com/zh-cn/aspnet/web-api/overview/error-handling/

 

步骤如下

自定义异常类

  此异常类即是”已知“异常,约定程序里我们自己抛出的异常都用此类,Message属性记录异常的描述信息

using System;
using System.Runtime.Serialization;

namespace webapi.Exceptions
{
    public class KnownException : Exception
    {
        public KnownException():base()
        {
        }

        public KnownException(string message) : base(message)
        {
        }

        public KnownException(string message, Exception innerException) : base(message, innerException)
        {
        }

        protected KnownException(SerializationInfo info, StreamingContext context) : base(info, context)
        {
        }
    }
}

 

创建webapi异常过滤器

  创建WebApiExceptionFilterAttribute类,代码如下

using System.Net;
using System.Net.Http;
using System.Web.Http.Filters;
using log4net;

namespace webapi.Exceptions
{
    public class WebApiExceptionFilterAttribute : ExceptionFilterAttribute
    {
        public override void OnException(HttpActionExecutedContext actionExecutedContext)
        {
            var exception = actionExecutedContext.Exception;//获取产生的异常对象
            var exceptionMessage = exception.Message;
            var logMessage = 
                $@"controller.action={actionExecutedContext.ActionContext.ControllerContext.ControllerDescriptor.ControllerName}.{actionExecutedContext.ActionContext.ActionDescriptor.ActionName}:exception="
                + exception.Message;//异常内容
            ILog log = LogManager.GetLogger(actionExecutedContext.ActionContext.ControllerContext.Controller.GetType());
            if (exception is KnownException)
            {
                log.Debug(logMessage);
            }
            else
            {
                log.Error(logMessage, exception);
            }
            actionExecutedContext.Response = actionExecutedContext.Request.CreateErrorResponse(HttpStatusCode.BadRequest, exceptionMessage);
        }

    }
}

  在webapi里使用异常过滤最简单的方法就是继承自ExceptionFilterAttribute类,并重写OnException方法并写入自己的异常处理逻辑

将异常过滤器加到webapi里

修改之前的WebApiConfig.OwinWebApiConfiguration方法,代码如下

/// <summary>
        /// 返回webapi的httpconfiguration配置
        /// 用于webapi应用于owin技术时使用
        /// </summary>
        /// <returns></returns>
        public static HttpConfiguration OwinWebApiConfiguration(HttpConfiguration config)
        {
            config.MapHttpAttributeRoutes();//开启属性路由
            config.Routes.MapHttpRoute(
                name: "DefaultApi",
                routeTemplate: "api/{controller}/{id}",
                defaults: new { id = RouteParameter.Optional }
            );
            config.Filters.Add(new WebApiExceptionFilterAttribute());
            return config;
        }

  增加的只是config.Filters.Add(new WebApiExceptionFilterAttribute());这一句

 

测试结果

创建用于测试的控制器,写两个接口分别模拟程序bug抛出的未知异常和自己抛出的已知异常

using System;
using System.Web.Http;
using webapi.Exceptions;

namespace webapi.example
{
    [RoutePrefix("api/exceptionTest")]
    public class ExceptionTestController : ApiController
    {
        /// <summary>
        /// 模拟程序bug抛出的异常
        /// </summary>
        /// <returns></returns>
        [Route("unknown"),HttpGet]
        public IHttpActionResult UnKnow()
        {
            throw new Exception("未知的异常");
        }
        /// <summary>
        /// 模拟主动抛出的业务异常
        /// </summary>
        /// <returns></returns>
        [Route("known"), HttpGet]
        public IHttpActionResult Know()
        {
            throw new KnownException("已知的异常");
        }
    }
}

  返问两个接口会得到内容为{"Message":"xxx"},status为400的respose,和我们的约定规则一样。

 

posted @ 2018-01-12 17:02  shengyu_kmust  阅读(2129)  评论(0编辑  收藏  举报