在文章:這些.NET開源項目你知道嗎?讓.NET開源來得更加猛烈些吧!(第二輯)中,給大家初步介紹了一下FluentValidation驗證組件。那里只是概述了一下,並沒有對其使用和強大功能做深入研究,所以今天以及接下去的幾篇文章就專門介紹這個組件。不僅僅是它小,輕量級,優雅,而且一直在持續更新中。本人對這個感觸很深是源於4年前自己在做一個數據過濾軟件時,自己也設計了一套驗證過濾的東西,雖然勉強能用,但太復雜了,復雜到我看到就想吐。。。指導我遇到了FluentValidation,徹底顛覆了我的看法,原來代碼是可以很優雅的。。。這就是所謂的架構技術吧,雖然我不是很懂,但一直追求中。
為了保持內容的完整性,大部分內容我都是參考FluentValidation提供的幫助文檔,自己經過翻譯和理解加工。更好的呈現給大家。
.NET開源目錄:【目錄】本博客其他.NET開源項目文章目錄
本文原文地址:.NET平台開源項目速覽(6)FluentValidation驗證組件介紹與入門(一)
1.基本介紹
FluentValidation是一個使用Linq表達式,非常流暢的小型業務對象驗證組件。流暢也可以說優雅。類似鏈式操作。易於理解,功能完善。還可以配合MVC使用直接在頁面進行驗證,當你看到它的語法時,非常優雅,非常令人心動。不僅可以使用Linq的操作,還能自帶驗證返回信息。更重要的是,組件內部已經封裝好了10幾種驗證器。當然可以自定義一個復雜的哦。核心dll文件也不大,130多k。如果好用,可以自己移植到自己的系統哦。直接更好。目前一直在更新中,主要是bug修復。
官方網站:https://github.com/JeremySkinner/FluentValidation
NuGet Packages:Install-Package FluentValidation
ASP.NET MVC集成包:Install-Package FluentValidation.MVC5
下面我們將從一個簡單的驗證器的創建以及使用來介紹它的基本功能。
2.創建驗證器
使用之前,要引用FluentValidation.dll,太簡單,就省略了吧。為了給特定的對象定義一組驗證規則,必須創建一個繼承AbstractValidator<T>的類,T是需要驗證的類型。例如,假設我們有一個Customer類,如下所示:
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; } }
所以按照上面要求,我們要給Customer定義一組驗證規則,就要繼承AbstractValidator<Customer>,如下面代碼:
using FluentValidation; public class CustomerValidator : AbstractValidator<Customer> { }
驗證規則本身在驗證器的構造函數中定義。為了給特定屬性指定一個驗證規則,需要調用RuleFor方法,通過屬性的lambda表達式來進行你想要的驗證。例如,確保Surname屬性不是null,驗證器應該這樣寫:
using FluentValidation; //Customer驗證器 public class CustomerValidator : AbstractValidator<Customer> { public CustomerValidator() { RuleFor(customer => customer.Surname).NotNull(); } }
3.針對相同屬性的鏈式編程驗證
針對同一個屬性編寫驗證代碼時,我們可以使用鏈式的方式進行,非常方便,也容易理解。如下面的代碼:
using FluentValidation; public class CustomerValidator : AbstractValidator<Customer> { public CustomerValidator() { //Surname不為空,且不等於foo RuleFor(customer => customer.Surname).NotNull().NotEqual("foo"); } }
上面的注釋已經很明顯了,針對Surname屬性,直接進行判斷和編寫代碼,同樣可以寫其他的,一直寫下去。。。為了執行驗證器,我們首先要創建一個驗證器的實例對象,然后將要驗證的對象傳遞給Validate方法,即可進行驗證。如下面代碼:
//要驗證的對象實例 Customer customer = new Customer(); //驗證器實例 CustomerValidator validator = new CustomerValidator(); //進行驗證操作,獲取驗證結果 ValidationResult results = validator.Validate(customer);
至於結果的內容,請接着往下看。
4.驗證結果
在使用驗證器的Validate進行驗證后,獲取的ValidationResult對象里面提供了2個主要信息:
1.IsValid: 標記是否驗證成功
2.Errors :錯誤情況,驗證失敗的對象集合,包括所有驗證失敗對象的細節。
例如下面的代碼將驗證失敗的信息打印出來:
Customer customer = new Customer(); CustomerValidator validator = new CustomerValidator(); ValidationResult results = validator.Validate(customer); //如果驗證失敗 if(! results.IsValid) { //遍歷所有的失敗對象 foreach(var failure in results.Errors) { //失敗的屬性名稱,如錯誤信息 Console.WriteLine("Property " + failure.PropertyName + " failed validation. Error was: " + failure.ErrorMessage); } }
5.異常與復雜驗證
5.1 如何拋出異常
上一節中,我們看到了驗證結果的處理情況,但是在很多情況下,如果驗證失敗的情況下,要及時拋出異常給用戶,所以在驗證的時候就要注意拋出異常,FluentValidation也提供了這樣的機制,它為驗證器提供了一個ValidateAndThrow 的擴展方法。使用這個方法后,如果碰到失敗的情況,會及時拋出一個ValidationException 異常,讓業務驗證過程使用。主要代碼如下:
Customer customer = new Customer(); CustomerValidator validator = new CustomerValidator(); validator.ValidateAndThrow(customer);
5.2 復雜驗證的處理
我們前面處理的都是單個驗證器的使用,構成也基本清楚了,但如果在當前驗證的實體類中還有其他對象,也需要對這個對象進行各種屬性驗證,該怎么辦。舉個例子,假設我們有一個 客戶類 Customer 以及地址類Address,在Customer 中包括了一個Address類型的屬性,用來存儲當前客戶的地址信息,如下面所示代碼:
//客戶類 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 County { get; set; } public string Postcode { get; set; } }
由於我們也需要對Address類進行,驗證,所以先類似的構造一個Address驗證器:
public class AddressValidator : AbstractValidator<Address> { public AddressValidator() { RuleFor(address => address.Postcode).NotNull(); } }
然后我們同理要構造CustomerValidator驗證器,在驗證Address的時候,及可以復用上面的AddressValidator,如下面代碼:
public class CustomerValidator : AbstractValidator<Customer> { public CustomerValidator() { RuleFor(customer => customer.Name).NotNull(); //對Address使用驗證器直接進行驗證,可以重復使用代碼 RuleFor(customer => customer.Address).SetValidator(new AddressValidator()) } }
過程比較簡單,更加復雜的處理也類似,應該沒啥問題了。值得注意的是,如果Address 是集合類型,如List<Address> ,則要使用SetCollectionValidator來進行驗證,和SetValidator的使用類似。
6.靈活的驗證規則組設置
我們在編寫驗證過程中,可以編寫大量的驗證方法,針對不同使用場景,不同字段。但隨着業務的復雜,並不是每一個驗證器的使用的時候都要執行所有的驗證規則。有的時候可能只需要執行一部分就可以了,否則需要針對同一個類型,編寫很多個不同業務場景的驗證器,顯然則是非常殘酷的。而FluentValidation則提供了處理這種問題的靈活性,將規則組集合在一起,並賦予一個名稱,在執行的時候,可以只執行指定名稱規則組的規則。看看下面的例子:
假設一個Person類有3個屬性(Id,Surname,Forename),我們寫一個驗證器分別對幾個屬性進行驗證,並將其中2個的驗證規則放在一個規則集合里面RuleSet,名稱為:Names,如下面代碼:
public class PersonValidator : AbstractValidator<Person> { public PersonValidator() { //名稱為 Names 的規則組 RuleSet("Names", () => { RuleFor(x => x.Surname).NotNull(); RuleFor(x => x.Forename).NotNull(); }); //其他沒有集合的組名稱,默認為:default RuleFor(x => x.Id).NotEqual(0); } }
然后我們在驗證的時候,就可以靈活指定規則集的名稱了,一次可以指定單個或者多個,值得注意的是,沒有放在集合中的規則,默認在 default 組中。如下面的代碼:
var validator = new PersonValidator(); var person = new Person(); //只執行 Names 規則集 var result = validator.Validate(person, ruleSet: "Names"); //執行 Names,MyRuleSet,SomeOtherRuleSet 規則集 validator.Validate(person, ruleSet: "Names,MyRuleSet,SomeOtherRuleSet") //執行默認的規則(不在集合中的) 和 MyRuleSet validator.Validate(person, ruleSet: "default,MyRuleSet")
上面就是今天的內容,我們對驗證器的完整過程和使用細節進行了很深入的研究,相信自己構造一個強大的驗證器已經很容易了吧。接下來的內容,我們將繼續介紹內置的一些驗證方法和規則。對於該組件的源碼可以直接從github獲取,本文將在后面的文章中發布自己制作的CHM幫助文檔。敬請關注!