Day11:路由 + Model 验证(WebAPI 核心必考)
·
一、今日目标
- 掌握 Attribute 路由(
[Route]/[HttpGet]/[HttpPost]) - 熟练绑定参数:
FromBody/FromQuery/FromRoute - 会用 DataAnnotations 做模型验证
- 能独立写出:带完整校验的增删改查接口
二、必背面试题 + 标准答案
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. 模型验证流程是什么?
答案:
- 模型绑定自动完成
- 框架自动验证 DataAnnotations
- 通过
ModelState.IsValid判断是否通过 - 返回
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(完整校验)
需求
-
创建 .NET 8 WebAPI 项目
-
创建一个模型类
UserCreateDto,并加上验证:- Name:必填,长度 2~20
- Age:必填,范围 1~130
- Phone:手机号格式
- Email:邮箱格式
- Password:必填,最小长度 6
- ConfirmPassword:必填,必须和 Password 相同
-
写 3 个接口:
-
GET /api/user/{id}
- 根据 id 查询用户
- id 从路由获取
-
POST /api/user
- 添加用户
- 参数从 FromBody 获取
- 必须做模型验证
- 验证不通过自动返回错误
- 通过返回成功信息
-
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();
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐

所有评论(0)