0%

【MVC教學】6.驗證參數- 透過FluentValidation

Demo範例 :Git位置

上一篇簡介了Controller如何安排程式邏輯流程、驗證參數,卻也發現了驗證參數導致程式寫得冗長不易維護,這一篇要介紹【FluentValidation】這個套件來解決這個問題。

安裝



設定

把之前的程式碼稍作整理,將Account與Password新建一個類型(Class)來封裝起來,原本Controller裡面的程式整理一下

自定義驗證Class

建立一個Class命名為UserSignUpParameterValidation

將UserSignUpParameter掛上Validator Attribute,意思是UserSignUpParameter請幫我用UserSignUpParameterValidation裡面的邏輯來驗證

帳號密碼不能為空值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
/// <summary>
/// Validation UserSignUpParameter
/// </summary>
/// <seealso cref="FluentValidation.AbstractValidator{HelloDotNetMVC.Parameters.UserSignUpParameter}" />
public class UserSignUpParameterValidation:AbstractValidator<UserSignUpParameter>
{
public UserSignUpParameterValidation()
{
//AbstractValidator為FluentValidation提供的抽象類別
//目的是讓使用者可以透過繼承這個抽象類別後,實作自己的驗證邏輯
//而泛型T, AbstractValidator<T> ,則帶入你想驗證的類別
//所以這邊帶入UserSignUpParameter,這個我們剛剛製作的Class

//Account
RuleFor(x => x.Account)
.NotEmpty()
.WithMessage("帳號不能為Empty")
.NotNull()
.WithMessage("帳號不能為Null");

//Password
RuleFor(x=>x.Password)
.NotEmpty()
.WithMessage("密碼不能為Empty")
.NotNull()
.WithMessage("密碼不能為Null");
}
}

RuleFor是FluentValidation提供的方法,意思是我為Account這個屬性建立驗證的Rule,而Rule分別是,NotEmpty(不能為空值)、NotNull(不能為Null),而緊接在每個驗證邏輯下面的WithMessage則是表示,當發生它上面的錯誤時,錯誤訊息請回傳這行。

接著我們可以將Controller的這塊驗證邏輯拿掉,交給UserSignUpParameterValidation專責處理就好。

帳號必須包含@字元,Password必須大於6個字

因為判斷字元@並不像判斷空值與Null一樣,官方有實做好的方法,必須自己透過Must來定義,這邊提供兩種寫法給讀者參考

上面是匿名方法的寫法,但如果你對於匿名委派還不是很熟悉,也可以用比較簡單的方式寫

[![](https://4.bp.blogspot.com/-KmJSyZdiGb0/WvAWiccBedI/AAAAAAAAIvw/17gYP6xPzgIUFII1ptocXolNHkBXfGeegCLcBGAs/s400/11.png)](https://4.bp.blogspot.com/-KmJSyZdiGb0/WvAWiccBedI/AAAAAAAAIvw/17gYP6xPzgIUFII1ptocXolNHkBXfGeegCLcBGAs/s1600/11.png)
先寫好驗證的方法,然後在Must中帶入方法。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
/// <summary>
/// Validation UserSignUpParameter
/// </summary>
/// <seealso cref="FluentValidation.AbstractValidator{HelloDotNetMVC.Parameters.UserSignUpParameter}" />
public class UserSignUpParameterValidation:AbstractValidator<UserSignUpParameter>
{
public UserSignUpParameterValidation()
{
//AbstractValidator為FluentValidation提供的抽象類別
//目的是讓使用者可以透過繼承這個抽象類別後,實作自己的驗證邏輯
//而泛型T, AbstractValidator<T> ,則帶入你想驗證的類別
//所以這邊帶入UserSignUpParameter,這個我們剛剛製作的Class

//Account
RuleFor(x => x.Account)
.NotEmpty()
.WithMessage("帳號不能為Empty")
.NotNull()
.WithMessage("帳號不能為Null")
.Must(IncludeAccountKeyword)
.WithMessage("帳號不符合格式");

//Password
RuleFor(x=>x.Password)
.NotEmpty()
.WithMessage("密碼不能為Empty")
.NotNull()
.WithMessage("密碼不能為Null")
.MinimumLength(7)
.WithMessage("密碼必須大於6個字元");
}

/// <summary>
/// Accounts 必須包含@.
/// </summary>
/// <param name="account">The account.</param>
/// <returns></returns>
private bool IncludeAccountKeyword(string account)
{
if (!string.IsNullOrWhiteSpace(account))
{
return account.Contains("@");
}

return false;
}
}

整理後的Controller

透過ModelState得知驗證結果

ModelState是本來MVC就有提供的參數驗證方式,而使用方法這邊提供幾篇文章給有興趣的讀者參考
What is the ModelState? - ASP.NET MVC Demystified
保哥 : ASP.NET MVC 開發心得分享 (28):深入了解 ModelState 內部細節

而因為開發習慣的關係,我習慣用FluentValidation的方式來取代原本ModelState驗證方法與設定方式,接著我們在Global.asax中呼叫FluentValidationModelValidatorProvider.Configure()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
[HttpPost]
public ActionResult SignUp(UserSignUpParameter parameter)
{
if (!ModelState.IsValid)
{
//IsValida為False時,表示驗證參數不過
//取出第一筆錯誤訊息回傳
var Error = ModelState.Values.SelectMany(x => x.Errors).First();
TempData["Message"] = Error.ErrorMessage;
return RedirectToAction("signup", "user");
}

//這邊沒有搬到FluentValidation去驗證的原因是
//使用者存在與否比較屬於服務層的事情,通常需要讀取資料庫才能判斷
//開發上習慣盡量讓驗證參數越乾淨簡單越好,而不是在裡面呼叫很多外部服務(例如資料庫)後做驗證
//這會讓職責過於複雜
if (parameter.Account != "steven@mymail.com")
{
TempData["Message"] = "註冊成功!!";
//註冊成功,導到首頁
return RedirectToAction("index", "home");

}
else
{
TempData["Message"] = "帳號已經存在";
return RedirectToAction("signup", "user");
}
}

接著執行程式,驗證看看是否之前的驗證邏輯都還是正常運作。


比較一下最一開始與套用FluentValidation後的程式碼,應該可以明顯感受到差異,這不僅僅只是讓程式變乾淨,更重要的是驗證參數的職責被分離到UserSignUpParameterValidation這個類別中,以後要改參數驗證的邏輯只要到這調整即可,不用再擔心Controller會被不小心改壞。

延伸閱讀

FluentValidation : 官方文件、各種API使用方法
FluentValidation : 擴充驗證方法
FluentValidation : 繼承父類別的驗證