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

其他类别

.NET 10 Minimal API中的数据验证

[[academy-video-youtube({"vid": "sW_AcN-nD0Y", "start_time": "0", "title": "在.NET 10中的Minimal API进行数据验证", "creator": "Tim Corey", "length": "~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; }
}

在文件顶部添加[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
);

构造函数参数上的属性应用于生成的属性,因此[EmailAddress]的行为与在类上是一样的。 发送一个格式错误的电子邮件请求,例如Email字段为无效。

Password。 在记录上,属性目标需要明确指示,因为编译器必须知道您指的是生成的成员,而不是构造函数参数本身:

[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 APIs特有的,但在这里更常见,因为这些项目往往比较紧凑,开发者有时会在不考虑可见性的情况下内联定义模型或在与Program.cs相同的文件中定义模型。

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

您可以验证的内容

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

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

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

结论

[7:46 - end] 在注册AddValidation()并装饰您的模型后,Minimal APIs会自动在类和记录中强制执行输入约束。要在.NET 10中实现这一点,只需调用public

记录上的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 小时在线。
聊天
电子邮件
打电话给我