基于.NET的FluentValidation数据验证实现
学习地址:官方文档,更多更详细的内容可以看官方文档。
FluentValidation是一个基于.NET开发的验证框架,开源免费,而且优雅,支持链式操作,易于理解,功能完善,还是可与MVC5、WebApi2和ASP.NETCORE深度集成,组件内提供十几种常用验证器,可扩展性好,支持自定义验证器,支持本地化多语言。
要使用验证框架,需要在项目中添加对FluentValidation.dll的引用,支持netstandard2.0库和.NET4.5平台,支持.NETCore平台,最简单的方法是使用NuGet包管理器引用组件。我这里安装的是9.2.0版本。
Install-PackageFluentValidation
若要在ASP.NETCore中使用FluentValidation扩展,可引用以下包:
Install-PackageFluentValidation.AspNetCore
若要在ASP.NETMVC5或WebApi2项目集成,可以使用分别使用FluentValidation.Mvc5和FluentValidation.WebApi程序包。
Install-PackageFluentValidation.Mvc5 Install-PackageFluentValidation.WebApi
创建第一个验证程序
若要为特定对象定义一组验证规则,您需要创建一个从AbstractValidator
publicclassCustomer{ publicintId{get;set;} publicstringSurname{get;set;} publicstringForename{get;set;} publicdecimalDiscount{get;set;} publicstringAddress{get;set;} }
接下来自定义继承于AbstractValidator泛型类的验证器,然后在构造函数中使用LINQ表达式编写RuleFor验证规则,使验证在。
usingFluentValidation; usingNetCoreBasicLearning.Entity; namespaceNetCoreBasicLearning { publicclassCustomerValidator:AbstractValidator{ publicCustomerValidator() { RuleFor(customer=>customer.Surname).NotNull(); } } }
若要执行验证程序,我们通过定义好的CustomerValidator验证器传入实体类Customer即可。
该验证方法返回一个ValidationResult对象,表示验证结果,ValidationResult包含两个属性:IsValid属性是布尔值,它表示验证是否成功,Errors属性包含相关验证失败的详细信息。
publicIActionResultIndex(stringid) { Customercustomer=newCustomer(); CustomerValidatorvalidationRules=newCustomerValidator(); ValidationResultvalidationResult=validationRules.Validate(customer); if(!validationResult.IsValid) { varstr=newStringBuilder(); foreach(vartinvalidationResult.Errors) { str.AppendLine($"属性:{t.PropertyName},错误信息:{t.ErrorMessage}"); } returnContent(str.ToString()); } returnView(); }
链接规则写法
您可以将对象的同一属性用多个验证程序链在一起,以下代码将验证Surname属性不为Null的同时且不等于foo字符串。
usingFluentValidation; usingNetCoreBasicLearning.Entity; namespaceNetCoreBasicLearning { publicclassCustomerValidator:AbstractValidator{ publicCustomerValidator() { RuleFor(customer=>customer.Surname).NotNull().NotEqual("foo"); } } }
引发异常
如果验证失败,不想返回ValidationResult对象,而是想直接抛出异常,可通过调用验证器的ValidateAndThrow进行验证。
如果验证失败,将引发一个ValidationException类型的异常,这个异常可以被上层程序捕获,并从异常中找到详细错误信息。
Customercustomer=newCustomer(); CustomerValidatorvalidationRules=newCustomerValidator(); validationRules.ValidateAndThrow(customer);
集合
当针对一个集合进行验证时,只需要定义集合项类型的规则即可,以下规则将对集合中的每个元素运行NotNull检查。
publicclassCustomer { publicListOtherAddress{get;set;} } publicclassCustomerValidator:AbstractValidator { publicCustomerValidator() { RuleForEach(customer=>customer.OtherAddress).NotEmpty(); } }
如果要对list进行进行非空判断可以如下:
publicclassCustomerValidator:AbstractValidator{ publicCustomerValidator() { RuleFor(customer=>customer.OtherAddress).NotEmpty(); } }
复杂属性
验证程序可以用于复杂属性,假设您有两个类:客户和地址
publicclassCustomer { publicAdressAddress{get;set;} } publicclassAdress { publicstringCity{get;set;} publicstringProvince{get;set;} }
然后定义一个基于地址的AddressValidator验证器件:
publicclassAdressValidator:AbstractValidator{ publicAdressValidator() { RuleFor(t=>t.City).NotEmpty(); RuleFor(t=>t.Province).NotEmpty(); } }
然后定义一个基于客户的CustomerValidator验证器件,对地址验证时使用地址验证器。
publicclassCustomerValidator:AbstractValidator{ publicCustomerValidator() { RuleFor(t=>t.Address).SetValidator(newAdressValidator()); } }
如果不想要创建另一个验证器可以直接内联定义子规则:
RuleFor(t=>t.Address.City).NotEmpty();
另外,还可以在集合属性上使用验证程序,假设客户对象包含地址集合属性:
publicclassCustomer { publicListAddress{get;set;} }
此验证程序可在CustomerValidator中通过SetCollectionValidator(在8.0版本以前)方法使用,在8.0版本以及之后被弃用需要使用RuleForEach来验证:
publicclassCustomerValidator:AbstractValidator{ publicCustomerValidator() { RuleForEach(t=>t.Address).SetValidator(newAdressValidator()); //RuleFor(x=>x.Address).SetCollectionValidator(newAdressValidator());在8.0版本及以后弃用 } }
在编写验证规则时,可以通过Where关键字排除或者筛选不需要验证的对象。
publicclassCustomerValidator:AbstractValidator{ publicCustomerValidator() { RuleForEach(t=>t.Address).Where(t=>!string.IsNullOrEmpty(t.City)).SetValidator(newAdressValidator()); //RuleFor(x=>x.Address).SetCollectionValidator(newAdressValidator()).Where(t=>!string.IsNullOrEmpty(t.City));在8.0版本及以后弃用 } }
从FluentValidation8.5开始,您还可以使用以下ChildRules方法在线定义子集合元素的规则,从而不用再定义另一个验证器:
RuleForEach(t=>t.Address).ChildRules(adderss=>{ adderss.RuleFor(t=>t.City).NotEmpty(); adderss.RuleFor(t=>t.Province).NotEmpty(); }).NotEmpty();
支持规则集
规则集允许您将验证规则分组在一起,这些规则可以作为一个组一起执行,而忽略其他规则:
我们可以把“姓”和“名”统一加在一个姓名规则集中。
publicclassCustomerValidator:AbstractValidator{ publicCustomerValidator() { RuleSet("Name",()=> { RuleFor(t=>t.Surname).NotEmpty(); RuleFor(t=>t.Forename).NotEmpty(); }); } }
规则集通过一般的Validate方法是不会执行验证的,需要用如下方法进行单独的验证,这将复杂的验证器定义分解为较小的部分进行验证,IncludeRuleSets中可以传入多个规则集名称来执行多个规则集的验证:
Customercustomer=newCustomer(); CustomerValidatorvalidationRules=newCustomerValidator(); ValidationResultvalidationResult=validationRules.Validate(customer,options=>options.IncludeRuleSets("Name"));
还可以通过IncludeRulesNotInRuleSet方法或使用特殊名称“默认”(不区分大小写)来执行验证所有不属于规则集的规则:
ValidationResultvalidationResult=validationRules.Validate(customer,options=>{options.IncludeRulesNotInRuleSet();options.IncludeRuleSets("Name");});
可以通过调用强制执行所有规则,而不管它们是否在规则集中IncludeAllRuleSets(这等效于usingIncludeRuleSets("*"))。
同个类型的多个验证器
一个验证器可以包含多个其他的验证器,只要这些验证器都是验证统一类型的即可。这样就可以拆分验证器,通过不同的需求组合在一起:
publicclassCustomerValidator:AbstractValidator{ publicCustomerValidator() { Include(newCustomerSurnameValidator()); Include(newCustomerForenameValidator()); } } publicclassCustomerSurnameValidator:AbstractValidator { publicCustomerSurnameValidator() { RuleFor(t=>t.Surname).NotEmpty(); } } publicclassCustomerForenameValidator:AbstractValidator { publicCustomerForenameValidator() { RuleFor(t=>t.Forename).NotEmpty(); } }
继承验证
从FluentValidation9.2开始,如果您的对象属性作为其他类的基类或接口,则可以为各个子类/实现器设置特定的子验证器,来验证这个属性。我们的类设置如下:
publicclassStore { publicPeoplePeoples{get;set;} } publicclassCustomer:People { publicstringAddress{get;set;} } publicclassPeople { publicstringName{get;set;} }
验证器如下:
publicclassStoreValidator:AbstractValidator{ publicStoreValidator() { RuleFor(t=>t.Peoples).NotNull().SetInheritanceValidator(t=> { t.Add (newCustomerValidator()); }); } } publicclassCustomerValidator:AbstractValidator { publicCustomerValidator() { RuleFor(t=>t.Address).NotEmpty(); } }
覆盖消息
通过在验证程序上调用WithMessage方法,可以覆盖验证程序的默认验证错误消息。错误提示中,可以通过{PropertyName}占位符替换属性名。除了{PropertyName}占位符,框架还内置了:{PropertyValue}、{ComparisonValue}、{MinLength}、{MaxLength}和{TotalLength}占位符,关于更多内置占位符,可以参阅官方文档。
RuleFor(customer=>customer.Surname).NotNull().WithMessage("Pleaseensureyouhaveenteredyour{PropertyName}");
验证程序支持通过WithName方法来指定属性别名,以下代码输出姓名不能为空。请注意,这仅替换错误消息中属性的名称。当您检查上的Errors集合时ValidationResult,此错误仍将与一个名为的属性相关联Surname。如果要完全重命名该属性,则可以使用OverridePropertyName方法。
RuleFor(customer=>customer.Surname).NotNull().WithName("姓名");
条件
When和Unless方法可用于执行满足指定条件情况下的规则,例如只当Surname属性不为空的时候,才执行前面的Name属性的非空验证(Unless和When是相反的所以这边只讲When就行啦!):
RuleFor(t=>t.Name).NotEmpty().When(t=>!string.IsNullOrEmpty(t.Surname));
如果需要指定多个规则在相同的条件下才执行验证,可以直接用顶级的When方法:
publicclassCustomerValidator:AbstractValidator{ publicCustomerValidator() { When(t=>!string.IsNullOrEmpty(t.Surname),()=>{RuleFor(t=>t.Name).NotEmpty();//其他验证规则}); } }
通过在When方法后面追加一个Otherwise方法,可以执行不满足When中调整的验证规则,如下:
When(t=>!string.IsNullOrEmpty(t.Surname),()=>{RuleFor(t=>t.Name).NotEmpty();}).Otherwise(()=>{RuleFor(t=>t.Name).Equal("哈哈");});
默认情况下,FluentValidation会将条件应用于对的同一调用中的所有先前的验证器RuleFor。比如下面这条代码,如果Surname不为空,则对Name进行非空和是否等于11的验证,否则不会对Name执行这两个验证:
RuleFor(t=>t.Name).NotEmpty().Equal("11").When(t=>!string.IsNullOrEmpty(t.Surname));
如果仅希望将条件应用于紧接条件之前的验证器,则必须明确参数ApplyConditionTo.CurrentValidator,如下,只有Equal受到When方法的限制,NotEmpty不管When是否为true都会执行的。
RuleFor(t=>t.Name).NotEmpty().Equal("11").When(t=>!string.IsNullOrEmpty(t.Surname),ApplyConditionTo.CurrentValidator);
设置级联模式
有两种联级模式:
- Continue(默认设置)-始终调用规则定义中的所有验证器
- Stop-验证程序失败后立即停止执行规则(仅在FluentValidation9.1和更高版本中可用,在旧版本中,您可以改用StopOnFirstFailure)
通过如下代码,可以在NotNull验证不通过的时候就停止验证,不再执行NotEqual的验证。默认是验证不通过,也继续验证下去。
RuleFor(x=>x.Surname).Cascade(CascadeMode.Stop).NotNull().NotEqual("foo");
设置严重性级别
默认情况下,如果这些规则失败,则严重性为“错误”。可以通过调用WithSeverity方法来更改。例如,如果我们希望将缺少的姓氏标识为警告而不是错误,则可以将上面的行修改为:
RuleFor(x=>x.Surname).NotNull().WithSeverity(Severity.Warning);
在9.0及更高版本中,可以改用回调,这也使您可以访问正在验证的项目:
RuleFor(person=>person.Surname).NotNull().WithSeverity(person=>Severity.Warning);
定制验证器
之前我们都是使用内置的验证器,如Equal、NotNull等等。
我们也可以自己定义验证器,实现自定义验证器的最简单方法是使用Must方法,该方法在内部使用PredicateValidator。假设我们有以下课程:
publicclassPerson{ publicIListPets{get;set;}=newList (); }
为了确保我们的list属性包含少于10个项目,我们可以这样做:
publicclassPersonValidator:AbstractValidator{ publicPersonValidator(){ RuleFor(x=>x.Pets).Must(list=>list.Count<10) .WithMessage("Thelistmustcontainfewerthan10items"); } }
为了使我们自己定义的验证器可以重用,我们可以将其包装为可作用于任何List
publicstaticclassMyCustomValidators{ publicstaticIRuleBuilderOptions>ListMustContainFewerThan (thisIRuleBuilder >ruleBuilder,intnum){ returnruleBuilder.Must(list=>list.Count 在这里,我们在上创建一个扩展方法IRuleBuilder
,并使用通用类型约束来确保此方法仅出现在对列表类型的智能感知中。在方法内部,我们以与以前相同的方式调用Must方法,但是这次我们在传入的RuleBuilder实例上调用它。我们还将要比较的项目数作为参数传递。现在,我们的规则定义可以重写为使用以下方法: RuleFor(x=>x.Pets).ListMustContainFewerThan(10);我们还可以通过Custom方法来自定义验证器,它相比于Must的好处是允许针对同一规则返回多个错误(通过context.AddFailure多次调用该方法)。
publicclassPersonValidator:AbstractValidator{ publicPersonValidator(){ RuleFor(x=>x.Pets).Custom((list,context)=>{ if(list.Count>10){ context.AddFailure("Thelistmustcontain10itemsorfewer"); } }); } } 到此这篇关于基于.NET的FluentValidation数据验证实现的文章就介绍到这了,更多相关.NETFluentValidation数据验证内容请搜索毛票票以前的文章或继续浏览下面的相关文章希望大家以后多多支持毛票票!