安装
//普通winform等用到的
Install-Package FluentValidation
//这是AspNetCore中用到的
Install-Package FluentValidation.AspNetCore
创建第一个认证
若要为特定对象定义一组验证规则, 您需要创建一个从 AbstractValidator 继承的类, 其中泛型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;
public class CustomerValidator : AbstractValidator<Customer>
{
public CustomerValidator()
{
RuleFor(customer => customer.Surname).NotNull();
}
}
若要执行验证程序,我们通过定义好的 CustomerValidator 验证器传入实体类 Customer 即可。
Customer customer = new Customer();
CustomerValidator validator = new CustomerValidator();
ValidationResult result = validator.Validate(customer);
该验证方法返回一个 ValidationResult 对象,表示验证结果,ValidationResult 包含两个属性:IsValid属性是布尔值, 它表示验证是否成功,Errors属性包含验证失败的详细信息。
下面的代码演示向控制台输出验证失败的详细信息:
using FluentValidation.Results;
Customer customer = new Customer();
CustomerValidator validator = new CustomerValidator();
ValidationResult results = validator.Validate(customer);
if(! results.IsValid)
{
foreach(ValidationFailure failure in results.Errors)
{
Console.WriteLine("Property " + failure.PropertyName + " failed validation. Error was: " + failure.ErrorMessage);
}
}
你可以收能够用tostring将所有的验证异常数据揉合在一起,默认情况下会分多行,你可以指定分隔符。
using FluentValidation;
using FluentValidation.Results;
Customer customer = new Customer();
CustomerValidator validator = new CustomerValidator();
ValidationResult results = validator.Validate(customer);
if (!results.IsValid)
{
Console.WriteLine(results.ToString("~"));
}
链接规则写法
您可以将对象的同一属性用多个验证程序链在一起,以下代码将验证 Surname 属性不为 Null 的同时且不等于foo字符串。
using FluentValidation;
public class CustomerValidator : AbstractValidator<Customer>
{
public CustomerValidator()
{
RuleFor(customer => customer.Surname).NotNull().NotEqual("foo");
}
}
集合
当针对一个集合进行验证时,只需要定义集合项类型的规则即可,以下规则将对集合中的每个元素运行 NotNull 检查。
public class Person
{
public List<string> AddressLines { get; set; } = new List<string>();
}
public class PersonValidatior:AbstractValidator<Person>
{
public PersonValidatior()
{
RuleForEach(x => x.AddressLines).NotNull();
}
}
复杂属性
验证程序可以用于复杂属性,假设您有两个类:客户和地址。
public class Customer
{
public string Name { get; set; }
public Address Address { get; set; }
}
public class Address
{
public string Line1 { get; set; }
public string Line2 { get; set; }
public string Town { get; set; }
public string Country { get; set; }
public string Postcode { get; set; }
}
然后定义一个基于地址的 AddressValidator 验证器件:
public class AddressValidator:AbstractValidator<Address>
{
public AddressValidator()
{
RuleFor(address => address.Postcode).NotNull();
}
}
然后定义一个基于客户的 CustomerValidator 验证器件,对地址验证时使用地址验证器。
public class CustomerValidator : AbstractValidator<Customer>
{
public CustomerValidator()
{
RuleFor(customer => customer.Name).NotNull();
RuleFor(customer => customer.Address).SetValidator(new AddressValidator());
}
}
这时候你就可以运行CustomerValidator 的Validate,这会运行Customer以及Address的验证器,并将结果合在一起。
在编写验证规则时,可以通过 Where 关键字排除或者筛选不需要验证的对象。
customer.Address 为空的不再验证
RuleFor(customer => customer.Address.Postcode).NotNull().When(customer => customer.Address != null)
重写异常信息
你可以使用WithMessage 重写default的异常信息
RuleFor(customer => customer.Surname).NotNull().WithMessage("Please ensure that you have entered your Surname");
请注意WithMessage中也可以使用占位符,例如
RuleFor(customer => customer.Surname).NotNull().WithMessage("Please ensure you have entered your {PropertyName}");
这里PropertyName将会被Surname替代。
通用占位符
如上所述,Validator可以包含占位符例如{PropertyName},这会在运行时被替换,每一种内置的验证器都有一系列的占位符,以下占位符在所有的类型的验证器中都可以使用
- {PropertyName} 被验证的属性的属性名
- {PropertyValue} 被验证的属性的属性值
比较类验证占位符(Equal, NotEqual, GreaterThan, GreaterThanOrEqual, etc.)
- {ComparisonValue} 属性将要比对的值
- {ComparisonProperty} 被用来比较的属性
Length 验证占位符
- {MinLength} – Minimum length
- {MaxLength} – Maximum length
- {TotalLength} – Number of characters entered
验证指定属性
通过指定IncludeProperties 你可以运行validator中的特殊属性而不是所有属性都验证
public class CustomerValidator : AbstractValidator<Customer>
{
public CustomerValidator()
{
RuleFor(x => x.Surname).NotNull();
RuleFor(x => x.Forename).NotNull();
RuleForEach(x => x.Orders).SetValidator(new OrderValidator());
}
}
//以下只会验证Surname
var validator = new CustomerValidator();
validator.Validate(new Customer(), options =>
{
options.IncludeProperties(x => x.Surname);
});
RuleSets 规则集
规则集允许您将验证规则分组在一起,这些规则可以作为一个组一起执行,同时忽略其他规则。
例如我们有一个Person类,有三个属性 (Id, Surname, Forename)然后每个属性都有一个验证规则,我们将Surname 和Forename的验证规则组合成一个名为Names的验证集。
public class Person
{
public int Id { get; set; }
public string Surname { get; set; }
public string Forename { get; set; }
}
public class PersonValidator:AbstractValidator<Person>
{
public PersonValidator()
{
RuleSet("Names", () =>
{
RuleFor(x => x.Surname).NotNull();
RuleFor(x => x.Forename).NotNull();
});
RuleFor(x => x.Id).NotEqual(0);
}
}
我们可以通过向validator添加选项指定运行规则
var validator = new PersonValidator();
var person = new Person();
var result = validator.Validate(person, options => options.IncludeRuleSets("Names"));
这允许您将复杂的验证器定义分解为可以单独执行的更小的段。如果在没有传递规则集的情况下调用Validate,则只执行不在规则集中的规则。
你可以通过将多个规则集名称传递给inclerulesets来执行多个规则集:
var result = validator.Validate(person, options =>
{
options.IncludeRuleSets("Names", "MyRuleSet", "SomeOtherRuleSet");
});
你也可以通过调用inclerulesnotinruleset来包含所有不属于规则集的规则,或者使用特殊名称“default”(不区分大小写):
validator.Validate(person, options =>
{
// Option 1: IncludeRulesNotInRuleSet is the equivalent of using the special ruleset name "default"
options.IncludeRuleSets("Names").IncludeRulesNotInRuleSet();
// Option 2: This does the same thing.
option.IncludeRuleSets("Names", "default");
});
设置级联模式(Cascade)
您可以设置级联模式,以自定义当验证器类中的特定规则或规则中的验证器失败时,FluentValidation如何执行规则和验证器。
默认情况,编写多个链式验证规则时,下无论前一个规则失败与否,后一个规则都将执行,以下代码检查 Surname 是否为空,然后检查 Surname 不等于零度,如多 NotNull 验证失败,则仍将调用 NotEqual 验证。
RuleFor(x => x.Surname).NotNull().NotEqual("零度");
我们可以通过 Stop方法制定级联模式。
public class Person
{
public int Id { get; set; }
public string Surname { get; set; }
public string Forename { get; set; }
}
public class PersonValidator:AbstractValidator<Person>
{
public PersonValidator()
{
RuleFor(x => x.Surname).Cascade(CascadeMode.Stop).NotNull().NotEqual("零度");
}
}
Must自定义验证
我们还可以只用mast函数,指定自定义得验证器
using FluentValidation;
using FluentValidation.Results;
Customer customer = new Customer() { ID = 1, Name = "ellisvv" };
CustomerValidator validationRules = new CustomerValidator();
ValidationResult validationResult= validationRules.Validate(customer);
Console.WriteLine(validationResult.ToString());
public class Customer
{
public int ID { get; set; }
public string Name { get; set; }
}
public class CustomerValidator : AbstractValidator<Customer>
{
public CustomerValidator()
{
RuleFor(x => x.Name).Must(test).WithMessage("{PropertyName} must contains blank");
}
public bool test(string arg)
{
if(arg.Contains(" "))
{
return true;
}
else
{
return false;
}
}
}