FluentValidation 支援與 ASP.NET Core 2.1 或3.1整合(建議使用3.1)。啟用後,MVC將使用 FluentValidation 來驗證由模型繫結基礎結構傳遞到控制器操作中的物件。
要啟用MVC整合,您需要 FluentValidation.AspNetCore 通過安裝適當的NuGet軟體包來新增對程式集的引用。
安裝完成後,您需要通過在 AddFluentValidation 方法在 Startup 類中的 ConfigureServices 方法中註冊服務。
public void ConfigureServices(IServiceCollection services) {
services.AddMvc().AddFluentValidation().SetCompatibilityVersion(CompatibilityVersion.Version_2_2); }
為了使驗證生效還需要再 ConfigureServices 中依賴注入我們的驗證器。
services.AddTransient<IValidator<Customer>, CustomerValidator>();
自動註冊驗證器
不過這樣一個個註冊太麻煩了,所以有一個批量註冊的方法 RegisterValidatorsFromAssemblyContaining 通過這個方法可以註冊特定程式集中的所有的驗證器。這將自動查詢從其繼承 AbstractValidator 並在容器中註冊的所有公共非抽象型別(不支援開放的泛型)。如下所示建立一個驗證器和一個驗證器介面,相應的類我就不建立了。
public class CustomerValidator : AbstractValidator<Customer> , IValidator { public CustomerValidator() { RuleFor(t => t.Name).NotEmpty(); } } public interface IValidator{}
之後在 Startup 類中的 ConfigureServices 方法中使用 RegisterValidatorsFromAssemblyContaining 註冊 IValidator 介面,這樣所有繼承 IValidator 和 AbstractValidator 的驗證器就會全部自動註冊了。
services.AddMvc().AddFluentValidation(fv => fv.RegisterValidatorsFromAssemblyContaining<IValidator>()).SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
自動註冊的驗證器是以 Transient 的形式註冊的而不是 Singleton 。如果您不想註冊特定的驗證器型別,則可以使用過濾器回撥將其排除,如下所示就排除了CustomerValidator驗證器:
services.AddMvc().AddFluentValidation(fv => fv.RegisterValidatorsFromAssemblyContaining<IValidator>(discoveredType => discoveredType.ValidatorType != typeof(CustomerValidator))).SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
在控制器中使用驗證器
直接用原來的 ModelState.IsValid 就可以了。
public IActionResult Create(Customer customer) { customer = new Customer(); CustomerValidator validationRules = new CustomerValidator(); if (!ModelState.IsValid) return Content("失敗了"); return View(); }
執行應用程式時,還可以選擇對子屬性啟用隱式驗證。啟用此功能後,無需使用來指定子驗證器 SetValidator,MVC的驗證基礎結構將遞迴地嘗試自動為每個屬性查詢驗證器。可以通過設定 ImplicitlyValidateChildProperties 為true來完成:
services.AddMvc().AddFluentValidation(fv => { fv.ImplicitlyValidateChildProperties = true; });
請注意,如果啟用此行為,則不應將其 SetValidator 用於子屬性,否則驗證程式將執行兩次。
手動驗證
有時您可能需要手動驗證 MVC 專案中的物件,在這種情況下, 我們可以將驗證結果複製到 MVC 的 ModelState 字典中,便可用於前端錯誤提示。
public ActionResult DoSomething() { var customer = new Customer(); var validator = new CustomerValidator(); var results = validator.Validate(customer); results.AddToModelState(ModelState, null); return View(); }
AddToModelState 方法是作為擴充套件方法實現的, 需要引用 FluentValidation 名稱空間,請注意, 第二個引數是可選的模型名稱字首, 該引數可設定物件屬性在 ModelState 字典中的字首。
驗證程式自定義
您可以使用 CustomizeValidatorAttribute 為模型指定驗證程式,也支援為驗證器指定規則集。
public ActionResult Save([CustomizeValidator(RuleSet="MyRuleset")] Customer cust) { // ... }
這相當於為驗證指定規則集,等同於將規則集傳遞給驗證程式:
var validator = new CustomerValidator(); var customer = new Customer(); var result = validator.Validate(customer, ruleSet: "MyRuleset");
該屬性還可用於呼叫單個屬性的驗證:
public ActionResult Save([CustomizeValidator(Properties="Surname,Forename")] Customer cust) { // ... }
這相當於對驗證程式指定特定屬性,其它屬性將不被驗證:
var validator = new CustomerValidator(); var customer = new Customer(); var result = validator.Validate(customer, properties: new[] { "Surname", "Forename" });
也可以使用 CustomizeValidatorAttribute 特性跳過某些型別的驗證。
public ActionResult Save([CustomizeValidator(Skip=true)] Customer cust) { // ... }
驗證器攔截器
您可以使用攔截器進一步自定義驗證過程,攔截器必須實現 FluentValidation.Mvc 名稱空間中的 IValidatorInterceptor 介面:
public interface IValidatorInterceptor { ValidationContext BeforeMvcValidation(ControllerContext controllerContext, ValidationContext validationContext); ValidationResult AfterMvcValidation(ControllerContext controllerContext, ValidationContext validationContext, ValidationResult result); }
此介面有兩個方法:BeforeMvcValidation 和 AfterMvcValidation,分別可攔截驗證前和驗證後的過程。除了在驗證程式類中直接實現此介面外, 我們還可以在外部實現該介面, 通過 CustomizeValidatorAttribute 特性指定攔截器:
public ActionResult Save([CustomizeValidator(Interceptor=typeof(MyCustomerInterceptor))] Customer cust) { //... }
在這種情況下, 攔截器必須是一個實現 IValidatorInterceptor 介面,並具有公共無引數建構函式的類。請注意, 攔截器是高階方案,大多數情況下, 您可能不需要使用攔截器, 但如果需要, 可以選擇它。
為客戶端指定規則集
預設情況下 FluentValidation 不會為客戶端生成基於規則集的驗證程式碼, 但您可以通過 RuleSetForClientSideMessagesAttribute 為客戶端指定規則集。
[RuleSetForClientSideMessages("MyRuleset")] public ActionResult Index() { return View(new PersonViewModel()); }
也可以在控制器中使用 SetRulesetForClientsideMessages 擴充套件方法 (需要引用 FluentValidation 名稱空間)為客戶端指定規則集。
public ActionResult Index() { ControllerContext.SetRulesetForClientsideMessages("MyRuleset"); return View(new PersonViewModel()); }