在 WebAPI 世界中,一定會針對傳入資料進行驗證。本篇文章記錄我在 .NET Core 的兩種驗證方法的實作過程,一種是使用內建的 Model Binding Validation,另一種是使用 FluentValidation 進行驗證。
本文記錄兩種實作方法,並不會比較或說明那個好那個不好,請各位看完後自己思考看看,再決定要採用哪種方法。
另外這文章記錄我的實作(簡易版)過程,算是 101 等級的文章,並沒有太多理論或撞牆部分。
一、Model Binding 驗證設定
有在 .NET Framework 寫過 MVC 或 WebAPI 都知道,只要在想被驗證的 Model 中的 Property 上掛上 Attribute Tags 就可以了。
public class Person
{
[Required]
public int Id { get; set; }
[MinLength(0)]
[MaxLength(10)]
public string Name { get; set; }
[EmailAddress]
public string Email { get; set; }
[Range(18, 60)]
public int Age { get; set; }
}
還有哪些 Attribute Tags?或者如何自訂驗證?可以參考微軟官方說明:模型驗證。
這樣我們就完成驗證相關設定了。
接下來使用 ModelState.IsValid == false
就能進行驗證了。
二、FluentValidation 驗證設定
- 安裝 FluentValidation:
Install-Package FluentValidation.AspNetCore
- Startup.cs 中的 ConfigureServices 設定:
.AddMVC()
後加上.AddFluentValidation()
(using FluentValidation.AspNetCore
)。- 依賴注入:
services.AddTransient<IValidator<Person>, PersonValidator>();
其中PersonValidator
是撰寫被驗證模型 Person 的驗證規則的地方。public void ConfigureServices(IServiceCollection services) { services.AddMvc() .SetCompatibilityVersion(CompatibilityVersion.Version_2_2) .AddFluentValidation(); services.AddTransient<IValidator<Person>, PersonValidator>(); }
-
實作模組 Person 與 PersonValidator:
-
PersonValidator 繼承
AbstractValidator
,開始撰寫<Person> RuleFor()
。public class Person { public int Id { get; set; } public string Name { get; set; } public string Email { get; set; } public int Age { get; set; } public DateTime Birthday { get; set; } } public class PersonValidator : AbstractValidator<Person> { public PersonValidator() { RuleFor(x => x.Id).NotNull(); RuleFor(x => x.Name).Length(0, 100); RuleFor(x => x.Email).EmailAddress(); RuleFor(x => x.Age).InclusiveBetween(18, 99); RuleFor(x => x.Birthday).LessThan(x => DateTime.Today); } }
-
詳細使用 FluentValidation 方式,請參考:[料理佳餚] 讓 FluentValidation 把參數的檢查條件口語化。
-
-
一樣於 Controller 使用
ModelState.IsValid == false
就能進行驗證了。 -
個人覺得原廠的錯誤訊息滿清楚的,當然你也能針對每個欄位進行客製化錯誤訊息。
{ "errors": { "Age": [ "'Age' 必須在 18 (包含)和 60 (包含)之間, 您輸入了 0。" ], "Email": [ "'Email' 不是有效的電子郵件地址。" ], "Birthday": [ "'Birthday' 必須小於 '2019/3/30 上午 12:00:00'。" ] }, "title": "One or more validation errors occurred.", "status": 400, "traceId": "0HLLKVDDP3BM3:00000001" }
其實 FluentValidation 功能相當的多,而且可能會和 Model Binding Validation 相衝,更多詳細設定可以參考這篇(推薦)文章。
三、調整執行驗證方式
很多人會在各 Action 中加上以下程式碼做驗證:
if(! ModelState.IsValid)
{
return BadRequest(); // 可自製錯誤訊息回傳回去
}
如果每個 Action 都掛上去,就會變成重複的程式,所以我將這段執行驗證程式放到 Action Filter 中。
public class ValidateModelAttribute : Attribute, IAsyncActionFilter
{
[ProducesResponseType(400)]
public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
{
if (context.ModelState.IsValid == false)
{
context.Result = new BadRequestObjectResult(context); // 可自製錯誤訊息回傳回去
}
await next();
}
}
以上程式,兩種驗證方法都適用。
四、結尾
兩種驗證方式選擇其一使用就好,另外配合 Action Filter,讓沒通過驗證的一開始就踢出去。
以上作法只是新手入門,網路上也有很多針對這兩種驗證的教學(包含自定義驗證),可能遇到各種奇怪問題,未來有空在寫寫撞牆心得。