FluentValidation驗證組件

在文章:這些.NET開源項目你知道嗎?讓.NET開源來得更加猛烈些吧!(第二輯)中,給大家初步介紹了一下FluentValidation驗證組件。那裡只是概述了一下,並沒有對其使用和強大功能做深入研究,所以今天以及接下去的幾篇文章就專門介紹這個組件。不僅僅是它小,輕量級,優雅,而且一直在持續更新中。本人對這個感觸很深是源於4年前自己在做一個數據過濾軟體時,自己也設計了一套驗證過濾的東西,雖然勉強能用,但太複雜了,複雜到我看到就想吐。。。指導我遇到了FluentValidation,徹底顛覆了我的看法,原來代碼是可以很優雅的。。。這就是所謂的架構技術吧,雖然我不是很懂,但一直追求中。

為了保持內容的完整性,大部分內容我都是參考FluentValidation提供的幫助文檔,自己經過翻譯和理解加工。更好的呈現給大家。

1.基本介紹

FluentValidation是一個使用Linq表達式,非常流暢的小型業務對象驗證組件。流暢也可以說優雅。類似鏈式操作。易於理解,功能完善。還可以配合MVC使用直接在頁面進行驗證,當你看到它的語法時,非常優雅,非常令人心動。不僅可以使用Linq的操作,還能自帶驗證返回信息。更重要的是,組件內部已經封裝好了10幾種驗證器。當然可以自定義一個複雜的哦。核心dll文件也不大,130多k。如果好用,可以自己移植到自己的系統哦。直接更好。目前一直在更新中,主要是bug修復。

官方網站:github.com/JeremySkinne

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")//執行默認的規則(不在集合中的) 和 MyRuleSetvalidator.Validate(person, ruleSet: "default,MyRuleSet")

上面就是今天的內容,我們對驗證器的完整過程和使用細節進行了很深入的研究,相信自己構造一個強大的驗證器已經很容易了吧。接下來的內容,我們將繼續介紹內置的一些驗證方法和規則。對於該組件的源碼可以直接從github獲取。


推薦閱讀:

同事離職,我接盤了個垃圾項目,該如何是好?
.NET, PHP, JSP 哪個才是未來的主流語言選擇? 做 SNS 用哪個好?
自學編程十年,依然沒有編寫出過什麼有用的東西,想知道下一步怎麼走?
c# 為什麼不脫離.net平台,實現跨平台呢?
如何正確理解.NET 4.5和C# 5.0中的async/await非同步編程模式?

TAG:NET | 開源項目 | oschina開源中國 |