用过asp.net mvc 的都应该知道,在实体类上添加一些特性,可以实现后端实体的数据校验,这里简单实现一下 实现原理:利用反射获取实体的每一个属性,并通过属性获取属性上标注的特
用过asp.net mvc 的都应该知道,在实体类上添加一些特性,可以实现后端实体的数据校验,这里简单实现一下
实现原理:利用反射获取实体的每一个属性,并通过属性获取属性上标注的特性,调用特性的Validate方法(此方法自定义的)来验证属性的值是否合法。
1、创建自己的校验特性基类
此类继承了Attribute,表明为一个特性,Validate方法为抽象方法,目的是给实现的子类自己定义自己的Validate方法。error为错误消息提示信息。
1 [AttributeUsage(AttributeTargets.Property,AllowMultiple = true)] 2 public abstract class BaseAttribute:Attribute 3 { 4 public virtual string error { get; set; } 5 public abstract bool Validate(object value); 6 }
2、创建特性类继承自BaseAttribute
这里只简单写3个特性,写法都一样,只是校验方法Validate中的逻辑不一样。
1 /// <summary> 2 /// 约束属性不能为空 3 /// </summary> 4 public class RequiredAttribute : BaseAttribute 5 { 6 public override string error { 7 get 8 { 9 if (base.error != null) 10 { 11 return base.error; 12 } 13 return "属性不能为空"; 14 } 15 set => base.error = value; 16 } 17 public override bool Validate(object value) 18 { 19 return !(value == null); 20 } 21 }
1 /// <summary> 2 /// 约束字符串的长度范围 3 /// </summary> 4 public class StringRangeAttribute : BaseAttribute 5 { 6 public int min { get; set; } 7 public int max { get; set; } 8 public override string error { 9 get { 10 if (base.error != null) 11 { 12 return base.error; 13 } 14 return $"字符串长度范围{this.min}-{this.max}"; 15 } 16 set => base.error = value; } 17 public override bool Validate(object value) 18 { 19 return value.ToString().Length >= this.min && value.ToString().Length <= this.max; 20 } 21 }
1 /// <summary> 2 /// 约束符合正则表达式 3 /// </summary> 4 public class RegexAttribute : BaseAttribute 5 { 6 public string regexText; 7 public override bool Validate(object value) 8 { 9 var regex = new Regex(regexText); 10 return regex.Match(value.ToString()).Success; 11 } 12 }
3、给实体类扩展一个方法,用来验证实体类实例属性值是否合法
此方式的扩展方法会污染其他非实体类,不是太推荐用太多此种扩展写法,其实这里不写成扩展方法也没什么问题。
此扩展方法会验证实例中的所有属性,并将所有不通过验证的属性的提示信息以字符串的形式返回,所有都验证通过则返回空串。
1 public static string Validate<T>(this T t) 2 { 3 Type type = t.GetType(); 4 5 //获取所有属性 6 PropertyInfo[] propertyInfos = type.GetProperties(BindingFlags.Instance|BindingFlags.Public|BindingFlags.NonPublic); 7 List<string> errorList = new List<string>(); 8 foreach (PropertyInfo propertyInfo in propertyInfos) 9 { 10 if(propertyInfo.IsDefined(typeof(BaseAttribute)))//如果属性上有定义该属性,此步没有构造出实例 11 { 12 foreach (BaseAttribute attribute in propertyInfo.GetCustomAttributes(typeof(BaseAttribute))) 13 { 14 if (!attribute.Validate(propertyInfo.GetValue(t, null))) 15 { 16 errorList.Add( $"[{propertyInfo.Name}]" + attribute.error); 17 } 18 } 19 20 } 21 } 22 return string.Join(",", errorList); 23 }
4、定义一个实体类,并测试(控制台程序)。
假设有Student.cs ,在其id属性中添加Required特性,name属性上添加StringRange和Regex特性。
1 public class Student 2 { 3 [Required(error = "id 不能为空!")] 4 public int? id { get; set; } 5 [Regex(regexText = "^a.*a$",error = "属性不合格规则")] 6 [StringRange(min =5,max =10)] 7 public string name { get; set; } 8 }
1 static void Main(string[] args) 2 { 3 Student student = new Student() 4 { 5 id = null, 6 name = "ajiudsagasgasgaxb" 7 }; 8 string errorStr = student.Validate(); 9 Console.WriteLine(errorStr); 10 Console.ReadKey(); 11 }
测试结果
此代码纯属自己理解的原理性还原,代码可能有多处写的不严谨。