.NET Core 数据验证(最全实战指南)

.NET Core 内置**强大的模型验证(Model Validation)**机制,基于 DataAnnotations 数据注解 + 自动验证,无需手写大量判断代码,是 API、MVC 项目的标准验证方案。

我给你整理最常用、最实用的用法,直接复制就能用!


一、最核心用法:DataAnnotations 注解(推荐)

直接在模型类 / DTO 上加特性,框架会自动验证,无需手动判断。

1. 常用验证特性(背会这 10 个就够用)

csharp 复制代码
// 必填
[Required(ErrorMessage = "用户名不能为空")]

// 字符串长度
[StringLength(50, MinimumLength = 2, ErrorMessage = "长度 2-50 位")]

// 范围(数字)
[Range(1, 120, ErrorMessage = "年龄必须在 1-120 之间")]

// 正则表达式(手机号、身份证等)
[RegularExpression(@"^1[3-9]\d{9}$", ErrorMessage = "手机号格式不正确")]

// 邮箱格式
[EmailAddress(ErrorMessage = "邮箱格式不正确")]

// 密码复杂度
[DataType(DataType.Password)]

// 比较两个字段(确认密码)
[Compare("Password", ErrorMessage = "两次密码不一致")]

// 电话号码
[Phone(ErrorMessage = "电话号码格式错误")]

// 最大/最小值
[MaxLength(100)]
[MinLength(6)]

// 自定义错误消息
[Required(ErrorMessage = "请输入姓名")]

二、完整实战示例(DTO + 自动验证)

1. 定义 DTO(带验证)

csharp 复制代码
using System.ComponentModel.DataAnnotations;

namespace YourProject.DTOs
{
    public class CreateUserDto
    {
        [Required(ErrorMessage = "用户名不能为空")]
        [StringLength(20, MinimumLength = 2, ErrorMessage = "用户名长度 2-20 位")]
        public string UserName { get; set; }

        [Required(ErrorMessage = "密码不能为空")]
        [MinLength(6, ErrorMessage = "密码至少 6 位")]
        public string Password { get; set; }

        [Required(ErrorMessage = "确认密码不能为空")]
        [Compare(nameof(Password), ErrorMessage = "两次密码不一致")]
        public string ConfirmPassword { get; set; }

        [EmailAddress(ErrorMessage = "邮箱格式不正确")]
        public string Email { get; set; }

        [RegularExpression(@"^1[3-9]\d{9}$", ErrorMessage = "手机号格式错误")]
        public string Phone { get; set; }

        [Range(1, 120, ErrorMessage = "年龄必须在 1-120 之间")]
        public int Age { get; set; }
    }
}

三、API 中自动使用验证(无需手写判断)

1. 控制器写法(.NET Core 自动验证)

csharp 复制代码
using Microsoft.AspNetCore.Mvc;
using YourProject.DTOs;

[Route("api/[controller]")]
[ApiController]  // 关键:加了这个,框架会自动验证模型
public class UserController : ControllerBase
{
    [HttpPost("create")]
    public IActionResult Create(CreateUserDto dto)
    {
        // 重点:加了 [ApiController],如果验证失败,框架会自动返回 400 错误!
        // 这里直接写业务逻辑即可

        return Ok("创建成功");
    }
}

2. 自动返回的错误格式(前端直接用)

json 复制代码
{
  "type": "https://tools.ietf.org/html/rfc9110#section-15.5.1",
  "title": "One or more validation errors occurred.",
  "status": 400,
  "errors": {
    "UserName": ["用户名不能为空"],
    "Phone": ["手机号格式错误"],
    "Age": ["年龄必须在 1-120 之间"]
  }
}

四、手动获取验证结果(兼容老项目)

如果没加 [ApiController],可以手动判断:

csharp 复制代码
[HttpPost("create")]
public IActionResult Create(CreateUserDto dto)
{
    // 手动判断验证是否通过
    if (!ModelState.IsValid)
    {
        // 返回验证错误
        return BadRequest(ModelState);
    }

    return Ok("创建成功");
}

五、自定义验证(满足特殊业务规则)

如果内置注解不够用,可以自定义验证特性

示例:验证"用户名不能包含 admin"

csharp 复制代码
using System.ComponentModel.DataAnnotations;

public class NoAdminAttribute : ValidationAttribute
{
    protected override ValidationResult? IsValid(object? value, ValidationContext validationContext)
    {
        var userName = value?.ToString();
        
        if (userName != null && userName.Contains("admin"))
        {
            return new ValidationResult("用户名不能包含 admin");
        }

        return ValidationResult.Success;
    }
}

使用:

csharp 复制代码
[NoAdmin]  // 自定义验证
public string UserName { get; set; }

六、全局统一验证返回格式(企业级)

默认的 400 返回格式太丑,我们可以统一成前端友好格式

Program.cs 中配置:

csharp 复制代码
builder.Services.AddControllers()
    .ConfigureApiBehaviorOptions(options =>
    {
        // 自定义验证失败返回结果
        options.InvalidModelStateResponseFactory = context =>
        {
            // 提取所有错误信息
            var errors = context.ModelState
                .Where(e => e.Value.Errors.Count > 0)
                .ToDictionary(
                    k => k.Key,
                    v => v.Value.Errors.Select(e => e.ErrorMessage).ToArray()
                );

            // 统一返回格式
            var result = new
            {
                Code = 400,
                Message = "参数验证失败",
                Errors = errors
            };

            return new BadRequestObjectResult(result);
        };
    });

返回效果:

json 复制代码
{
  "Code": 400,
  "Message": "参数验证失败",
  "Errors": {
    "UserName": ["用户名不能为空"],
    "Phone": ["手机号格式错误"]
  }
}

七、服务层(Service)验证

如果想在业务层做验证,可以手动调用:

csharp 复制代码
using System.ComponentModel.DataAnnotations;

public class UserService
{
    public void CreateUser(CreateUserDto dto)
    {
        // 手动验证
        var validationContext = new ValidationContext(dto);
        var validationResults = new List<ValidationResult>();

        bool isValid = Validator.TryValidateObject(dto, validationContext, validationResults, true);

        if (!isValid)
        {
            // 处理错误
            throw new ArgumentException("参数错误");
        }
    }
}

核心总结(必看)

  1. 最简单 :给 DTO 加 [Required][EmailAddress] 等注解
  2. 最方便 :控制器加 [ApiController],自动验证、自动返回错误
  3. 最规范:全局配置统一错误返回格式
  4. 扩展:内置不够用 → 写自定义验证特性

总结:.NET Core 验证 = 数据注解 + 自动校验,零冗余代码!

相关推荐
卷无止境5 小时前
智能体开发环境ADE浅析,编程工具的下一次范式跃迁
后端·python
码事漫谈7 小时前
DeepSeek 这波操作很凶
后端
Bs_MoneyMagnet8 小时前
基于springboot+vue的医疗健康便民服务平台的设计与实现 源码+文档
java·vue.js·spring boot·后端·spring
子兮曰10 小时前
Bun v1.4.1 深度解析:从 Zig 到 Rust,一场 11 天、64 个 AI 代理的语言迁徙
前端·后端·bun
IT_陈寒12 小时前
Vue的computed属性竟然坑了我一把
前端·人工智能·后端
薛定谔的悦12 小时前
一套储能 BMS 的充电电流限值,是怎么一步步算出来的
后端
逐米时代13 小时前
AR加知识库提升一次修复率
后端·restful
王码码203513 小时前
Go语言CGO:Go与C交互
后端·golang·go·接口
PC2005-cloud14 小时前
DSH 白嫖指南:接入 Command Code Go、WorkBuddy 与 Trae 的免费额度
开发语言·后端·golang
vx-程序开发14 小时前
【计算机毕设】基于Spring Boot的古城景区管理系统88564
java·数据库·spring boot·后端·spring·elasticsearch·课程设计