一、今日目标

  1. 掌握 Attribute 路由[Route]/[HttpGet]/[HttpPost]
  2. 熟练绑定参数:FromBody / FromQuery / FromRoute
  3. 会用 DataAnnotations 做模型验证
  4. 能独立写出:带完整校验的增删改查接口

二、必背面试题 + 标准答案

1. ASP.NET Core 路由有哪两种?

答案:

  • 传统路由:app.MapControllerRoute()
  • 特性路由(Attribute Routing):控制器 / 方法上加 [HttpGet]/[Route]
  • WebAPI 推荐特性路由,更灵活、语义清晰

2. FromBody / FromQuery / FromRoute 区别?

答案:

  • [FromRoute]:从 URL 路径取(/api/user/{id}
  • [FromQuery]:从 URL 查询参数取(?id=1&name=xx
  • [FromBody]:从请求体取(JSON 格式,POST/PUT 专用
  • 注意:一个 Action 只能有一个 FromBody

3. 模型验证流程是什么?

答案:

  1. 模型绑定自动完成
  2. 框架自动验证 DataAnnotations
  3. 通过 ModelState.IsValid 判断是否通过
  4. 返回 ValidationProblem() 或自定义错误

4. 常用验证特性有哪些?

答案:

[Required] 必填
[MaxLength] / [MinLength] 长度
[Range] 数值范围
[Phone] 手机号
[EmailAddress] 邮箱
[RegularExpression] 正则
[Compare] 比较两个字段(如确认密码)

5. 模型验证失败怎么统一返回?

答案:

  • .NET 6/7/8 默认:自动返回 400 + 错误详情
  • 也可手动判断 ModelState.IsValid 自定义返回格式

6. [ApiController] 有什么用?

答案:

  • 自动启用 特性路由
  • 自动 模型验证,失败直接返回 400
  • 简化参数绑定推断
  • WebAPI 必须加

7. 路由模板中 [controller]/[action] 是什么?

答案:

  • [controller] = 控制器类名去掉 Controller
  • [action] = 方法名
  • 方便统一路由模板

三、核心语法速记

[ApiController]
[Route("api/[controller]")]
public class UserController : ControllerBase
{
    [HttpGet("{id}")]
    public IActionResult Get([FromRoute] int id) { ... }

    [HttpPost]
    public IActionResult Add([FromBody] UserDto dto) { ... }

    [HttpGet]
    public IActionResult Search([FromQuery] string name) { ... }
}

public class UserDto
{
    [Required(ErrorMessage = "姓名不能为空")]
    public string Name { get; set; }

    [Range(1, 130, ErrorMessage = "年龄不合法")]
    public int Age { get; set; }
}

四、Day11 独立练习(无代码提示,自己完整写)

练习名称:用户信息管理 API(完整校验)

需求

  1. 创建 .NET 8 WebAPI 项目

  2. 创建一个模型类 UserCreateDto,并加上验证:

    • Name:必填,长度 2~20
    • Age:必填,范围 1~130
    • Phone:手机号格式
    • Email:邮箱格式
    • Password:必填,最小长度 6
    • ConfirmPassword:必填,必须和 Password 相同
  3. 写 3 个接口:

    1. GET /api/user/{id}

      • 根据 id 查询用户
      • id 从路由获取
    2. POST /api/user

      • 添加用户
      • 参数从 FromBody 获取
      • 必须做模型验证
      • 验证不通过自动返回错误
      • 通过返回成功信息
    3. GET /api/user

      • 分页查询用户
      • 参数:pageIndex(int)、pageSize(int)
      • 从 Query 取

强制要求

  • 使用 特性路由
  • 正确使用 FromRoute / FromQuery / FromBody
  • 完整 模型验证特性
  • 控制器加 [ApiController]
  • 代码结构规范、命名规范

五、练习代码:

User.cs

    public class User
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public int Age {  get; set; }
        public string Phone {  get; set; }
        public string Email { get; set; }
        public string Password { get; set; }
    }

DataDemo.cs

public class DataDome 
{
    public static List<User> users = new List<User>()
    {
        new User() { Id = 1,Name="Lily",Age=18,Phone="17785693236",Email="10524429@qq.com",Password="123456" },
        new User() { Id = 2,Name="John",Age=19,Phone="17785663836",Email="10525529@qq.com",Password="123456" },
        new User() { Id = 3,Name="Jack",Age=20,Phone="17785611136",Email="10529929@qq.com",Password="123456" },
        new User() { Id = 4,Name="Mike",Age=16,Phone="17785622236",Email="10524889@qq.com",Password="123456" },
    };
}

UserCreateDto.cs

public class UserCreateDto
{        
    [Required(ErrorMessage ="名字不能为空")]
    [Length(2,20, ErrorMessage ="名字长度在2~20")]
    public string Name {  get; set; }

    [Required(ErrorMessage ="年龄不能为空")]
    [Range(1,130,ErrorMessage ="年龄不合法")]
    public int Age {  get; set; }

    //自定义特性:允许电话号码为空,在不为空的情况下再去验证格式
    [Attritudes.Phone]
    public string Phone {  get; set; } = string.Empty;

    [EmailAddress]
    public string Email { get; set; } =string.Empty;

    [Required(ErrorMessage ="密码不能为空")]
    [MinLength(6,ErrorMessage ="最小长度6")]
    public string Password {  get; set; }

    [Compare("Password",ErrorMessage ="两次密码不相同")]
    public string ConfirmPassword {  get; set; }

}

PhoneAttribute.cs

[AttributeUsage(AttributeTargets.Property)]
public class PhoneAttribute : ValidationAttribute
{
    protected override ValidationResult IsValid(object value, ValidationContext validationContext)
    {
    
        if (value == null || string.IsNullOrEmpty(value.ToString()))
            return ValidationResult.Success; // 如果值为null,认为是有效的
   
        // 定义电话号码的正则表达式
        string pattern = @"^1[3-9]\d{9}$"; // 正则表达式模式
        if (!Regex.IsMatch(value.ToString(), pattern))
            return new ValidationResult("电话号码格式不正确。");

        return ValidationResult.Success; // 验证成功
    }
}

UserController.cs

 [ApiController]
 [Route("api/[controller]")]
 public class UserController:ControllerBase
 {
     [HttpGet("{id}")]
     public IActionResult GetUser([FromRoute] int id) //不是必须加[FromRoute],但显式使用 [FromRoute] 可提高代码可读性和明确性 ‌
     {
         User user=DataDome.users.FirstOrDefault(u=>u.Id == id);

         if (user == null) 
             return NotFound();
         else
             return Ok(user);
     }

     [HttpPost]
     public IActionResult AddUser([FromBody]UserCreateDto dto) 
     {
         if (!ModelState.IsValid) 
         {
             return BadRequest(ModelState);
         }
         else
         {
             User user=new User();
             user.Id = DataDome.users.MaxBy(u => u.Id).Id + 1;
             user.Name=dto.Name;
             user.Email=dto.Email;
             user.Phone=dto.Phone;
             user.Password=dto.Password;
             user.Age=dto.Age;

             DataDome.users.Add(user);

             return Ok("添加成功");
         }
     }

     [HttpGet]
     public IActionResult QueryUsers([FromQuery]int pageIndex, int pageSize) 
     {
         List<User> users= DataDome.users.Skip((pageIndex - 1) * pageSize).Take(pageSize).ToList();
         return Ok(users);
     }
 }

Program.cs

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllers();
var app = builder.Build();

app.UseHttpsRedirection();

app.MapControllers();
app.Run();

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐