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

其他类别

在Linux上为.NET Aspire添加带验证的POST插入端点

[[academy-video-youtube({"vid": "oAMMHR8kKnw", "start_time": "0", "title": "在Linux上的.NET Aspire中添加带验证的POST插入端点", "creator": "Tim Corey", "length": "20m 31s"})]]

从API中读取数据只是故事的一半。 到最后,每个应用程序都需要接收新记录,这意味着构建一个POST端点来接收请求体,验证输入,将它持久化到数据库,并返回一个有意义的状态代码。 在原型开发过程中跳过验证步骤很有诱惑力,但接受未经验证输入的生产API会成为损坏数据的来源,比预防更难清理。

在他的视频"在Linux上的.NET Aspire中添加带验证的POST插入端点"中,Tim Corey为Tiny Ticket API添加了一个插入端点,创建了一个专用的输入记录类型,连接.NET的内置验证管道用于Minimal API,并在API启动时自动配置Swagger启动。 此集涵盖从存储过程到测试端点的完整周期,包括.NET默认返回的验证错误响应格式。 如果您正在关注Linux上的C#系列或首次添加写操作到Minimal API,这篇文章将带您逐步完成每一步。

创建插入记录类型

[1:46 - 4:43] 在创建端点之前,Tim 创建了一个数据传输对象,表示插入请求的结构。现有的CreatedDate等字段。 在POST主体中接受这些内容要么会被忽略,要么会引起冲突,因此一个单独的类型将输入限定为只有调用者应提供的字段。

public record TicketInsertRecord(string Title, string Description, int Priority);
public record TicketInsertRecord(string Title, string Description, int Priority);

使用class是一个深思熟虑的选择。记录默认提供基于值的等价性和不可变性,这符合请求负载的语义:数据到达、经过验证、传递到数据库,并且在此过程中从不修改。 这三个属性(Title、Description、Priority)直接映射到spTickets_Insert存储过程的参数。

映射POST端点

[4:43 - 9:51] 定义记录类型后,端点注册遵循与GET 路由相同的模式,但使用MapPost并将请求正文绑定到插入记录:

app.MapPost("/api/tickets", async (TicketInsertRecord ticket, IDbConnection db) =>
{
    await db.SaveDataAsync("spTickets_Insert", ticket);
    return Results.NoContent();
});
app.MapPost("/api/tickets", async (TicketInsertRecord ticket, IDbConnection db) =>
{
    await db.SaveDataAsync("spTickets_Insert", ticket);
    return Results.NoContent();
});

请注意,路径是/api/tickets,没有ID段,符合REST 约定,其中POST 到集合URL会创建一个新资源。 处理程序调用存储过程,并将整个ticket对象作为参数包传递。 Dapper按名称映射记录的属性到SQL参数。

返回Results.NoContent()发送204状态码。 Tim解释了原因:插入成功,但在响应体中没有任何有意义的内容可以返回。 一些API返回新创建的对象,状态为201 Created,并带有指向新资源的Location头,这是一个有效的替代方案。对于Tiny Ticket项目,204保持简单。

通过Swagger测试插入

[9:51 - 14:43] Tim启动项目并导航到Swagger。 POST端点出现,带有与TicketInsertRecord属性匹配的请求正文模式。 他填写了一个测试票据,其中包含标题、描述和优先级,然后执行请求。

返回了204,确认插入成功。 为了验证数据确实已持久化,他切换到GET all端点并执行它。 新票据出现在列表中,与原始测试记录并列。

测试还揭示了没有验证的差距:发送一个空标题、缺失描述或优先级为99的请求都成功并返回204。数据库接受API发送的任何内容。 这个差距促成了下一节的来临。

添加内置验证

[14:43 - 18:28] 从.NET 10开始,Minimal API支持内置的验证管道,该管道从输入类型读取数据注解属性,在处理程序执行之前拒绝无效请求。 Tim通过两步将其连接起来。

首先,在Program.cs中注册验证服务。 这一行激活整个管道:

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

注册服务后,框架会在处理程序运行之前检查每个请求体的验证属性。 第二步是用每个字段必须满足的规则注释插入记录:

public record TicketInsertRecord(
    [Required, MinLength(1)] string Title,
    [Required] string Description,
    [Range(1, 5)] int Priority
);
public record TicketInsertRecord(
    [Required, MinLength(1)] string Title,
    [Required] string Description,
    [Range(1, 5)] int Priority
);

[Required]确保字段存在且不为null。 [MinLength(1)]防止空字符串通过必要的检查(因为空字符串在技术上不为null)。 [Range(1, 5)]将优先级限制在有效的级别。 这些属性是ASP.NET MVC控制器多年以来使用的相同System.ComponentModel.DataAnnotations类型,但现在无需附加中间件即可在最小API中工作。

保存并重新启动后,Tim发送一个空标题和优先级为10的请求。响应返回为400 Bad Request,带有结构化错误体:

{
    "errors": {
        "Title": ["The Title field is required."],
        "Priority": ["The field Priority must be between 1 and 5."]
    }
}

验证管道在处理程序运行之前短路请求,因此无效数据不会到达数据库。 错误响应遵循RFC 7807问题详情格式,API消费者可以以编程方式解析。

启动时自动启动Swagger

[19:44 - 20:31]一个小的生活质量提升为这一集结尾。 每次Tim启动API时,他都必须手动在浏览器URL中输入/swagger。 为了自动化这一点,他打开API项目的launchUrl属性:

{
    "profiles": {
        "https": {
            "launchUrl": "swagger"
        }
    }
}

下一次启动时,浏览器将直接打开Swagger UI而非默认页面。 这节省了调试周期中的几秒钟,这在整次开发会话中累加。

结论

[20:09 - 20:31] 在最小API中添加POST端点涉及创建一个专用的输入记录,将其映射到集合URL的MapPost,并以记录作为参数对象调用存储过程。 .NET 10中的验证需要一个服务注册和记录属性上的标准数据注解属性。 框架会自动处理400响应的格式化。

系列导航:本文是Tiny Ticket应用建设过程中Linux上的C#系列的一部分。上一个:添加按ID获取端点。 下一个:添加PUT更新端点

示例提示:当您的插入存储过程返回新记录的ID时,将返回值从Results.Created($"/api/tickets/{newId}", result),以向调用者提供带有位置头的201状态,他们可以跟随该头以获取创建的资源。

观看完整视频在他的YouTube频道上,获得更多关于在Linux上的C#系列中构建写端点的见解。

Hero Worlddot related to 在Linux上为.NET Aspire添加带验证的POST插入端点
Hero Affiliate related to 在Linux上为.NET Aspire添加带验证的POST插入端点

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

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

钢铁支援团队

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