.Net Core 使用 FluentValidation

FluentValidation 支持與 ASP.NET Core 2.1 或3.1集成(建議使用3.1)。啓用後,MVC將使用 FluentValidation 來驗證由模型綁定基礎結構傳遞到控制器操做中的對象。前端

要啓用MVC集成,您須要 FluentValidation.AspNetCore 經過安裝適當的NuGet軟件包來添加對程序集的引用。ide

安裝完成後,您須要經過在 AddFluentValidation 方法在 Startup 類中的 ConfigureServices 方法中註冊服務。函數

public void ConfigureServices(IServiceCollection services)
{              
  services.AddMvc().AddFluentValidation().SetCompatibilityVersion(CompatibilityVersion.Version_2_2); }

爲了使驗證生效還須要再 ConfigureServices 中依賴注入咱們的驗證器。spa

services.AddTransient<IValidator<Customer>, CustomerValidator>();

自動註冊驗證器

不過這樣一個個註冊太麻煩了,因此有一個批量註冊的方法 RegisterValidatorsFromAssemblyContaining 經過這個方法能夠註冊特定程序集中的全部的驗證器。這將自動查找從其繼承 AbstractValidator 並在容器中註冊的全部公共非抽象類型(不支持開放的泛型)。以下所示建立一個驗證器和一個驗證器接口,相應的類我就不建立了。code

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驗證器:blog

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());
}