跳到主要内容

4.6 模型绑定与输入校验

模型绑定负责把 HTTP 请求中的路由、查询字符串、Header 和 Body 转换为 C# 参数。输入校验负责在业务逻辑执行前拒绝非法数据。

学习目标

  • 能区分路由参数、查询参数和请求体绑定。
  • 能为请求 DTO 添加校验规则。
  • 能返回稳定的 400 错误响应。
  • 能理解前端校验和后端校验的职责差异。

应用场景

  • GET /todos?completed=false&page=1 读取查询参数。
  • GET /todos/{id} 读取路由参数。
  • POST /todos 从 JSON Body 读取创建请求。
  • 对标题长度、必填字段和分页范围做校验。

核心概念

数据来源示例适合内容
Route/todos/{id}资源标识
Query?page=1筛选、排序、分页
BodyJSON创建或更新的复杂对象
HeaderAuthorization认证、追踪、客户端信息

案例:分页查询请求

app.MapGet("/todos", async (
[AsParameters] TodoQuery query,
TodoService service,
CancellationToken cancellationToken) =>
{
if (query.Page < 1 || query.PageSize is < 1 or > 100)
{
return Results.BadRequest(new {message = "分页参数不合法"});
}

var result = await service.GetPageAsync(query, cancellationToken);
return Results.Ok(result);
});

public sealed record TodoQuery(
bool? Completed,
int Page = 1,
int PageSize = 20);

示例:创建请求校验

public sealed record CreateTodoRequest(string Title, string? Description)
{
public IReadOnlyDictionary<string, string[]> Validate()
{
var errors = new Dictionary<string, string[]>();

if (string.IsNullOrWhiteSpace(Title))
{
errors["title"] = ["标题不能为空"];
}
else if (Title.Length > 120)
{
errors["title"] = ["标题不能超过 120 个字符"];
}

if (Description?.Length > 500)
{
errors["description"] = ["备注不能超过 500 个字符"];
}

return errors;
}
}

重点难点

  • 请求 DTO 是外部输入边界,不应直接复用数据库实体。
  • 前端校验只提升体验,后端校验才是安全边界。
  • 校验错误要包含字段级信息,方便前端表单展示。
  • 分页、排序字段和筛选条件都要设置上限和白名单。

常见误区

误区推荐做法
直接把 Entity 作为请求体使用专门 Request DTO
只校验必填,不限制长度同时校验长度、范围和格式
前端做了校验,后端就省略后端永远重新校验外部输入

练习

  • 给任务列表查询增加 sortBy 白名单。
  • 创建任务时校验标题和备注长度。
  • 设计字段级错误格式并让前端展示。

延伸阅读

  • ASP.NET Core 模型绑定。
  • Minimal API 参数绑定。
  • FluentValidation。