首先看一段代码
public class TestController : BaseController { public ActionResult Create(Product product) { if (string.IsNullOrWhiteSpace(product.Name)) //判断商品名称是否为空 { return Content("商品Name不可为空"); } if (string.IsNullOrWhiteSpace(product.CategoryId)) //判断商品类别Id是否为空 { return Content("商品CategoryId不可为空"); } if (Service.BaseService.Query<Entity.Category>($"select *from dbo.[Category] where Id='{product.CategoryId}'").FirstOrDefault() == null) //判断商品类别Id是否为空 { return Content("不存在的商品CategoryId"); } //todo 判断完成,写入数据库 return Content("添加成功"); }
在做后端验证时,我们经常会写到如上的代码,判断是否为空,判断是否符合格式,判断是否存在于数据库中,写多了难免使人烦躁。
好在Net框架中出现了数据标注System.ComponentModel.DataAnnotations。 这是一个很棒的组件,但是用起来并不顺手,比如他不能验证单个值,支持的属性也比较少,实际使用中很多需要自己来实现。
所以接下来我们从头实现一个C#验证的插件,
实现中。。。。。
实现中。。。。。
实现中。。。。。
实现完成。
基本配置
首先定义一个验证类让所有需要的验证继承于此
public abstract class ValidationAttribute : Attribute { public string ErrorMessage { get; set; } public string Name { get; set; } public virtual bool Verify(object o) { return false; } }
1 using Common.EntityValidation; 2 using System; 3 using System.Collections.Generic; 4 using System.Linq; 5 using System.Web; 6 7 namespace TestMvc.Models 8 { 9 public class Student 10 { 11 12 [NotNull(ErrorMessage = "Id是必须的")] //验证非空,自定义ErroMessage 13 public string Id { get; set; } 14 15 16 [LengthAttribute(Max = 10, ErrorMessage = "个人介绍的长度")] //字符长度限制 17 public string Introduce { get; set; } //个人介绍 18 19 20 [Range(Min =1,Max =120)] //数值类型大小区间限制,最小,最大 21 public int Age { get; set; } 22 23 24 [Range( Min = "1900-10-10",Max = "2100-10-10")] //字符类型的区间 25 public string Birthday { get; set; } 26 27 28 [Chinese] 29 public string Name { get; set; } //只能是中文 30 31 32 33 [In(Range = "高中生,初中生,小学生")] 34 public string StudentType { get; set; }//只能是 "高中生","初中生","小学生" 之一 35 36 37 38 39 40 41 [DbValidation(Sql = "select*from dbo.[data] where id=@ClassId")] //数据库验证,验证班级Id ClassId是否存在于数据库中 42 public string ClassId { get; set; } 43 44 45 46 [Mobile] 47 public string CellPhone { get; set; } 48 49 50 [Email] 51 52 public string Email { get; set; } 53 54 [IdCard] 55 public string IdCard { get; set; } 56 57 58 59 [InEnum(RangeType = typeof(StuState))] //只能是属于枚举中的值 ,0 或者 2或者4 60 public int StuState { get; set; } 61 } 62 63 public enum StuState 64 { 65 66 上学中 = 0, 67 肄业 = 2, 68 退学 = 4, 69 70 71 } 72 }
调用过程
using Common.EntityValidation; using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Mvc; using TestMvc.Models; namespace TestMvc.Controllers { public class HomeController : Controller { public ActionResult Create(Student student) { #region var defaulVali = EntifyValidator.Validate(student);// 验证实体,默认验证所有字段 #endregion #region var IgnoreVali = EntifyValidator.Validate(student,"ClassId");// 验证实体,跳过字段ClassId的验证 #endregion #region var r2 = EntifyValidator.ValidateQuickly(student);//快速验证,当有不通过的字段时,立即返回 #endregion #region string pwd = Request["Pwd"]; var vPwd = StrongPassWordAttribute.IsValid(pwd); //验证单个value,验证是否强密码 if (!vPwd.IsValid) { return Content(vPwd.ErrorMessage); //这不是一个强密码 } #endregion if (defaulVali.IsValid) //返回true或者false { return Content(defaulVali.ErrorMessage); } //TODO return Content(""); } } //自定义 public class CustomAttribute:ValidationAttribute { public override bool Verify(object o) { //这里写验证逻辑 return false; } } }
使用数据库验证时可以在应用程序入口初始化连接值
protected void Application_Start() { AreaRegistration.RegisterAllAreas(); FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters); RouteConfig.RegisterRoutes(RouteTable.Routes); BundleConfig.RegisterBundles(BundleTable.Bundles); DbValidationAttribute.Init("server=XXXX;database=XX;user=sa;password=1234; pooling=true;max pool size=2048;");
自定义
//自定义 public class CustomAttribute:ValidationAttribute { public override bool Verify(object o) { //这里写验证逻辑 return false; } }
验证的主要方法
using System; using System.Collections.Generic; using System.Linq; using System.Reflection; using System.Text; using System.Threading.Tasks; namespace Common.EntityValidation { public class EntifyValidator { public static ValidResult Validate(object data, params string[] ignore) //验证完所有字段 { return new EntifyValidator().Verify(false, data, ignore); } public static ValidResult ValidateQuickly(object data, params string[] ignore) //当有未通过的验证时,直接返回,停止验证 { return new EntifyValidator().Verify(true, data, ignore); } /// <summary> /// /// </summary> /// <param name="quickly">验证完所有字段Or验证到未通过的立即返回</param> /// <param name="data">需要验证的数据</param> /// <param name="ignore">忽略的字段</param> /// <returns></returns> public virtual ValidResult Verify(bool quickly, object data, params string[] ignore) { ValidResult result = new ValidResult(); List<PropertyInfo> props = data.GetType().GetProperties().Where(a => !ignore.Contains(a.Name.ToLower())).ToList(); foreach (var item in props) { var validateattrs = item.GetCustomAttributes(typeof(ValidationAttribute));// var input = item.GetValue(data); foreach (var itemattr in validateattrs) { var attr = ((ValidationAttribute)itemattr); if (attr != null) { attr.Name = item.Name; var isvalid = attr.Verify(input); if (!isvalid) { ValidResultDetail validResultDetail = new ValidResultDetail(); validResultDetail.Name = item.Name; validResultDetail.ErrorMessage = string.Format(attr.ErrorMessage, item.Name); validResultDetail.IsValid = false; result.ValidResultDetails.Add(validResultDetail); if(quickly) { return result; } } } } } return result; } } }
源码地址:https://gitee.com/unclescar/Validator
欢迎下载,讨论,联系作者 QQ 634892969