基于 .NET 的 FluentValidation 数据验证
学习地址:官方文档,更多更详细的内容可以看官方文档。
FluentValidation 是一个基于 .NET 开发的验证框架,开源免费,而且优雅,支持链式操作,易于理解,功能完善,还是可与 MVC5、WebApi2 和 ASP.NET CORE 深度集成,组件内提供十几种常用验证器,可扩展性好,支持自定义验证器,支持本地化多语言。
要使用验证框架, 需要在项目中添加对 FluentValidation.dll 的引用,支持 netstandard2.0 库和 .NET4.5 平台,支持.NET Core 平台,最简单的方法是使用 NuGet 包管理器引用组件。我这里安装的是9.2.0版本。
Install-Package FluentValidation
若要在 ASP.NET Core 中使用 FluentValidation 扩展,可引用以下包:
Install-Package FluentValidation.AspNetCore
若要在 ASP.NET MVC 5 或 WebApi 2 项目集成, 可以使用分别使用 FluentValidation.Mvc5 和 FluentValidation.WebApi 程序包。
Install-Package FluentValidation.Mvc5
Install-Package FluentValidation.WebApi
创建第一个验证程序
若要为特定对象定义一组验证规则, 您需要创建一个从 AbstractValidator<T> 继承的类, 其中泛型T参数是要验证的类的类型。假设您有一个客户类别:
public class Customer {
public int Id { get; set; }
public string Surname { get; set; }
public string Forename { get; set; }
public decimal Discount { get; set; }
public string Address { get; set; }
}
接下来自定义继承于 AbstractValidator 泛型类的验证器,然后在构造函数中使用 LINQ 表达式编写 RuleFor 验证规则,使验证在。
using FluentValidation;
using NetCoreBasicLearning.Entity; namespace NetCoreBasicLearning
{
public class CustomerValidator : AbstractValidator<Customer>
{
public CustomerValidator()
{
RuleFor(customer => customer.Surname).NotNull();
}
}
}
若要执行验证程序,我们通过定义好的 CustomerValidator 验证器传入实体类 Customer 即可。
该验证方法返回一个 ValidationResult 对象,表示验证结果,ValidationResult 包含两个属性:IsValid属性是布尔值, 它表示验证是否成功,Errors属性包含相关验证失败的详细信息。
public IActionResult Index(string id)
{
Customer customer = new Customer();
CustomerValidator validationRules = new CustomerValidator();
ValidationResult validationResult = validationRules.Validate(customer); if (!validationResult.IsValid)
{
var str = new StringBuilder();
foreach(var t in validationResult.Errors)
{
str.AppendLine($"属性:{t.PropertyName},错误信息:{t.ErrorMessage}");
}
return Content(str.ToString());
}
return View();
}
链接规则写法
您可以将对象的同一属性用多个验证程序链在一起,以下代码将验证 Surname 属性不为 Null 的同时且不等于foo字符串。
using FluentValidation;
using NetCoreBasicLearning.Entity; namespace NetCoreBasicLearning
{
public class CustomerValidator : AbstractValidator<Customer>
{
public CustomerValidator()
{
RuleFor(customer => customer.Surname).NotNull().NotEqual("foo");
}
}
}
引发异常
如果验证失败, 不想返回 ValidationResult 对象,而是想直接抛出异常,可通过调用验证器的 ValidateAndThrow 进行验证。
如果验证失败,将引发一个 ValidationException 类型的异常,这个异常可以被上层程序捕获,并从异常中找到详细错误信息。
Customer customer = new Customer();
CustomerValidator validationRules = new CustomerValidator();
validationRules.ValidateAndThrow(customer);
集合
当针对一个集合进行验证时,只需要定义集合项类型的规则即可,以下规则将对集合中的每个元素运行 NotNull 检查。
public class Customer
{
public List<string> OtherAddress { get; set; }
}
public class CustomerValidator : AbstractValidator<Customer>
{
public CustomerValidator()
{
RuleForEach(customer => customer.OtherAddress).NotEmpty();
}
}
如果要对list进行进行非空判断可以如下:
public class CustomerValidator : AbstractValidator<Customer>
{
public CustomerValidator()
{
RuleFor(customer => customer.OtherAddress).NotEmpty();
}
}
复杂属性
验证程序可以用于复杂属性,假设您有两个类:客户和地址
public class Customer
{
public Adress Address { get; set; }
}
public class Adress
{
public string City { get; set; }
public string Province { get; set; }
}
然后定义一个基于地址的 AddressValidator 验证器件:
public class AdressValidator : AbstractValidator<Adress>
{
public AdressValidator()
{
RuleFor(t => t.City).NotEmpty();
RuleFor(t => t.Province).NotEmpty();
}
}
然后定义一个基于客户的 CustomerValidator 验证器件,对地址验证时使用地址验证器。
public class CustomerValidator : AbstractValidator<Customer>
{
public CustomerValidator()
{
RuleFor(t => t.Address).SetValidator(new AdressValidator());
}
}
如果不想要创建另一个验证器可以直接内联定义子规则:
RuleFor(t => t.Address.City).NotEmpty();
另外,还可以在集合属性上使用验证程序,假设客户对象包含地址集合属性:
public class Customer
{
public List<Adress> Address { get; set; }
}
此验证程序可在 CustomerValidator 中通过 SetCollectionValidator(在8.0版本以前) 方法使用,在8.0版本以及之后被弃用需要使用RuleForEach来验证:
public class CustomerValidator : AbstractValidator<Customer>
{
public CustomerValidator()
{
RuleForEach(t => t.Address).SetValidator(new AdressValidator());
//RuleFor(x => x.Address).SetCollectionValidator(new AdressValidator());在8.0版本及以后弃用
}
}
在编写验证规则时,可以通过 Where 关键字排除或者筛选不需要验证的对象。
public class CustomerValidator : AbstractValidator<Customer>
{
public CustomerValidator()
{
RuleForEach(t => t.Address).Where(t => !string.IsNullOrEmpty(t.City)).SetValidator(new AdressValidator());
//RuleFor(x => x.Address).SetCollectionValidator(new AdressValidator()).Where(t => !string.IsNullOrEmpty(t.City));在8.0版本及以后弃用
}
}
从FluentValidation 8.5开始,您还可以使用以下ChildRules
方法在线定义子集合元素的规则,从而不用再定义另一个验证器:
RuleForEach(t => t.Address).ChildRules(adderss => {
adderss.RuleFor(t => t.City).NotEmpty();
adderss.RuleFor(t => t.Province).NotEmpty();
}).NotEmpty();
支持规则集
规则集允许您将验证规则分组在一起,这些规则可以作为一个组一起执行,而忽略其他规则:
我们可以把“姓”和“名”统一加在一个姓名规则集中。
public class CustomerValidator : AbstractValidator<Customer>
{
public CustomerValidator()
{
RuleSet("Name", () =>
{
RuleFor(t => t.Surname).NotEmpty();
RuleFor(t => t.Forename).NotEmpty();
});
}
}
规则集通过一般的 Validate 方法是不会执行验证的,需要用如下方法进行单独的验证,这将复杂的验证器定义分解为较小的部分进行验证,IncludeRuleSets 中可以传入多个规则集名称来执行多个规则集的验证:
Customer customer = new Customer();
CustomerValidator validationRules = new CustomerValidator();
ValidationResult validationResult = validationRules.Validate(customer, options => options.IncludeRuleSets("Name"));
还可以通过 IncludeRulesNotInRuleSet 方法或使用特殊名称“默认”(不区分大小写)来执行验证所有不属于规则集的规则:
ValidationResult validationResult = validationRules.Validate(customer, options =>{ options.IncludeRulesNotInRuleSet(); options.IncludeRuleSets("Name"); } );
可以通过调用强制执行所有规则,而不管它们是否在规则集中 IncludeAllRuleSets(这等效于using IncludeRuleSets("*")
)。
同个类型的多个验证器
一个验证器可以包含多个其他的验证器,只要这些验证器都是验证统一类型的即可。这样就可以拆分验证器,通过不同的需求组合在一起:
public class CustomerValidator : AbstractValidator<Customer>
{
public CustomerValidator()
{
Include(new CustomerSurnameValidator());
Include(new CustomerForenameValidator());
}
}
public class CustomerSurnameValidator : AbstractValidator<Customer>
{
public CustomerSurnameValidator()
{
RuleFor(t => t.Surname).NotEmpty();
}
}
public class CustomerForenameValidator : AbstractValidator<Customer>
{
public CustomerForenameValidator()
{
RuleFor(t => t.Forename).NotEmpty();
}
}
继承验证
从FluentValidation 9.2开始,如果您的对象属性作为其他类的基类或接口,则可以为各个子类/实现器设置特定的子验证器,来验证这个属性。我们的类设置如下:
public class Store
{
public People Peoples { get; set; }
}
public class Customer : People
{
public string Address { get; set; }
}
public class People
{
public string Name { get; set; }
}
验证器如下:
public class StoreValidator : AbstractValidator<Store>
{
public StoreValidator()
{
RuleFor(t => t.Peoples).NotNull().SetInheritanceValidator(t =>
{
t.Add<Customer>(new CustomerValidator());
});
}
}
public class CustomerValidator : AbstractValidator<Customer>
{
public CustomerValidator()
{
RuleFor(t => t.Address).NotEmpty();
}
}
覆盖消息
通过在验证程序上调用 WithMessage 方法, 可以覆盖验证程序的默认验证错误消息。错误提示中,可以通过 {PropertyName} 占位符替换属性名。除了 {PropertyName} 占位符,框架还内置了:{PropertyValue}、{ComparisonValue}、{MinLength}、{MaxLength}和{TotalLength} 占位符,关于更多内置占位符,可以参阅官方文档。
RuleFor(customer => customer.Surname).NotNull().WithMessage("Please ensure you have entered your {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方法:
public class CustomerValidator : AbstractValidator<Customer>
{
public CustomerValidator()
{
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
-验证程序失败后立即停止执行规则(仅在FluentValidation 9.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。假设我们有以下课程:
public class Person {
public IList<Pet> Pets {get;set;} = new List<Pet>();
}
为了确保我们的list属性包含少于10个项目,我们可以这样做:
public class PersonValidator : AbstractValidator<Person> {
public PersonValidator() {
RuleFor(x => x.Pets).Must(list => list.Count < 10)
.WithMessage("The list must contain fewer than 10 items");
}
}
为了使我们自己定义的验证器可以重用,我们可以将其包装为可作用于任何List<T>
类型的扩展方法。
public static class MyCustomValidators {
public static IRuleBuilderOptions<T, IList<TElement>> ListMustContainFewerThan<T, TElement>(this IRuleBuilder<T, IList<TElement>> ruleBuilder, int num) {
return ruleBuilder.Must(list => list.Count < num).WithMessage("The list contains too many items");
}
}
在这里,我们在上创建一个扩展方法IRuleBuilder<T,TProperty>
,并使用通用类型约束来确保此方法仅出现在对列表类型的智能感知中。在方法内部,我们以与以前相同的方式调用Must方法,但是这次我们在传入的RuleBuilder实例上调用它。我们还将要比较的项目数作为参数传递。现在,我们的规则定义可以重写为使用以下方法:
RuleFor(x => x.Pets).ListMustContainFewerThan(10);
我们还可以通过Custom方法来自定义验证器,它相比于Must的好处是允许针对同一规则返回多个错误(通过context.AddFailure
多次调用该方法)。
public class PersonValidator : AbstractValidator<Person> {
public PersonValidator() {
RuleFor(x => x.Pets).Custom((list, context) => {
if(list.Count > 10) {
context.AddFailure("The list must contain 10 items or fewer");
}
});
}
}
基于 .NET 的 FluentValidation 数据验证的更多相关文章
- 【转】基于jquery,bootstrap数据验证插件bootstrapValidator 教程
bootstrap:能够增加兼容性的强大框架. 因为项目需要数据验证,看bootstrapValidator 还不错,就上手一直,完美兼容,话不多说. 需要引用css: bootstrap.min.c ...
- 基于jquery,bootstrap数据验证插件bootstrapValidator 教程
bootstrap:能够增加兼容性的强大框架. 因为项目需要数据验证,看bootstrapValidator 还不错,就上手一直,完美兼容,话不多说. 需要引用css: bootstrap.min.c ...
- 基于jquery,bootstrap数据验证插件bootstrapValidator
bootstrap:能够增加兼容性的强大框架. 因为项目需要数据验证,看bootstrapValidator 还不错,就上手一直,完美兼容,话不多说. 需要引用css: bootstrap.min.c ...
- asp.net mvc3 数据验证(四)—Remote验证的一个注意事项
原文:asp.net mvc3 数据验证(四)-Remote验证的一个注意事项 前几篇把asp.net mvc3 中基于Model的主要数据验证的方法都已经讲完了,本节纯粹只是讲一个我 ...
- ASP.NET Core 6.0 基于模型验证的数据验证
1 前言 在程序中,需要进行数据验证的场景经常存在,且数据验证是有必要的.前端进行数据验证,主要是为了减少服务器请求压力,和提高用户体验:后端进行数据验证,主要是为了保证数据的正确性,保证系统的健壮性 ...
- WebApi基于Token和签名的验证
最近一段时间在学习WebApi,涉及到验证部分的一些知识觉得自己并不是太懂,所以来博客园看了几篇博文,发现一篇讲的特别好的,读了几遍茅塞顿开(都闪开,我要装逼了),刚开始读有些地方不理解,所以想了很久 ...
- 基于Hadoop的密码安全级别验证
学习Hadoop有一段时间了,期间写过很多Demo,都是针对单个知识点做的验证,今天写个完整的应用程序——基于Hadoop的密码安全级别验证. 在很多网站上注册用户时输入密码都会在下方提示密码安全级别 ...
- asp.net中使用基于角色role的Forms验证
http://www.cnblogs.com/yao/archive/2006/06/24/434783.html asp.net中使用基于角色role的Forms验证,大致经过几下四步:1.配置系统 ...
- Silverlight实例教程 – Datagrid,Dataform数据验证和ValidationSummary(转载)
Silverlight 4 Validation验证实例系列 Silverlight实例教程 - Validation数据验证开篇 Silverlight实例教程 - Validation数据验证基础 ...
随机推荐
- LiteOS-任务篇
目录 前言 链接 参考 笔录草稿 基本概念 任务相关概念 LiteOS 任务运作机制 内核初始化 创建任务 创建任务有两种方案 任务相关函数 任务开发流程 创建创建任务 部分源码 例子 创建任务的任务 ...
- 八、多线程爬虫(先占个位置,等整理好线程,进程,协程,异步IO在来写)
计算机的核心是CPU,CPU承担了所有的计算任务. 一个CPU核心,一次只能执行一个任务: 多个CPU核心同时可以执行多个任务. 一个CPU一次只能执行一个进程,其他进程处于非运行状态. 进程里包含的 ...
- idea 2020.1 Mybatis log plugin破解插件
下载 链接: https://pan.baidu.com/s/1FTgtJiyzxxaNxWLyX4OgZw 密码: w7w8 idea安装本地插件
- Oracle 和 MySQL 在显示数据库名和表名的区别
Oracle 显示数据库名和表名 Oracle 查看表名: select table_name from user_tables; select table_name from dba_tables; ...
- CAD& CG 2020 胡事民教授—开源框架Jittor的创新与探索
题目:深度学习框架"计图"的创新与探索 报告人:胡事民 报告人简介:胡事民,清华大学计算机系教授,主要研究方向为计算机图形学.虚拟现实.智能信息处理和系统软件等. 报告简介:深度学 ...
- ansible-playbook文件结构
ansible-playbook文件结构: 1 --- 2 - name: play1 #指定的playbook名字 3 hosts: webservers #指定主机组 4 remote_user: ...
- ubuntu19.10如何设置固定ip
$ip a 看见系统中有两块网卡 lo: ...... ens33: ...... #cd /etc/netplan$ls目录下面有文件01-network-manager-all.yaml $sud ...
- 【C语言教程】双向链表学习总结和C语言代码实现!值得学习~
双向链表 定义 我们一开始学习的链表中各节点中都只包含一个指针(游标),且都统一指向直接后继节点,通常称这类链表为单向链表. 虽然使用单向链表能 100% 解决逻辑关系为 "一对一" ...
- docker系统化学习图文+视频教程
1.背景 博客对应的视频课程: 9.9元在线学习:https://study.163.com/course/courseMain.htm?share=2&shareId=40000000033 ...
- CentOS 8 安装 oniguruma 和 oniguruma-devel
一,oniguruma是什么? oniguruma是一个处理正则表达式的库,我们之所以需要安装它, 是因为在安装php7.4的过程中,mbstring的正则表达式处理功能对这个包有依赖性, 所以我们要 ...