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