跳至页脚内容
Iron Academy Logo
学习 C#
学习 C#

其他类别

.NET 10 Minimal API中的数据验证

Tim Corey
~10m

Minimal API一直是基于控制器的ASP.NET Core的瘦替代方案,但长期以来它们存在一个显著的缺口:没有内置支持来验证传入数据。 您可以在每个处理程序中手动设置检查,或者依赖于第三方库。 .NET 10通过提供针对查询字符串、头信息和请求体的一级数据注释验证,弥补了这一空缺,且不需额外包。

基于Tim Corey的讲解,此.NET 10 Minimal API深度探讨解释了如何注册验证服务、注释模型类以及避免可能破坏设置的常见访问修饰符陷阱。

设置:一个简单的Minimal API

[0:44 - 1:35] 演示以一个简单的ASP.NET Core Minimal API项目开始,运行在.NET 10上。表面很简单:两个POST端点,每个接受不同的模型。

app.MapPost("/person", (Person person) => Results.Ok(person));
app.MapPost("/login", (LoginModel login) => Results.Ok(login));
app.MapPost("/person", (Person person) => Results.Ok(person));
app.MapPost("/login", (LoginModel login) => Results.Ok(login));

Person 模型包含基本身份字段。 LoginModel 处理凭证:电子邮件地址、密码和确认密码字段。 两者都作为JSON体发送。 此时没有任何输入校验; 该API接收其收到的任何内容,包括空字符串和格式错误的邮箱地址。

Scalar(随.NET 10附带的现代OpenAPI UI)用于直接从浏览器发送测试请求,可以轻松查看API在接线前后的确切返回内容。

注册验证服务

[2:36 - 3:06] 在任何验证属性生效之前,您需要在服务级别选择加入。 在服务注册块中的一个简单调用即可启用对所有Minimal API端点的强制执行:

builder.Services.AddValidation();
builder.Services.AddValidation();

这一行是整个配置步骤。不需添加中间件,也无需挂接到管道阶段。 一旦注册了服务,框架会自动接管。 如果跳过此调用,数据注释属性将存在于模型上,但永远不会被评估,无论其包含什么,请求仍会通过。

记住这一点作为调试的第一步:如果验证没有任何提示地无效,通常是因为缺少 AddValidation()

为类模型添加验证

[3:00 - 3:55] 注册服务后,为基于类的模型添加验证只需为属性加上数据注释属性

public class Person
{
    [Required]
    public string FirstName { get; set; }

    [Required]
    public string LastName { get; set; }
}
public class Person
{
    [Required]
    public string FirstName { get; set; }

    [Required]
    public string LastName { get; set; }
}

在文件顶部添加 System.ComponentModel.DataAnnotations 使用指令后,将 FirstNameLastName 标记为 [Required] 确保它们被验证。 通过 Scalar 发送一个空主体的 POST 请求现在会返回一个带有结构化错误响应的 400 Bad Request

{
  "errors": {
    "FirstName": ["The FirstName field is required."],
    "LastName": ["The LastName field is required."]
  }
}

没有自定义错误处理,没有过滤属性。 框架会自动产生该响应,并在处理程序体执行前运行检查,因此您永远不需要在端点逻辑内防止空值。

将验证应用于记录

[4:29 - 5:30] 相同的属性也适用于C#记录,但语法略有不同,因为记录属性通常在主构造函数中定义,而不是作为单独的成员声明。

public record LoginModel(
    [Required] [EmailAddress] string Email,
    [Required] string Password,
    [Required] string ConfirmPassword
);
public record LoginModel(
    [Required] [EmailAddress] string Email,
    [Required] string Password,
    [Required] string ConfirmPassword
);

构造函数参数上的属性会应用于生成的属性,所以 [Required][EmailAddress] 的行为与在类上完全相同。 发送一个格式错误的邮件请求,例如 "notanemail",现在会返回一个 400 ,识别 Email 字段为无效。

[Compare] 属性也可以用于强制 ConfirmPasswordPassword 匹配。 在记录上,属性目标需要明确指示,因为编译器必须知道您指的是生成的成员,而不是构造函数参数本身:

[property: Compare(nameof(Password))]
string ConfirmPassword
[property: Compare(nameof(Password))]
string ConfirmPassword

[property:] 目标告诉编译器将属性附加到生成的成员而不是参数。 没有此功能,[Compare] 编译但在检查过程中从不运行。 在该上下文中处理记录与类时,这是最棘手的部分:类属性自然接受属性,而记录参数需要对任何在成员级别操作的东西进行明确的目标指定。

公共访问修饰符要求

[7:51 - 9:00] 一个常见的陷阱很容易被忽略,并且在触发时不会产生错误信息。 验证系统使用反射在运行时检查您的模型类型;为了让反射找到一个类型的成员,类型本身必须标记为 public

// Validation will NOT run; the class is internal by default
class Person { ... }

// Validation runs correctly
public class Person { ... }
// Validation will NOT run; the class is internal by default
class Person { ... }

// Validation runs correctly
public class Person { ... }

记录上同样的规则适用。 如果您的模型没有声明访问修饰符,C# 默认为 internal,服务将其完全跳过。 您的端点仍会接收请求,处理程序仍会执行,并且不返回错误; 检查只是无声无息地不作为。

这是ASP.NET Core的行为,不特定于Minimal API,但由于这些项目趋于紧凑,开发人员有时在与 Program.cs 相同的文件中定义模型或内联而不考虑可见性,因此此问题频繁出现。

快速审核项目的方法:任何传递到端点处理程序的模型类型都应显式标记为 public。 如果没有,无论有多少属性也不会让框架启动。

您可以验证的内容

内置数据注释属性涵盖了大多数常见场景,且无需额外工作:

  • [Required] 拒绝空或空值
  • [EmailAddress] 验证电子邮件字符串的格式
  • [Compare] 检查两个属性是否匹配,对密码确认很有用
  • [Range] 强制实施数字或日期边界
  • [StringLength] 限制字符串长度并具有可选的最小值
  • [RegularExpression] 根据自定义模式进行验证

所有这些适用于查询字符串参数、请求头和JSON体。 相同的模型类或记录可以从不同源绑定,而无需更改其任何属性。

结论

[7:46 - end] 注册 AddValidation() 并装饰您的模型后,Minimal APIs 会自动在类和记录中强制输入约束。要在.NET 10中实现此功能,只需调用一次 builder.Services.AddValidation(),使用标准数据注释属性装饰模型属性,并确保每个模型类型都标记为 public

记录上的 [property:] 目标和 public 修饰符要求是唯一的需要注意的问题。 它们易于忽视,产生无声的失败而不是编译错误,所以每当输入检查未作时,请将它们放在检查表上。

观看完整的视频Tim Corey的YouTube上以了解完整的源码演示。

Hero Worlddot related to .NET 10 Minimal API中的数据验证
Hero Affiliate related to .NET 10 Minimal API中的数据验证

分享您的所爱,赚取更多收入

您为使用 .NET、C#、Java、Python 或 Node.js 的开发人员创建内容吗?将您的专业知识转化为额外收入!

钢铁支援团队

我们每周 5 天,每天 24 小时在线。
聊天
电子邮件
打电话给我