数据校验FluentValidation.AspNetCore
FluentValidation 可在 ASP.NET Core Web 应用程序中用于验证传入模型。有两种主要方法可以做到这一点:
- 手动验证
- 自动验证
通过手动验证,您将验证器注入您的控制器(或 api 端点),调用验证器并对结果采取行动。这是最直接和最可靠的方法。
通过自动验证,FluentValidation 插入作为 ASP.NET Core MVC 一部分的验证管道,并允许在调用控制器操作之前验证模型(在模型绑定期间)。这种验证方法更加无缝,但有几个缺点:
- 自动验证不是异步的:如果您的验证器包含异步规则,那么您的验证器将无法运行。如果您尝试使用带有自动验证的异步验证器,您将在运行时收到异常。
- 自动验证仅适用于 MVC:自动验证仅适用于 MVC 控制器和 Razor 页面。它不适用于更现代的 ASP.NET 部分,例如 Minimal API 或 Blazor。
- 自动验证很难调试:自动验证的“神奇”特性使得如果出现问题很难调试/排除故障,因为在幕后做了很多事情。
我们通常不建议对新项目使用自动验证,但它仍可用于旧版实现。
一、用NuGet安装 FluentValidation.AspNetCore 包
二、验证模型
public record Login2Request(string Email, string Password, string Password2);
public class Login2RequestValidator : AbstractValidator<Login2Request> {//Login2Request的数据校验类 public Login2RequestValidator() { RuleFor(x => x.Email).NotNull().EmailAddress() .Must(v => v.EndsWith("@qq.com") || v.EndsWith("@163.com")) .WithMessage("只支持QQ和163邮箱"); RuleFor(x => x.Password).NotNull().Length(3, 10) .WithMessage("密码长度必须介于3到10之间") .Equal(x => x.Password2).WithMessage("两次密码必须一致"); } }
2.1 手动验证(推荐)
注册验证器
//注册验证器 services.AddScoped<IValidator<Login2Request>, Login2RequestValidator>();
[Route("api/[controller]")] [ApiController] public class FluentValidatorsController : ControllerBase { private readonly IValidator<Login2Request> _validator; public FluentValidatorsController(IValidator<Login2Request> validator) { _validator = validator; } [Route(nameof(Create))] [HttpPost] public async Task<ActionResult> Create(Login2Request model) { FluentValidation.Results.ValidationResult result = await _validator.ValidateAsync(model); if(!result.IsValid) { result.AddToModelState(this.ModelState); return ValidationProblem(ModelState); } return Ok(model); } }
验证错误信息
MVC控制器
public class PeopleController : Controller { private IValidator<Person> _validator; private IPersonRepository _repository; public PeopleController(IValidator<Person> validator, IPersonRepository repository) { // Inject our validator and also a DB context for storing our person object. _validator = validator; _repository = personRepository; } public ActionResult Create() { return View(); } [HttpPost] public async Task<IActionResult> Create(Person person) { ValidationResult result = await _validator.ValidateAsync(person); if (!result.IsValid) { // Copy the validation results into ModelState. // ASP.NET uses the ModelState collection to populate // error messages in the View. result.AddToModelState(this.ModelState); // re-render the view when validation failed. return View("Create", person); } _repository.Save(person); //Save the person to the database, or some other logic TempData["notice"] = "Person successfully created"; return RedirectToAction("Index"); } }
验证中执行异步操作,仅手动验证支持
public class Login2RequestValidator : AbstractValidator<Login2Request> {//Login2Request的数据校验类 private readonly IdDbContext _dbContext; public Login2RequestValidator(IdDbContext dbContext) { RuleFor(x => x.Email).NotNull().EmailAddress() .Must(v => v.EndsWith("@qq.com") || v.EndsWith("@163.com")) .WithMessage("只支持QQ和163邮箱"); RuleFor(x => x.Password).NotNull().Length(3, 10) .WithMessage("密码长度必须介于3到10之间") .Equal(x => x.Password2).WithMessage("两次密码必须一致"); _dbContext = dbContext; RuleFor(x => x.UserName).NotNull()
.MustAsync(async (m, cancellation) => await _dbContext.Users.AnyAsync(u => u.UserName == m))
.WithMessage(c => $"用户名{c.UserName}不存在");
} }
2.2 自动验证
//Fluent数据校验 //注册验证器 services.AddScoped<IValidator<Login2Request>, Login2RequestValidator>(); //或者通过程序集注册验证器 //services.AddValidatorsFromAssemblyContaining<Login2RequestValidator>(); services.AddFluentValidationAutoValidation();//注册自动验证 //services.AddFluentValidationClientsideAdapters();
执行 Create 请求之前,会先执行以上设置的验证,验证通过才执行Create方法体
[Route("api/[controller]")] [ApiController] public class FluentValidatorsController : ControllerBase { [Route(nameof(Create))] [HttpPost] public async Task<ActionResult> Create(Login2Request model) { return Ok(model); } }
验证失败
参考:https://docs.fluentvalidation.net/en/latest/aspnet.html