知識與實務

商業實務・AI 應用・人才發展

AI 工作實務

ASP.NET Core API 實作:用依賴注入與 8 個 HTTP 檢查建立清楚的回應契約

一個 API 能回傳資料,還不足以讓其他系統放心串接。這份 .NET 10 練習從案件查詢出發,將路由、服務依賴與輸入驗證分開,並用正常、找不到、格式錯誤和邊界輸入檢查實際 HTTP 回應。

ASP.NET 分層伺服器連接用戶端與資料庫

一個 API 能回傳資料,還不足以讓其他系統放心串接。這份 .NET 10 練習從案件查詢出發,將路由、服務依賴與輸入驗證分開,並用正常、找不到、格式錯誤和邊界輸入檢查實際 HTTP 回應。

專題編輯:Derek Chou|AI 技術與架構編輯 · 文件核對 2026.11.09

ASP.NET 分層伺服器連接用戶端與資料庫

先確定你說的是哪一代 ASP.NET

舊專案文件只寫「ASP.NET」,不足以判斷它的部署方式與相容性。ASP.NET Core 是現代 .NET 的 Web 框架,可以建立 HTTP API;舊有 .NET Framework 應用與它不能只靠改專案名稱就完成移轉。盤點時應查看目標 framework、NuGet 依賴、作業系統相依功能,以及現有資料庫與身分系統。

本文採 net10.0。截至 2026 年 11 月 9 日,Microsoft 的支援頁將 .NET 10 列為 LTS,並要求支援期內持續跟進修補更新;LTS 不是永遠不必升級,也不是每個第三方套件都獲得相同保證。.NET 官方支援政策

這篇解決的是「如何把一個小 API 的回應契約做清楚」。它沒有聲稱 ASP.NET Core 是所有企業的最佳選擇,也不以供應商名氣替代安全驗收。若團隊已有 C# 能力和 .NET 整合需求,可以從此練習觀察分層;若主要資產是 Python,選型仍應比較維護人才、依賴、測試與營運成本。

一次請求經過哪些地方?

最小 API 可以用三層來理解:Host 管理伺服器、設定與服務;路由把 HTTP 路徑對到處理函式;服務處理應用邏輯。本例讓 GET /cases/1 透過 ICaseService 查詢一筆合成案件,找得到回 200,找不到回 404。

依賴注入讓 endpoint 宣告它需要 ICaseService,實際實作由啟動時的註冊提供。這方便替換儲存來源及撰寫測試,但不會自動產生授權規則。本例用沒有可變狀態的 singleton 服務;如果改成具 request scope 的資料庫存取,就必須重新確認生命週期,不能把 scoped 服務直接塞進 singleton。Microsoft DI 文件

Middleware 則在請求管線處理橫切責任,例如例外處理、認證與授權。本文沒有加入登入管線,這個缺項會明確留在驗收界線中。建立一個 /health 路由,不等於其他 endpoint 已受到保護。

步驟一:準備可建置的專案

需要 .NET 10 SDK 和 Python 3,並具有在本機啟動測試程序的權限。Python 只負責送 HTTP 請求及檢查結果,不是 API 的執行環境。先記錄 dotnet --info、dotnet --version 和 python3 --version,避免把 SDK、runtime 與專案 target framework 混為一談。

下載完整練習檔,內含 CaseApi.csproj、Program.cs、verify.py 與操作說明。專案檔為:

<Project Sdk="Microsoft.NET.Sdk.Web">
  <PropertyGroup>
    <TargetFramework>net10.0</TargetFramework>
    <Nullable>enable</Nullable>
    <ImplicitUsings>enable</ImplicitUsings>
  </PropertyGroup>
</Project>

進入練習目錄後執行:

dotnet build -c Release

預期產生 bin/Release/net10.0/CaseApi.dll。若出現 SDK 不支援目標 framework,先核對 SDK,而不是任意改成更舊 framework 掩蓋相容性問題。若有 restore 或來源連線錯誤,保存完整錯誤並確認套件來源;本文沒有要求使用私人套件或真實金鑰。

步驟二:把案件查詢接到服務

Program.cs 的查詢部分如下:

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddSingleton<ICaseService, InMemoryCaseService>();
var app = builder.Build();

app.MapGet("/health", () => Results.Ok(new { status = "ok" }));
app.MapGet("/cases/{id:int}", IResult (int id, ICaseService service) =>
    service.Find(id) is { } item
        ? Results.Ok(item)
        : Results.NotFound());

public interface ICaseService { CaseItem? Find(int id); }
public record CaseItem(int Id, string Title);
public class InMemoryCaseService : ICaseService
{
    public CaseItem? Find(int id) =>
        id == 1 ? new CaseItem(1, "示範案件資料確認") : null;
}

這段是便於閱讀的摘錄;完整檔案還包含下一步的 POST endpoint 和最後的 app.Run(),請以附件整份檔案建置。資料只有固定案件 1,沒有客戶、授信決策或真實金融業務。InMemory 在此甚至不保存新增狀態,因此重啟程序不會有資料持久化問題可供驗收。

Minimal API 和 Controller 都能建立 HTTP API;本文採 Minimal API 是為了讓小範例的路由與回應直接可見。如果團隊已有 Controller 慣例、複雜擴充需求或大型 API 組織方式,不應因示範程式較短就全面改寫。Microsoft API 建構方式說明

步驟三:定義輸入不合格時的回應

附件另有 POST /cases/validate。它只驗證標題,沒有建立案件;這個名稱刻意讓呼叫者看出功能範圍:

app.MapPost("/cases/validate", IResult (CaseInput item) =>
    string.IsNullOrWhiteSpace(item.Title) || item.Title.Length > 100
        ? Results.BadRequest(new { error = "title_required_max_100" })
        : Results.Ok(new { accepted = true, title = item.Title.Trim() }));

public record CaseInput(string? Title);

檢查規則是標題不能缺漏、不能全為空白,而且輸入字串的 Length 不超過 100。C# 的 string.Length 計算 UTF-16 code units,不是人眼看到的文字數量;若產品規格要求「100 個顯示字元」,需要另外定義 grapheme cluster 的計算。本例把邊界寫清楚,避免 UI 和 API 對長度有不同解釋。String.Length 官方說明

合法輸入會去除首尾空白再回傳;空字串、缺少 title 或 101 個 ASCII 字元都應回 400。這只是此樣本明確採用的業務規則,並非宣稱 Minimal API 自動替所有 C# record 完成了完整商業驗證。真實系統還要考慮資料範圍、重複提交、使用者可操作的資源,以及資料庫約束。

另有一個容易誤解的差異:/cases/not-an-int 不符合 {id:int} 路由,因此本例預期 404;/cases/validate 成功匹配 POST 路由後,內容不合格才回 400。路由 constraint 用於匹配,不應被描述成通用輸入驗證器。Microsoft routing 文件

步驟四:用真實 HTTP 執行八個檢查

在練習目錄執行:

python3 verify.py

驗證腳本重新 build,選擇一個本機空閒 port,以 127.0.0.1 啟動編譯後的 DLL,再發送請求。它不只呼叫 C# 函式,也實際經過 HTTP listener、路由與 JSON 序列化,最後結束自己啟動的程序。

檢查預期結果
GET /health200,status=ok
GET /cases/1200,id 與示範標題完全相符
GET /cases/999404
GET /cases/not-an-int404,路由 constraint 未匹配
POST 空 title400
POST 101 個 ASCII 字元400
POST 空 JSON 物件400
POST " demo "200,回傳 "demo"

成功時輸出 ASP_NET_LAB_PASS 並保存 evidence/result.json;任一 assertion 不符就以非零狀態結束。若程序啟動失敗,先看 evidence/server.log,區分 build 失敗、port 問題與回應契約不符,不要刪掉失敗案例湊出綠燈。

這份證據能支持什麼,還不能支持什麼?

八個檢查支援的結論是:在記錄的 SDK/runtime 與測試環境中,這組小型 API 的指定請求得到預期回應。它沒有測試登入、角色隔離、資料庫、併發壓力、TLS、反向代理或跨主機部署,也沒有證明任何企業正式服務可用。

下一步若接入資料庫,應先把固定的 ICaseService 換成清楚定義的資料存取實作,確認 DI lifetime,再測試不存在資料、資料庫逾時及交易失敗。若加入登入,應新增匿名、一般使用者和無權讀取他人案件等測試,不能只測合法管理員一路成功。

對技術主管來說,可以要求每次 API 變更附上三件事:端點契約的差異、這次新增或改變的失敗案例,以及實際測試版本。這比「已用框架內建功能」更容易確認交付範圍。對工程師來說,則應把外部依賴和部署組態留在可追溯設定中,不把開發機上的隱藏狀態當成團隊基準。

資料來源與素材說明

官方文件核對日:2026 年 11 月 9 日。這是一個原創的合成案件範例;Derek Chou 是技術專題策展角色,不代表具名真人實測或金融專業審核。圖片為架構概念示意,非 Visual Studio 或正式應用截圖。完整測試範圍、命令及版本留在附件紀錄中。

內容提供:TARAISG。本文由 AI 協助整理與查核;專題編輯為天地人 AI 編輯計畫的策展角色,未宣稱經具名人工或專家審核。

AI 生成內容

本文由 TARAISG(TIANDIREN AI SOLUTION GROUP)使用 AI 模型產生正文、整理來源並設計實務工具。方法依據與限制列於文末;案例為明確標示的教學假設。未有具名紀錄時,不宣稱經人工或專家審核。

查看內容製作與更正說明

立即領!558元學習投資折抵金

能力投資季。立即領取 558 元學習金!全站線上課立即折抵。只需填寫 Email,即可輕鬆獲得,先領起來,不要錯過!

立即領!559元學習投資折抵金

能力投資季。立即領取 559 元學習金!全站線上課立即折抵。只需填寫 Email,即可輕鬆獲得,先領起來,不要錯過!

立即領!579 元學習金

學習,看見新可能。 10/14 前領取 579 元折抵金,解鎖數百堂高品質線上課程,提升職場競爭力與專業技能。只需填寫Email,即可輕鬆獲得,投資自己從現在開始!

立即領!599 元學習金

學習,帶來新可能。 09/09 前領取 558 元折抵金,解鎖數百堂高品質線上課程,提升職場競爭力與專業技能。只需填寫Email,即可輕鬆獲得,投資自己從現在開始!

立即領!558 元學習金

學習,發現新大陸。 8/29 前領取 558 元折抵金,解鎖數百堂高品質線上課程,提升職場競爭力與專業技能。只需填寫Email,即可輕鬆獲得,投資自己從現在開始!

立即領!559 元學習金

學習,連結新亮點。 8/14 前領取 559 元折抵金,解鎖數百堂高品質線上課程,提升職場競爭力與專業技能。只需填寫Email,即可輕鬆獲得,投資自己從現在開始!

立即領!555 元學習金

學習,發現更多視角。 6/14 前領取 555 元折抵金,解鎖數百堂高品質線上課程,提升職場競爭力與專業技能。只需填寫Email,即可輕鬆獲得,投資自己從現在開始!

立即領!556 元學習金

學習,累積無限可能。 5/29 前領取 556 元折抵金,解鎖數百堂高品質線上課程,提升職場競爭力與專業技能。只需填寫Email,即可輕鬆獲得,投資自己從現在開始!

立即領!557 元學習金

學習,讓我們發現未曾想像的可能!5/14 前領取 557 元折抵金,解鎖數百堂高品質線上課程,提升職場競爭力與專業技能。只需填寫Email,即可輕鬆獲得,投資自己從現在開始!

立即領!579 元折抵金

知識就是力量,專業成就未來!3/18 前領取 579 元課程折抵金,解鎖數百堂高品質線上課程,提升職場競爭力與專業技能。只需填寫Email,即可輕鬆獲得,投資自己從現在開始!

年終學習金

年終之餘用學習投資自己!填入 Email ,立即領取 588 元年終學習金!數百堂線上課程立即折抵,先領取收藏起來!