• ASP.NET WebAPI 11 参数验证


    在绑定完Action的所有参数后,WebAPI并不会马上执行该方法,而要对参数进行验证,以保证输入的合法性.

    ModelState

    在ApiController中一个ModelState属性用来获取参数验证结果.

     

    public abstract class ApiController : IHttpController, IDisposable
    
     {
    
    public ModelStateDictionary ModelState { get; } 
    
     }
    

    ApiContext的ModelState属性实际是对每个Action参数验证的结果集合.

    public class ModelStateDictionary : IDictionary<string, ModelState>, ICollection<KeyValuePair<string, ModelState>>, IEnumerable<KeyValuePair<string, ModelState>>, IEnumerable
    
     { 
    
    public int Count { get; } 
    
    public bool IsReadOnly { get; } 
    
    public bool IsValid { get; } 
    
    public ModelState this[string key] { get; set; } 
    
    public void Add(KeyValuePair<string, ModelState> item); 
    
    public void Add(string key, ModelState value); 
    
     }
    

     

    public class ModelState
    
     { 
    
    public ModelState(); 
    
    public ModelErrorCollection Errors { get; } 
    
    public ValueProviderResult Value { get; set; } 
    
    } 
    
    public class ModelError
    
    {
    
    public string ErrorMessage { get; } 
    
    public Exception Exception { get; } 
    
     }
    

    对于ModelStateDictionary,ModelState,ModelError我们可以理解成Action所有参数(所有参数的属性)的验证结果.单个参数的验证结果.单个参数属性的单个验证结果(一个参数可能有多个难结果).

    ModelStateDictionary的IsValid属性表示验证是否通过.另外 Count属性对于不同的参数绑定方式在WebAPI中可能表现不同的结果.这个后面会有具体例子.

    ValidationAttribute特性

    采用ValidationAttribute特性进行参数验证是WebAPI的默认验证方式.ValidationAttribute位于" System.ComponentModel.DataAnnotations"命名空间下,在这个命名空间下还定义了一些具体的ValidationAttribute,如图:

     

    public abstract class ValidationAttribute : Attribute
    
     {
    
    public string ErrorMessage { get; set; } 
    
    public string ErrorMessageResourceName { get; set; } 
    
    public Type ErrorMessageResourceType { get; set; } 
    
    public virtual bool RequiresValidationContext { get; } 
    
    public virtual string FormatErrorMessage(string name); 
    
    public ValidationResult GetValidationResult(object value, ValidationContext validationContext); 
    
    public virtual bool IsValid(object value); 
    
    public void Validate(object value, string name); 
    
    public void Validate(object value, ValidationContext validationContext); 
    
     }
    

    ValidationAttribute的IsValid方法用来返回验证是否通过, FormatErrorMessage方法用来返回错误信息.

    下面我就自定义一个ArrayValidatorAttribute,用来进行区间判断,即让开发者自定义一个数组,然后判断值是不是在数组内.

     

    public class ArrayValidationAttribute : ValidationAttribute
    
     { 
    
    public object[] _list; 
    
     
    
     
    
    public ArrayValidationAttribute(params object[] list) 
    
     { 
    
     _list = list; 
    
     } 
    
    public object[] List 
    
     { 
    
    get { return _list; } 
    
    set { _list = value; } 
    
     } 
    
    public override bool IsValid(object value) 
    
     { 
    
    return _list.Contains(value); 
    
     } 
    
     
    
    public override string FormatErrorMessage(string name) 
    
     { 
    
    return string.Format("{0}不在区间内.", name); 
    
     } 
    
     }
    

    CustomerValidationAttribute的使用

     

    [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter, AllowMultiple = true)] 
    
    public sealed class CustomValidationAttribute : ValidationAttribute
    
     { 
    
    public CustomValidationAttribute(Type validatorType, string method); 
    
    public string Method { get; } 
    
    public override object TypeId { get; } 
    
    public Type ValidatorType { get; } 
    
    public override string FormatErrorMessage(string name); 
    
    protected override ValidationResult IsValid(object value, ValidationContext validationContext); 
    
     }
    

    从定义中我们可以看出来CustomerValidationAttribute是不能被继承的,这是说明CustomerValidationAttribute不同于ValidaitionAttribute的使用方式.实际上CustomerValidationAttribute采用的反射的方式去进行验证.它包含了ValidationType,Method两个属性,这两个属性分别表示反射使用到的类与方法名.

    对于可以用作验证的方法要满足以下条件:

    1. 方法是公开的,静态的
    2. 方法必须要有一个或者两个参数.
    3. 如果方法只有一个参数,那么这个参数必须是未做ref,out标注的(该参数实际上是要验证的值)
    4. 如果方法有两个参数,那么第一个参数的约束用3,第二个参数必须是ValidationContext类型

    Model绑定与反序列化参数结果对比

    Model绑定方式保存了所有的验证结果,反序列化方式只保存了验证未通过的结果

    如下:

     

    public ModelStateDictionary PostFigureFromUrlForState([ModelBinder]Figure figure) 
    
     { 
    
    return ModelState; 
    
     } 
    
     
    
    public ModelStateDictionary PostFigureFromBodyForState([FromBody]Figure figure) 
    
     { 
    
    return ModelState; 
    
     } 
    

    对于Figure,将LastName,FirstName都设置成必须。

     

    public class Figure
    
     { 
    
     [Required] 
    
    public string FirstName { get; set; } 
    
     
    
     [Required]
    
    public string LastName { get; set; } 
    
    } 
    

    现在我们对两个方法传相同的数据:{FirstName:null,LastName:"Stack"}

    url:

    /api/Demo/PostFigureFromUrlForState?LastName=Stack

    /api/Demo/PostFigureFromBodyForState

    实际得到的结果分别如下:

    源码

    Github: https://github.com/BarlowDu/WebAPI (API_11)

  • 相关阅读:
    Linux| 系统管理命令
    Linux | 文件编辑命令
    Linux | 权限管理命令
    Linux | 文件管理命令
    Linux | 帮助命令
    前端性能优化之防抖、节流
    css盒子模型
    linux常用命令(持续更新)
    Vue ERROR TypeError: Cannot read property 'upgrade' of undefined
    hbuilder-x使用js-beautiful格式化代码
  • 原文地址:https://www.cnblogs.com/gangtianci/p/4951351.html
Copyright © 2020-2023  润新知