C# Web开发教程(十二)数据校验机制
内置数据校验机制
- 框架内置了对数据校验的支持
- 在System.ComponentModel.DataAnnotations这个命名空间下:
- 比如[Required]、[EmailAddress] 、[RegularExpression] 、 CustomValidationAttribute、IValidatableObject等待
- demo演示
// LoginRequest1.cs
using System.ComponentModel.DataAnnotations;
namespace WebApplicationAboutDataValidate
{
public class LoginRequest1
{
[Required]
[EmailAddress]
[RegularExpression("^.*@(qq|163)\\.com$", ErrorMessage = "只支持QQ和163邮箱")]
public string Email { get; set; }
[Required]
[StringLength(10, MinimumLength = 3)]
public string Password { get; set; }
[Compare(nameof(Password2), ErrorMessage = "两次密码必须一致")]
public string Password2 { get; set; }
}
}
- 测试效果
- 提交如下字段
{
"email": "user@example.com",
"password": "string",
"password2": "string"
}
- 返回:
{
"type": "https://tools.ietf.org/html/rfc7231#section-6.5.1",
"title": "One or more validation errors occurred.",
"status": 400,
"traceId": "00-840f868ea1c247a51f659d0092a68ae9-a7f61df6b9a99cd3-00",
"errors": {
"Email": [
"只支持QQ和163邮箱"
]
}
}
- 提交如下字段:
{
"email": "user@qq.com",
"password": "string123",
"password2": "string"
}
- 返回:
{
"type": "https://tools.ietf.org/html/rfc7231#section-6.5.1",
"title": "One or more validation errors occurred.",
"status": 400,
"traceId": "00-e635ad8de5684008becbe67b9be814e8-fea276f49eca5228-00",
"errors": {
"Password2": [
"两次密码必须一致"
]
}
}
内置数据校验机制的问题点
- 校验规则都是和模型类耦合在一起,违反“单一职责原则”;
- 很多常用的校验都需要编写自定义校验规则,而且写起来麻烦。
数据校验机制第三方库--- FluentValidation1
-
FluentValidation在很多项目中都可以使用(比如WinForm,WPF) -
注意事项:
FluentValidation可以和内置的数据校验机制混用,但最好不要这么干,避免混淆和未知的坑. -
安装库
- Install-Package Microsoft.EntityFrameworkCore.Tools -Version 6.0.0
- Install-Package FluentValidation.AspNetCore -Version 10.3.4 // 这里不要搞成6的版本,有坑
Program.cs注册一下
// LoginRequest1.cs
using System.ComponentModel.DataAnnotations;
namespace WebApplicationAboutDataValidate
{
public class LoginRequest1
{
public string Email { get; set; }
public string UserName { get; set; }
public string Password { get; set; }
public string Password2 { get; set; }
}
}
// AddNewUserRequestValidator.cs---自定义校验器
using FluentValidation;
namespace WebApplicationAboutDataValidate
{
public class AddNewUserRequestValidator : AbstractValidator<LoginRequest1>
{
public AddNewUserRequestValidator()
{
RuleFor(x => x.Email).NotNull().EmailAddress().WithMessage("邮箱必须是合法地址").Must(x => x.EndsWith("@163.com") || x.EndsWith("@qq.com")).WithMessage("支持163或者QQ邮箱");
RuleFor(x => x.UserName).NotNull().Length(3,10);
RuleFor(x => x.Password).Equal(x => x.Password2).WithMessage("两次密码必须一致");
}
}
}
// Program.cs
......
builder.Services.AddSwaggerGen();
// 注册全局验证器
builder.Services.AddFluentValidation(fv => {
Assembly assembly = Assembly.GetExecutingAssembly();
fv.RegisterValidatorsFromAssembly(assembly);
});
var app = builder.Build();
......
// 测试接口
using Microsoft.AspNetCore.Mvc;
namespace WebApplicationAboutDataValidate.Controllers
{
[ApiController]
[Route("[controller]/[action]")]
public class ValidateDataController : ControllerBase
{
[HttpPost]
public ActionResult Login(LoginRequest1 req)
{
return Ok(req);
}
}
}
- 测试: https://localhost:7263/ValidateData/Login
{
"email": "string",
"userName": "string",
"password": "string",
"password2": "string111"
}
- 返回结果
{
"type": "https://tools.ietf.org/html/rfc7231#section-6.5.1",
"title": "One or more validation errors occurred.",
"status": 400,
"traceId": "00-7666f45f49e7afcab428d6bbd34d5bfb-1d6ed200ab8f73e3-00",
"errors": {
"Email": [
"邮箱必须是合法地址",
"支持163或者QQ邮箱"
],
"Password": [
"两次密码必须一致"
]
}
}
FluentValidation+DI高级功能---依赖注入: 可以通过构造方法来向校验器注入服务
using FluentValidation;
using Microsoft.AspNetCore.Identity;
namespace WebApplicationAboutDataValidate
{
public class AddNewUserRequestValidator : AbstractValidator<LoginRequest1>
{
public AddNewUserRequestValidator(UserManager<LoginRequest1> userManager)
{
RuleFor(x => x.Email).NotNull().EmailAddress().WithMessage("邮箱必须是合法地址").Must(x => x.EndsWith("@163.com") || x.EndsWith("@qq.com")).WithMessage("支持163或者QQ邮箱");
RuleFor(x => x.UserName).NotNull().Length(3,10).MustAsync(async (x,_) => await userManager.FindByNameAsync(x) == null).WithMessage("用户名已存在");
//RuleFor(x => x.Password).Equal(x => x.Password2).WithMessage("两次密码必须一致");
RuleFor(x => x.Password).Equal(x => x.Password2).WithMessage(x => $"密码{x.Password}和{x.Password2}不一致");
}
}
}
核心要点总结
- 分离关注点:FluentValidation 将校验逻辑从模型类中分离出来
- 链式编程:使用流畅的接口设计,代码可读性更强
- 灵活性强:支持复杂的业务逻辑校验,包括异步校验
- 错误信息定制:可以灵活定制错误消息,支持动态消息
- 依赖注入支持:可以在校验器中注入服务,实现更复杂的业务校验

浙公网安备 33010602011771号