WebAPI 统一处理(返回值、参数验证、异常)

现在 Web 开发比较流行前后端分离,在写 API 的过程中有很多地方需要统一处理

利用AOP可以对业务逻辑各个部分进行隔离,从而使业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高开发效率。

Filter是延续ASP.NET MVC的产物,同样保留了五种的Filter,分别是Authorization Filter、Resource Filter、Action Filter、Exception Filter及Result Filter。.
通过不同的Filter可以有效处理封包进出的统一处理

下面看下实际的应用

参数验证

此处所说的参数验证指的是实体类型的参数验证,通过在实体的属性上添加特性的方式来实现。

public override void OnActionExecuting(ActionExecutingContext context)
        {
            //模型验证
            if (!context.ModelState.IsValid)
            {
                throw new CustomException(context.ModelState.Values.First(p => p.Errors.Count > 0).Errors[0].ErrorMessage, ReturnCode.E1000002);
            }
            base.OnActionExecuting(context);
        }

返回值

返回值的统一处理需要下面几个步骤:

  • 创建统一返回结果的实体类,所有的接口方法都返回固定格式,方便前端统一处理

  • 创建过滤器,过滤器用来拦截请求,包装结果,统一输出

  • Startup 类中进行配置注册

/// <summary>
        /// 处理正常返回的结果对象
        /// </summary>
        /// <param name="context"></param>
        public override void OnActionExecuted(ActionExecutedContext context)
        {
            if (context.Result != null)
            {
                var serializerSettings = new JsonSerializerSettings
                {
                    DateTimeZoneHandling = DateTimeZoneHandling.Local,
                    DateFormatString = "yyyy-MM-ddTHH:mm:ss.fffzz:00",
                    //设置缩进
                    Formatting = Formatting.Indented,
                    //设置json格式为驼峰式
                    ContractResolver = new CamelCasePropertyNamesContractResolver()
                };

                var result = context.Result as ObjectResult;
                JsonResult newresult;
                if (context.Result is ObjectResult)
                {
                    newresult = new JsonResult(new ReturnData { Message = "操作成功!", Code = ReturnCode.E10000, Data = result.Value }, serializerSettings);
                }
                else if (context.Result is EmptyResult)
                {
                    newresult = new JsonResult(new ReturnData { Message = "操作成功!", Code = ReturnCode.E10000 }, serializerSettings);
                }
                else
                {
                    throw new Exception($"未经处理的Result类型:{ context.Result.GetType().Name}");
                }
                context.Result = newresult;
            }
            base.OnActionExecuted(context);
        }
    }

 异常处理

异常处理和参数验证的方式基本相同

// <summary>
    /// api异常统一处理过滤器
    /// </summary>
    public class ApiExceptionFilterAttribute : ExceptionFilterAttribute
    {
        public override void OnException(ExceptionContext context)
        {
            context.Result = BuildExceptionResult(context.Exception);
            base.OnException(context);
        }

        /// <summary>
        /// 包装处理异常格式
        /// </summary>
        /// <param name="ex"></param>
        /// <returns></returns>
        private JsonResult BuildExceptionResult(Exception ex)
        {
            var returnData = new ReturnData();
            var exresult = ex as CustomException;
            var WriteLog = true;
            if (exresult != null)
            {
                //异常为自定义的异常
                returnData.Code = exresult.ErrorCode;
                returnData.Message = exresult.Message;
                WriteLog = exresult.WriteLog;
            }
            else
            {
                //异常为未知异常
                returnData.Code = ReturnCode.E1000001;
                returnData.Message = ex.Message;
            }

            //TODO 日志

            var serializerSettings = new JsonSerializerSettings
            {
                DateTimeZoneHandling = DateTimeZoneHandling.Local,
                DateFormatString = "yyyy-MM-ddTHH:mm:ss.fffzz:00",
                //设置缩进
                Formatting = Formatting.Indented,
                //设置json格式为驼峰式
                ContractResolver = new CamelCasePropertyNamesContractResolver()
            };

            return new JsonResult(returnData, serializerSettings);
        }
    }