当前位置 博文首页 > 手把手教你AspNetCore WebApi数据验证的实现

    手把手教你AspNetCore WebApi数据验证的实现

    作者:深度码农 时间:2021-09-07 19:14

    前言

    小明最近又遇到麻烦了,小红希望对接接口传送的数据进行验证,既然是小红要求,那小明说什么都得满足呀,这还不简单嘛。

    传统验证

    [HttpPost]
    public async Task<ActionResult<Todo>> PostTodo(Todo todo)
    {
      if (string.IsNullOrEmpty(todo.Name))
      {
        return Ok("名称不能为空");
      }
      context.Todo.Add(todo);
      await context.SaveChangesAsync();
    
      return CreatedAtAction("GetTodo", new { id = todo.Id }, todo);
    }
    
    

    小明写着写着发现这样写,很多接口相同得地方都要写,使得代码比较臃肿。

    使用模型验证

    在参数模型上打上注解

    namespace App001.Models
    {
      /// <summary>
      /// 待办事项
      /// </summary>
      public class Todo
      {
        /// <summary>
        /// ID
        /// </summary>
        public Guid Id { get; set; }
        /// <summary>
        /// 名称
        /// </summary>
        [Required(ErrorMessage = "名称不能为空")]
        public string Name { get; set; }
      }
    }
    

    Postman测试Name传值未空时,则返回:

    {
      "type": "https://tools.ietf.org/html/rfc7231#section-6.5.1",
      "title": "One or more validation errors occurred.",
      "status": 400,
      "traceId": "|df184e36-4e11844dfd38a626.",
      "errors": {
        "Name": [
          "名称不能为空"
        ]
      }
    }
    

    注意Web API 控制器具有 [ApiController] 特性,则它们不必检查ModelState.IsValid。在此情况下,如果模型状态无效,将返回包含错误详细信息的自动 HTTP 400 响应。

    内置特性

    • [CreditCard]:验证属性是否具有信用卡格式。
    • [Compare]:验证模型中的两个属性是否匹配。
    • [EmailAddress]:验证属性是否具有电子邮件格式。
    • [Phone]:验证属性是否具有电话号码格式。
    • [Range]:验证属性值是否在指定的范围内。
    • [RegularExpression]:验证属性值是否与指定的正则表达式匹配。
    • [Required]:验证字段是否不为 null。
    • [StringLength]:验证字符串属性值是否不超过指定长度限制。
    • [Url]:验证属性是否具有 URL 格式。
    • [Remote]:通过在服务器上调用操作方法来验证客户端上的输入。

    Error messages

    通过验证特性可以指定要为无效输入显示的错误消息。 例如:

    [Required(ErrorMessage = "名称不能为空")]

    使用自定义返回消息格式

    有两种方式:

    • 使用自定义过滤器
    • 使用默认模型验证,需要在控制器上面加上【ApiController】。

    使用自定义过滤器

    首先,创建ModelValidateActionFilterAttribute过滤器。

    public class ModelValidateActionFilterAttribute : ActionFilterAttribute
    {
      public override void OnActionExecuting(ActionExecutingContext context)
      {
        if (!context.ModelState.IsValid)
        {
          //获取验证失败的模型字段
          var errors = context.ModelState
            .Where(e => e.Value.Errors.Count > 0)
            .Select(e => e.Value.Errors.First().ErrorMessage)
            .ToList();
    
          var str = string.Join("|", errors);
    
          //设置返回内容
          var result = new
          {
            Code = 10000,
            Msg = "未通过数据验证。",
            FullMsg = str
          };
    
          context.Result = new BadRequestObjectResult(result);
        }
    
      }
    }
    
    

    然后,Startup.ConfigureServices将过滤器添加到控制器中并关闭默认模型验证,另外我们还添加了AddNewtonsoftJson。

    //关闭默认模型验证
    services.Configure<ApiBehaviorOptions>(opt => opt.SuppressModelStateInvalidFilter = true);
    services.AddControllers(opt =>
    {
      //添加过滤器
      opt.Filters.Add(typeof(ModelValidateActionFilterAttribute));
    }).AddNewtonsoftJson(opt =>
    {
      //json字符串大小写原样输出
      opt.SerializerSettings.ContractResolver = new DefaultContractResolver();
    });
    

    最后,我们看一下返回效果:

    {
      "Code": 10000,
      "Msg": "未通过数据验证。",
      "FullMsg": "名称不能为空。"
    }
    

    使用默认模型验证

    services.Configure<ApiBehaviorOptions>(opt =>
    {
      opt.InvalidModelStateResponseFactory = actionContext =>
      {
        //获取验证失败的模型字段 
        var errors = actionContext.ModelState
          .Where(e => e.Value.Errors.Count > 0)
          .Select(e => e.Value.Errors.First().ErrorMessage)
          .ToList();
    
        var str = string.Join("|", errors);
    
        //设置返回内容
        var result = new
        {
          Code = 10000,
          Msg = "未通过数据验证。",
          FullMsg = str
        };
    
        return new BadRequestObjectResult(result);
      };
    });
    
    

    小结

    目前为止,小明把数据验证也搞定了,是不是so easy!

    jsjbwy
    下一篇:没有了