fancyblogs

前言

在实际应用场景中我们常常要对接口的入参进行校验, 例如分页大小是否正确, 必填参数是否已经填写等等. 

最简单的实现方式如下图, 这种在实际开发中代码过于冗余, 而且不灵活. 今天介绍一种统一参数校验的方式: System.ComponentModel.Annotations

教程 

一. 使用nuget安装 System.ComponentModel.Annotations

 二. 在请求参数上加属性

头部引用

using System.ComponentModel.DataAnnotations;

 

 原生的组件上就提供了丰富的参数校验规则, 也支持自定义规则. 

  • Required 必填, 示例:[Required(ErrorMessage = "ID是必填项")] 需要注意除了string类型的其他的值类型由于会赋予默认值, 所以加这个属性的时候值类型字段需要设置为可为空 例如 int? Id {get;set;}
  • Range 范围校验, 示例 [Range(1,99999999,ErrorMessage ="请输入正确的页码")]
  • Compare 比较 与指定的字段值进行比较  [Compare("MyOtherProperty")]两个属性必须相同值,比如我们要求用户重复输入两次邮件地址时有用
  • CreditCard 信用卡号
  • EmailAddress 是否为邮件
  • EnumDataType 校验枚举类型 示例:  [EnumDataType(typeof(EnumModels.ResponseHttpCode),ErrorMessage = "未知的类型")]
  • MaxLength 最大长度, 示例: [MaxLength(50,ErrorMessage = "昵称不能超过50个字")]
  • MinLength 最小长度 , 示例: [MinLength(2,ErrorMessage = "昵称不能少于2个字")]
  • StringLength 字符串长度不能超过给定的最大长度,也可以指定最小长度. 示例: [StringLength(50, ErrorMessage = "昵称只能介于2-50个字", MinimumLength = 2)]
  • Url url格式, 示例: [Url(ErrorMessage = "链接格式错误")]
  • RegularExpression 正则表达式 示例: [RegularExpression(@"^[1]{1}[3,4,5,6,7,8,9]{1}\d{9}$", ErrorMessage = "手机号码格式错误")]

三. 接口使用

请求参数

    public class IdHeader
    {
        /// <summary>
        /// Id
        /// </summary>
        [Required(ErrorMessage = "请填写id")]
        public string Id { get; set; }
    }

接口

        public IActionResult TestCode([FromBody]IdHeader req)
        {
            return Ok(new
            {
                req.Id
            });
        }

在.net core 3.1中 我们请求时给id不负值, 将返回以下结果 

{
  "type": "https://tools.ietf.org/html/rfc7231#section-6.5.1",
  "title": "One or more validation errors occurred.",
  "status": 400,
  "traceId": "|ae306434-48bb5a7d72259168.",
  "errors": {
    "Id": [
      "请填写id"
    ]
  }
}

一般情况我们需要返回自己定义的格式, 所以我们需要先关闭自动校验, .net core 2.x和 .net framework默认是不自动校验的, 无需关闭

在Startup.cs里的ConfigureServices 添加如下代码关闭自动校验

            //关闭参数自动校验,我们需要返回自定义的格式
            services.Configure<ApiBehaviorOptions>((o) =>
            {
                o.SuppressModelStateInvalidFilter = true;
            });

然后我们需要添加 OnActionExecuting 过滤器

添加过滤器

    public class ActionFilter : IActionFilter
    {
        /// <summary>
        /// action执行前
        /// </summary>
        /// <param name="context"></param>
        public void OnActionExecuting(ActionExecutingContext context)
        {
            //校验参数
            if (!context.ModelState.IsValid)
            {
                var errorMsg = context.ModelState.Values.SelectMany(e => e.Errors).Select(e => e.ErrorMessage).FirstOrDefault();
                context.Result = new OkObjectResult(new
                {
                    Code = 702,
                    Msg = string.IsNullOrWhiteSpace(errorMsg) ? "参数校验错误" : errorMsg,
                    Data = new {}
                });
                return;
            }
        }

        /// <summary>
        /// action执行后
        /// </summary>
        /// <param name="context"></param>
        public void OnActionExecuted(ActionExecutedContext context)
        {
        }
    }

.net core 使用过滤器, 在Startup.cs里的ConfigureServices 添加如下代码使用过滤器

            services.AddMvc(o =>
            {
                //action 过滤器
                o.Filters.Add<ActionFilter>();
            })

.net webapi 使用过滤器, 在 webapiConfig.cs 里的 Register 里添加代码

config.Filters.Add(new App_Start.ActionFilter());//action过滤器

 

最后的结果

{
  "code": 702,
  "msg": "请填写id",
  "data": {}
}

这样我们就可以自定义我们返回参数

四. 自定义参数校验

虽然官方已经提供了不少验证方法, 但是可能还不够我们使用, 例如身份证号, 行政区划代码等等. 

电话号码官方已经提供了一个,但是不适用于我们中国, 我们以校验中国手机号码为例, 来讲自定义参数校验

主要方法是: 自定义类 , 继承 ValidationAttribute, 然后复写 IsValid

    /// <summary>
    /// 是否为中国手机号码
    /// </summary>
    public class ChinaMobilPhoneAttribute : ValidationAttribute
    {
        /// <summary>
        /// 复写
        /// </summary>
        /// <param name="value"></param>
        /// <returns></returns>
        public override bool IsValid(object value)
        {
            if (!(value is string)) return false;

            var val = (string)value;
            return Regex.IsMatch(val, @"^[1]{1}[3,4,5,6,7,8,9]{1}\d{9}$");
        }
    }

然后入参校验

        /// <summary>
        /// Id  具体值请参考具体接口
        /// </summary>
        [ChinaMobilPhone(ErrorMessage = "请填写正确的手机号")]
        public string PhoneNumber { get; set; }

测试

错误结果

 

 正确结果

 

 通过以上方式我们轻松实现各种参数校验

相关文章: