在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 的內建驗證管道以用於最小 API,並配置 Swagger 以便在 API 啟動時自動啟動。 該集涵蓋了從儲存過程到測試端點的完整迴圈,包括 .NET 開箱即用返回的驗證錯誤響應格式。 如果您正在關注 Linux 上的 C# 系列或第一次向最小 API 新增寫入操作,這篇文章將逐步講解每個步驟。
建立插入記錄型別
[1:46 - 4:43] 在構建端點之前,Tim 建立了一個代表插入請求形狀的資料傳輸物件。現有的 TicketModel 包括資料庫自動生成的字段,例如 Id 和 CreatedDate。 在 POST 主體中接受這些會被忽略或導致衝突,因此單獨型別將輸入範圍限定為僅需呼叫者提供的字段。
public record TicketInsertRecord(string Title, string Description, int Priority);public record TicketInsertRecord(string Title, string Description, int Priority);using record 而不是 class 是一個刻意的選擇。記錄預設提供基於值的相等性和不可變性,這符合請求載荷的語義:資料到達、驗證、傳遞到資料庫,且中間從不修改。 三個屬性(標題、描述、優先順序)直接映射到 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 全部端點並執行它。 新票出現在列表中,與原始測試記錄並排。
測試還揭示了沒有驗證的差距:發送空標題、缺少描述或優先順序為 99 都以 204 成功,資料庫接受 API 發送的任何內容。 這種差距促成了下一節的動力。
新增內建驗證
[14:43 - 18:28] 自 .NET 10 起,最小 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] 確保該字段存在且不為空。 [MinLength(1)] 防止空字串通過必填檢查(因為空字串技術上不為空)。 [Range(1, 5)] 將優先順序約束在有效等級中。 這些屬性是 ASP.NET MVC 控制器多年間使用的相同 System.ComponentModel.DataAnnotations 型別,但現在已能在最小 API 中工作,無需額外的中介軟體。
保存並重新啟動後,Tim 發送了一個帶空標題和優先順序為 10 的請求。響應回來是結構化的錯誤主體:
{
"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 專案的 Properties/launchSettings.json,向 HTTPS 配置檔新增了 launchUrl 屬性:
{
"profiles": {
"https": {
"launchUrl": "swagger"
}
}
}下次啟動時,瀏覽器將直接開啟到 Swagger UI,而不是預設頁面。 這會每次除錯迴圈節省幾秒鐘,並且在整個開發會話中積累起來。
結論
[20:09 - 20:31] 向最小 API 新增 POST 端點涉及建立一個專用的輸入記錄,將其映射到帶有集合 URL 的 MapPost,並將記錄作為參數物件調用儲存過程。 .NET 10 中的驗證需要一個服務註冊和記錄屬性上的標準資料註解屬性。 框架自動處理 400 響應格式化。
系列導航: 本文是 Linux 上的 C# 系列構建 Tiny Ticket 應用的一部分。上一篇:新增 Get By ID 端點。 下一篇:新增 PUT 更新端點。
範例提示:當您的插入儲存過程返回新記錄的 ID 時,將返回從 Results.NoContent() 更改為 Results.Created($"/api/tickets/{newId}", result),以便給呼叫者一個帶位置標頭的 201 狀態,他們可以依據該標頭獲取建立的資源。
在他的 YouTube Channel 上觀看完整影片,獲得有關在 Linux 上的 C# 系列中構建寫入端點的更多見解。

