加了[required]没报错是因为验证未触发:必须通过框架绑定(如[frombody])才能激活验证管道;手动赋值、缺少validateallproperties=true、属性无public get或json名称不匹配均会导致跳过验证。

加了[Required]却没报错?不是注解失效,是验证根本没跑起来。
验证不触发:绑定方式错了
ModelState.IsValid 为 true 不代表验证通过,很可能压根没验证——因为模型不是由框架绑定的。
- ✅ 正确写法:
public IActionResult Create([FromBody] User user),框架自动调用Validator.TryValidateObject并填充ModelState - ❌ 错误写法:
var user = new User(); user.Name = Request.Form["name"];,此时[Required]完全被跳过 - Web API 中若控制器继承
ControllerBase,必须确保参数带[FromBody]或[FromForm],否则反序列化后不进验证管道
[Required] 对 int/DateTime 总是通过?类型默认值在捣鬼
[Required] 只检测“是否为 null 或空字符串”,而 int 默认是 0,DateTime 默认是 DateTime.MinValue,它们永远“有值”。
- 想让数值字段必填 → 改成可空类型:
public int? Age { get; set; },再加[Required] - 想限制日期非默认值 → 用
[Range(typeof(DateTime), "1900-01-01", "2100-12-31")],或手动检查user.BirthDate != DateTime.MinValue - 前端传
{"age": null},后端仍是int age = 0—— 这是 JSON.NET 反序列化行为,不是验证问题
验证通过但结果不对:参数漏传或属性不可读
即使用了正确绑定,Validator.TryValidateObject 仍可能跳过某些属性,导致 [Required] 不生效。
- 漏掉
validateAllProperties = true参数:手动验证时必须传第四个参数true,否则只校验“有值”的属性,空字符串或null的字段直接跳过 - 属性没有 public getter:
private set没问题,但get必须是 public,否则ValidationContext读不到值 - JSON 字段名和 C# 属性名不匹配(如前端传
user_name,后端是UserName)→ 验证器找不到对应属性,相当于没加注解。用[JsonProperty("user_name")]或全局配置SnakeCaseNamingStrategy
业务规则别塞进 DataAnnotations
[Required]、[StringLength] 这类注解只管结构合法性,查数据库唯一性、校验权限、判断状态流转等都得在服务层做。
- 邮箱是否已注册?不能靠注解 → 在 service 里查库,失败时调
ModelState.AddModelError("Email", "该邮箱已被使用") - 结束时间必须晚于开始时间?用
IValidatableObject实现Validate方法,或迁移到FluentValidation - 错误键名必须和属性名完全一致(区分大小写),否则前端收不到对应字段错误信息
最常被忽略的一点:DataAnnotations 是声明式标签,不是自动执行的逻辑。它依赖绑定管道或显式调用才起作用;而一旦脱离这个上下文,比如在 DTO 转 Entity 后再验证,就只剩一纸空文。










