怎么在.NET项目中利用FluentValidation对数据进行验证
本篇文章為大家展示了怎么在.NET項目中利用FluentValidation對數據進行驗證,內容簡明扼要并且容易理解,絕對能使你眼前一亮,通過這篇文章的詳細介紹希望你能有所收獲。
FluentValidation 是一個基于 .NET 開發的驗證框架,開源免費,而且優雅,支持鏈式操作,易于理解,功能完善,還是可與 MVC5、WebApi2 和 ASP.NET CORE 深度集成,組件內提供十幾種常用驗證器,可擴展性好,支持自定義驗證器,支持本地化多語言。
要使用驗證框架, 需要在項目中添加對 FluentValidation.dll 的引用,支持 netstandard2.0 庫和 .NET4.5 平臺,支持.NET Core 平臺,最簡單的方法是使用 NuGet 包管理器引用組件。我這里安裝的是9.2.0版本。
Install-PackageFluentValidation
若要在 ASP.NET Core 中使用 FluentValidation 擴展,可引用以下包:
Install-PackageFluentValidation.AspNetCore
若要在 ASP.NET MVC 5 或 WebApi 2 項目集成, 可以使用分別使用 FluentValidation.Mvc5 和 FluentValidation.WebApi 程序包。
Install-PackageFluentValidation.Mvc5 Install-PackageFluentValidation.WebApi
創建第一個驗證程序
若要為特定對象定義一組驗證規則, 您需要創建一個從 AbstractValidator<T> 繼承的類, 其中泛型T參數是要驗證的類的類型。假設您有一個客戶類別:
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<Customer>
{
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<Customer>
{
publicCustomerValidator()
{
RuleFor(customer=>customer.Surname).NotNull().NotEqual("foo");
}
}
}
引發異常
如果驗證失敗, 不想返回 ValidationResult 對象,而是想直接拋出異常,可通過調用驗證器的 ValidateAndThrow 進行驗證。
如果驗證失敗,將引發一個 ValidationException 類型的異常,這個異常可以被上層程序捕獲,并從異常中找到詳細錯誤信息。
Customercustomer=newCustomer(); CustomerValidatorvalidationRules=newCustomerValidator(); validationRules.ValidateAndThrow(customer);
集合
當針對一個集合進行驗證時,只需要定義集合項類型的規則即可,以下規則將對集合中的每個元素運行 NotNull 檢查。
publicclassCustomer
{
publicList<string>OtherAddress{get;set;}
}
publicclassCustomerValidator:AbstractValidator<Customer>
{
publicCustomerValidator()
{
RuleForEach(customer=>customer.OtherAddress).NotEmpty();
}
}
如果要對list進行進行非空判斷可以如下:
publicclassCustomerValidator:AbstractValidator<Customer>
{
publicCustomerValidator()
{
RuleFor(customer=>customer.OtherAddress).NotEmpty();
}
}
復雜屬性
驗證程序可以用于復雜屬性,假設您有兩個類:客戶和地址
publicclassCustomer
{
publicAdressAddress{get;set;}
}
publicclassAdress
{
publicstringCity{get;set;}
publicstringProvince{get;set;}
}
然后定義一個基于地址的 AddressValidator 驗證器件:
publicclassAdressValidator:AbstractValidator<Adress>
{
publicAdressValidator()
{
RuleFor(t=>t.City).NotEmpty();
RuleFor(t=>t.Province).NotEmpty();
}
}
然后定義一個基于客戶的 CustomerValidator 驗證器件,對地址驗證時使用地址驗證器。
publicclassCustomerValidator:AbstractValidator<Customer>
{
publicCustomerValidator()
{
RuleFor(t=>t.Address).SetValidator(newAdressValidator());
}
}
如果不想要創建另一個驗證器可以直接內聯定義子規則:
RuleFor(t=>t.Address.City).NotEmpty();
另外,還可以在集合屬性上使用驗證程序,假設客戶對象包含地址集合屬性:
publicclassCustomer
{
publicList<Adress>Address{get;set;}
}
此驗證程序可在 CustomerValidator 中通過 SetCollectionValidator(在8.0版本以前) 方法使用,在8.0版本以及之后被棄用需要使用RuleForEach來驗證:
publicclassCustomerValidator:AbstractValidator<Customer>
{
publicCustomerValidator()
{
RuleForEach(t=>t.Address).SetValidator(newAdressValidator());
//RuleFor(x=>x.Address).SetCollectionValidator(newAdressValidator());在8.0版本及以后棄用
}
}
在編寫驗證規則時,可以通過 Where 關鍵字排除或者篩選不需要驗證的對象。
publicclassCustomerValidator:AbstractValidator<Customer>
{
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版本及以后棄用
}
}
從FluentValidation 8.5開始,您還可以使用以下ChildRules方法在線定義子集合元素的規則,從而不用再定義另一個驗證器:
RuleForEach(t=>t.Address).ChildRules(adderss=>{
adderss.RuleFor(t=>t.City).NotEmpty();
adderss.RuleFor(t=>t.Province).NotEmpty();
}).NotEmpty();
支持規則集
規則集允許您將驗證規則分組在一起,這些規則可以作為一個組一起執行,而忽略其他規則:
我們可以把“姓”和“名”統一加在一個姓名規則集中。
publicclassCustomerValidator:AbstractValidator<Customer>
{
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(這等效于using IncludeRuleSets("*"))。
同個類型的多個驗證器
一個驗證器可以包含多個其他的驗證器,只要這些驗證器都是驗證統一類型的即可。這樣就可以拆分驗證器,通過不同的需求組合在一起:
publicclassCustomerValidator:AbstractValidator<Customer>
{
publicCustomerValidator()
{
Include(newCustomerSurnameValidator());
Include(newCustomerForenameValidator());
}
}
publicclassCustomerSurnameValidator:AbstractValidator<Customer>
{
publicCustomerSurnameValidator()
{
RuleFor(t=>t.Surname).NotEmpty();
}
}
publicclassCustomerForenameValidator:AbstractValidator<Customer>
{
publicCustomerForenameValidator()
{
RuleFor(t=>t.Forename).NotEmpty();
}
}
繼承驗證
從FluentValidation 9.2開始,如果您的對象屬性作為其他類的基類或接口,則可以為各個子類/實現器設置特定的子驗證器,來驗證這個屬性。我們的類設置如下:
publicclassStore
{
publicPeoplePeoples{get;set;}
}
publicclassCustomer:People
{
publicstringAddress{get;set;}
}
publicclassPeople
{
publicstringName{get;set;}
}
驗證器如下:
publicclassStoreValidator:AbstractValidator<Store>
{
publicStoreValidator()
{
RuleFor(t=>t.Peoples).NotNull().SetInheritanceValidator(t=>
{
t.Add<Customer>(newCustomerValidator());
});
}
}
publicclassCustomerValidator:AbstractValidator<Customer>
{
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<Customer>
{
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 -驗證程序失敗后立即停止執行規則(僅在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。假設我們有以下課程:
publicclassPerson{
publicIList<Pet>Pets{get;set;}=newList<Pet>();
}
為了確保我們的list屬性包含少于10個項目,我們可以這樣做:
publicclassPersonValidator:AbstractValidator<Person>{
publicPersonValidator(){
RuleFor(x=>x.Pets).Must(list=>list.Count<10)
.WithMessage("Thelistmustcontainfewerthan10items");
}
}
為了使我們自己定義的驗證器可以重用,我們可以將其包裝為可作用于任何List<T>類型的擴展方法。
publicstaticclassMyCustomValidators{
publicstaticIRuleBuilderOptions<T,IList<TElement>>ListMustContainFewerThan<T,TElement>(thisIRuleBuilder<T,IList<TElement>>ruleBuilder,intnum){
returnruleBuilder.Must(list=>list.Count<num).WithMessage("Thelistcontainstoomanyitems");
}
}
在這里,我們在上創建一個擴展方法IRuleBuilder<T,TProperty>,并使用通用類型約束來確保此方法僅出現在對列表類型的智能感知中。在方法內部,我們以與以前相同的方式調用Must方法,但是這次我們在傳入的RuleBuilder實例上調用它。我們還將要比較的項目數作為參數傳遞。現在,我們的規則定義可以重寫為使用以下方法:
RuleFor(x=>x.Pets).ListMustContainFewerThan(10);
我們還可以通過Custom方法來自定義驗證器,它相比于Must的好處是允許針對同一規則返回多個錯誤(通過context.AddFailure多次調用該方法)。
publicclassPersonValidator:AbstractValidator<Person>{
publicPersonValidator(){
RuleFor(x=>x.Pets).Custom((list,context)=>{
if(list.Count>10){
context.AddFailure("Thelistmustcontain10itemsorfewer");
}
});
}
}
總結
以上是生活随笔為你收集整理的怎么在.NET项目中利用FluentValidation对数据进行验证的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 搭建卷积神经网络时loss计算方式的选择
- 下一篇: C语言中的packed含义