本系列专栏基于杨中科老师的《ASP.NET Core技术内幕与项目 实战》,本人记录梳理的学习笔记,有部分的增补和省略。更全面系统的讲解,请看杨老师的视频课:【.NET教程,.Net Core视频教程,杨中科主讲】。
一、数据校验
数据校验是接口开发的第一道防线,用于校验前端/客户端传入的请求参数合法性,避免非法数据入库、业务逻辑异常。ASP.NET Core 提供内置校验方案,同时支持FluentValidation第三方库实现更灵活、解耦的校验逻辑。
1. 内置数据校验
(1)核心特性
ASP.NET Core内置数据校验基于System.ComponentModel.DataAnnotations命名空间,通过特性标签标注模型属性,实现自动校验,无需编写额外逻辑,简单场景开箱即用。
(2)常用校验特性
-
Required\]:必填字段,禁止为null/空字符串;
-
RegularExpression\]:正则表达式自定义校验;
-
StringLength\]:字符串长度限制;
-
CustomValidationAttribute:自定义校验特性;
-
IValidatableObject:模型级自定义校验。
(3)使用示例
cs
// 模型类标注校验特性
public class LoginRequest
{
[Required(ErrorMessage = "邮箱不能为空")]
[EmailAddress(ErrorMessage = "邮箱格式不合法")]
public string Email { get; set; }
[Required(ErrorMessage = "密码不能为空")]
[StringLength(10, MinimumLength = 3, ErrorMessage = "密码长度3-10位")]
public string Password { get; set; }
}
// Controller中自动校验
[ApiController]
[Route("api/[controller]")]
public class UserController : ControllerBase
{
[HttpPost("login")]
public IActionResult Login(LoginRequest request)
{
// 内置自动校验,校验失败返回400
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
return Ok("登录成功");
}
}
(4)内置校验的缺陷
- 违反单一职责原则:校验规则与模型类强耦合,模型既要承载数据,又要管理校验逻辑,不利于维护;
- 灵活性差:复杂校验(如业务规则校验、跨属性联动校验)需编写大量自定义代码,语法繁琐;
- 复用性低:相同校验规则无法跨模型复用,需重复编写;
- 异步校验支持弱:内置校验难以实现异步校验(如校验用户名是否已存在)。
2. FluentValidation
FluentValidation是.NET生态最流行的第三方校验库,采用Fluent API流式语法,将校验逻辑与模型解耦,支持异步校验、依赖注入、规则复用,完美弥补内置校验的缺陷。
(1)核心优势
- 解耦模型与校验逻辑,符合单一职责原则;
- 流式语法简洁易懂,可读性、可维护性极强;
- 支持同步/异步校验、自定义校验、规则复用;
- 完美适配ASP.NET Core DI,支持注入服务实现业务校验;
- 自定义错误消息,适配多语言、个性化提示。
(2)使用方法
步骤1:安装NuGet包
bash
Install-Package FluentValidation.AspNetCore
// .NET CLI
dotnet add package FluentValidation.AspNetCore
步骤2:Program.cs注册FluentValidation
cs
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllers();
// 注册FluentValidation,自动扫描程序集注册校验器
builder.Services.AddFluentValidation(fv =>
{
// 自动注册当前程序集所有继承AbstractValidator的校验类
Assembly assembly = Assembly.GetExecutingAssembly();
fv.RegisterValidatorsFromAssembly(assembly);
// 关闭内置DataAnnotations校验,避免冲突
fv.DisableDataAnnotationsValidation = true;
});
var app = builder.Build();
app.MapControllers();
app.Run();
步骤3:编写请求模型类
cs
// 纯数据模型,无任何校验特性,实现解耦
public record Login2Request(string Email, string Password, string Password2);
步骤4:编写校验器类(核心)
校验器继承AbstractValidator<T>,在构造函数中通过流式语法配置校验规则,支持多条件校验、自定义校验、错误消息定制。
cs
public class Login2RequestValidator : AbstractValidator<Login2Request>
{
public Login2RequestValidator()
{
// 邮箱校验:非空+格式+域名限制
RuleFor(x => x.Email)
.NotNull().WithMessage("邮箱不能为空")
.EmailAddress().WithMessage("邮箱格式不合法")
.Must(v => v.EndsWith("@qq.com") || v.EndsWith("@163.com"))
.WithMessage("仅支持QQ、163邮箱注册");
// 密码校验:非空+长度+两次密码一致
RuleFor(x => x.Password)
.NotNull().WithMessage("密码不能为空")
.Length(3, 10).WithMessage("密码长度必须介于3-10位")
.Equal(x => x.Password2).WithMessage("两次输入密码不一致");
// 确认密码非空校验
RuleFor(x => x.Password2)
.NotNull().WithMessage("确认密码不能为空");
}
}
步骤5:Controller中使用
cs
[ApiController]
[Route("api/[controller]")]
public class UserController : ControllerBase
{
[HttpPost("register")]
public IActionResult Register(Login2Request request)
{
// FluentValidation自动校验,校验失败返回400
return Ok("注册校验通过");
}
}
二、依赖注入与异步校验
实际业务中常需校验数据唯一性(如用户名、邮箱是否已存在),FluentValidation支持在校验器中注入服务,实现异步数据库校验。
1.注入服务至校验器
cs
public class Login2RequestValidator : AbstractValidator<Login2Request>
{
private readonly AppDbContext _dbCtx;
// 构造函数注入EF Core上下文(Scoped服务,FluentValidation自动适配)
public Login2RequestValidator(AppDbContext dbCtx)
{
_dbCtx = dbCtx;
RuleFor(x => x.Email)
.NotNull()
.EmailAddress()
.MustAsync(CheckEmailExistsAsync)
.WithMessage(c => $"邮箱{c.Email}已被注册,请更换");
}
// 异步校验:校验邮箱是否已存在
private async Task<bool> CheckEmailExistsAsync(string email, CancellationToken cancellationToken)
{
// 不存在返回true,校验通过;存在返回false,校验失败
return !await _dbCtx.Users.AnyAsync(u => u.Email == email, cancellationToken);
}
}
2.异步校验要点
- 使用MustAsync方法实现异步校验,替代同步Must;
- 校验方法需返回Task<bool>,true代表校验通过,false代表校验失败;
- 支持传递CancellationToken,适配异步取消操作;
- 错误消息支持动态拼接参数,个性化提示更友好。
总结
- 数据校验是接口安全的基础。简单场景可使用 .NET 内置的 DataAnnotations 快速实现。
- 企业级、复杂业务场景强烈推荐使用 FluentValidation ,它解耦校验逻辑、支持异步与依赖注入,代码更优雅、可维护性更强,是 ASP.NET Core 开发的最佳实践。