zoukankan      html  css  js  c++  java
  • .net core api 对于FromBody的参数验证

    前言

    在framework的mvc中,经常会使用 Model.StateModelState.IsValid 配合着特性进行参数验证,通过这种方式可以降低controller的复杂度,使用方便。

    常见的特性有: RequiredAttribute、RangeAttribute等...

    而在.net core api中可以看到这些特性依然被保存了下来,接下来就通过使用这些特性来看看.net core api是如何进行校验的。

    首先,在控制器中添加一个测试方法,和一个测试action

    [HttpPost]
    public Info Tets([FromBody] Info data)
    {
        return data;
    }
    
    public class Info
    {
        [Required]
        public bool Data { get; set; }
    }
    

    然后不传参数(空对象)来测试这个接口:

    <response>
    
    HTTPStatus : 400 Bad Request
    
    {
        "type": "https://tools.ietf.org/html/rfc7231#section-6.5.1",
        "title": "One or more validation errors occurred.",
        "status": 400,
        "traceId": "|8abecfa7-47340a71b12754df.",
        "errors": {
            "Data": [
                "The Data field is required."
            ]
        }
    }
    

    直接返回400,Action不用做多余的处理,这样的话对于简单的验证,我们可以直接在模型里面打标记,action只关注业务,错误码也不用特意去定义,真是一举多得。

    如何扩展?

    虽然官方已经提供了一些验证特性,但是对于一些其他简单校验,我们可能还是要自己写验证,那么如何去实现自定义的特性验证呢?

    查看RequiredAttribute定义:

    public class RequiredAttribute : ValidationAttribute
    

    1.继承ValidationAttribute,通过此特性标记当前特性是一个验证特性,在请求时会触发此类的实现

    public override bool IsValid(object value)
    {
    	if (value == null)
    	{
    		return false;
    	}
    	if (!AllowEmptyStrings)
    	{
    		string text = value as string;
    		if (text != null)
    		{
    			return text.Trim().Length != 0;
    		}
    	}
    	return true;
    }
    

    2.可以看到这里实现了IsValid方法,然后通过返回值的true or false 来表示是否验证成功

    接下来,让我们来实现一个简单的例子:传入的集合不能为空且必须有子项

    public class CollectionRequiredAttribute : ValidationAttribute
    {
        public override bool IsValid(object value)
        {
            if (value == null)
                return false;
            if (value is ICollection collection)
                if (collection.Count == 0) return false;
            return true;
        }
    }
    

    测试成功. 不符合时返回结果:

    {
        "type": "https://tools.ietf.org/html/rfc7231#section-6.5.1",
        "title": "One or more validation errors occurred.",
        "status": 400,
        "traceId": "|c04340c0-41f44630c5a43e25.",
        "errors": {
            "Arr": [
                "The field Arr is invalid."
            ]
        }
    }
    

    有的时候,我们可能会想要把错误信息显示得更明显一些,可以提供实现父类方法实现:

    public override string FormatErrorMessage(string name)
    {
        return "你想要返回的消息格式";
    }
    

    以上例子都只是一个列的验证,如果你想要类型于CompareAttribute那种多个列进行验证的,该如何实现?

    查看CompareAttribute源码:

    protected override ValidationResult IsValid(object value, ValidationContext validationContext)
    {
    	PropertyInfo runtimeProperty = validationContext.ObjectType.GetRuntimeProperty(OtherProperty);
    	if (runtimeProperty == null)
    	{
    		return new ValidationResult(System.SR.Format(System.SR.CompareAttribute_UnknownProperty, OtherProperty));
    	}
    	if (runtimeProperty.GetIndexParameters().Any())
    	{
    		throw new ArgumentException(System.SR.Format(System.SR.Common_PropertyNotFound, validationContext.ObjectType.FullName, OtherProperty));
    	}
    	object value2 = runtimeProperty.GetValue(validationContext.ObjectInstance, null);
    	if (!object.Equals(value, value2))
    	{
    		if (OtherPropertyDisplayName == null)
    		{
    			OtherPropertyDisplayName = GetDisplayNameForProperty(runtimeProperty);
    		}
    		return new ValidationResult(FormatErrorMessage(validationContext.DisplayName));
    	}
    	return null;
    }
    

    可以看到它实现了另外一个IsValid,然后通过ValidationContext获取信息进行校验。

    返回值说明 : null - 验证通过

    实现都非常简单,直接来看例子: 当另外一个字段的值为true时,当前字段不能为null

    public class MustDefinedWithPrevAttribute : ValidationAttribute
    {
    
        public string PrevCol { get; set; } // 另外一个字段的字段名,用于反射获取值
    
        public MustDefinedWithPrevAttribute(string prevCol, string errorMessage)
        {
            PrevCol = prevCol;
            ErrorMessage = errorMessage; // 指定错误信息
        }
    
        protected override ValidationResult IsValid(object value, ValidationContext validationContext)
        {
    
            var type = validationContext.ObjectInstance.GetType();
    
            if (type.GetProperty(PrevCol).GetValue(validationContext.ObjectInstance) is bool flag && flag)// 另外一个字段值为true
            {
                if(value == null)
                    return new ValidationResult(ErrorMessage); // 为空返回验证失败。
            }
            return null;
        }
    }
  • 相关阅读:
    SU Demos-02Filtering-03Sudipfilt
    SU suspecfk命令学习
    SU suplane命令学习
    (原创)c#学习笔记10--定义类成员01--成员定义01--定义字段
    (原创)c#学习笔记09--定义类08--浅度和深度复制
    (原创)c#学习笔记09--定义类07--结构类型
    (原创)c#学习笔记09--定义类06--接口和抽象类
    (原创)c#学习笔记09--定义类05--类库项目
    (原创)c#学习笔记09--定义类03--构造函数和析构函数
    (原创)c#学习笔记09--定义类02--System.Object
  • 原文地址:https://www.cnblogs.com/monster17/p/13322349.html
Copyright © 2011-2022 走看看