在這個快速入門中,你將使用 Microsoft.Data.SqlClient 7.1.1 建構一個 ASP.NET Core 最小 API。
你從一個空資料夾、.NET SDK 和一個可以從電腦存取的 SQL Server 或 Azure SQL 資料庫開始。 最後你會用一個網頁 API,將訊息加入資料表,並透過 ID 讀回該訊息。
在這個過程中,應用程式:
- 從 ASP.NET Core 設定讀取其 連接字串。 在本地開發中,數值來自 User Secrets,因此不會放在專案資料夾裡。
- 使用依賴注入註冊資料類別。
- 為每個請求開啟並釋放連線,讓預設連線池能重用實體連線。
- 將請求的
CancellationToken傳遞給每一次資料庫呼叫。
該應用程式使用與 Quickstart: Connect and query with Microsoft.Data.SqlClient 相同的 dbo.SqlClientQuickstart 表格。 你可以先做任一個快速入門。
Prerequisites
- .NET 10 SDK 或較新且受支援的 .NET SDK。 SDK 可運行於 Windows、Linux 及 macOS 上。
- 一個您可以連線到的資料庫。 要建立一個,請參考 主控台快速入門的前置條件。
-
curl或是 PowerShell 來向 API 發送請求。
目前的 ASP.NET Core 是運行在 .NET 上,而非 .NET 框架。 若要使用 .NET Framework 的驅動程式,請參見 .NET Framework 專案。
資料庫識別需要具備連線,以及建立資料表、向資料表插入資料,並從資料表選取資料的權限。
建立專案
在空資料夾中執行以下指令:
dotnet new web --framework net10.0 --name SqlClientWebQuickstart
cd SqlClientWebQuickstart
dotnet add package Microsoft.Data.SqlClient --version 7.1.1
dotnet add package Microsoft.Data.SqlClient.Extensions.Azure --version 7.1.1
dotnet user-secrets init
dotnet user-secrets init 在專案檔案中新增UserSecretsId。 ASP.NET Core 僅在應用程式於 Development 環境中執行時載入使用者秘密,而這是 dotnet run 的預設值。
擴充套件提供驅動程式的 Microsoft Entra 認證模式。 如果你的應用程式只使用 SQL 認證,可以省略 Microsoft.Data.SqlClient.Extensions.Azure。 使用兩個套件時,保持它們的版本相同。
設定連線
將 連接字串 儲存為 ConnectionStrings:Quickstart,並放在 user secrets 中。 使用者祕密會儲存在你的使用者設定檔裡,而不是專案資料夾,所以它們不會被提交到原始碼控制。 不要將密碼或生產 連接字串 放入 appsettings.json。
選擇其中一個起始點並替換佔位符。
dotnet user-secrets set PowerShell 和 Bash 的指令使用單引號。 在命令提示字元中,請改用雙引號,因為命令提示字元會將單引號視為索引鍵和值的一部分。
Azure SQL with Microsoft Entra ID
請使用有資料庫存取權的 Microsoft Entra 身份登入。 本地開發時,請使用開發工具如 Azure CLI:
az login
然後儲存 連接字串。 從 Azure SQL 資料庫複製精確的伺服器和資料庫名稱。 在 Microsoft Fabric 中,使用 SQL 資料庫項目中的伺服器與資料庫名稱時,相同的 連接字串 也適用於 sql 資料庫,如主控台快速入門所描述。
dotnet user-secrets set 'ConnectionStrings:Quickstart' 'Server=tcp:<server>,1433;Database=<database>;Authentication=Active Directory Default;Encrypt=Strict;Connect Timeout=30'
這個 連接字串 不包含密鑰。
Active Directory Default 會在本機使用你的開發者登入資訊。 當你部署到 Azure App 服務 或 Azure 容器應用程式 時,授與該應用程式的受控識別對資料庫的存取權,將值改為 Authentication=Active Directory Managed Identity,並在主機設定中將其設為 ConnectionStrings__Quickstart。 如需其他選項,請參閱 使用 Microsoft.Data.SqlClient 的 Microsoft Entra 驗證。
使用 SQL 驗證的本機 SQL Server
儲存一個沒有受信任憑證的本地開發實例的 連接字串。 使用單引號來防止 PowerShell 和 Bash 展開密碼中的 $ 字元。
dotnet user-secrets set 'ConnectionStrings:Quickstart' 'Server=tcp:<server>,1433;Database=<database>;User ID=<user-id>;Password=<password>;Encrypt=true;TrustServerCertificate=true;Connect Timeout=30'
Caution
TrustServerCertificate=true 跳過伺服器憑證驗證。 只能用在本地開發實例時使用。 對於共享或生產型 SQL Server 實例,安裝客戶端信任的憑證並移除 TrustServerCertificate=true。 如需詳細資訊,請參閱 Microsoft.Data.SqlClient中的加密和憑證驗證。
新增程式碼
請將 Program.cs 的內容替換為以下代碼:
using System.Data;
using Microsoft.Data.SqlClient;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddSingleton<MessageStore>();
var app = builder.Build();
await app.Services.GetRequiredService<MessageStore>()
.EnsureTableAsync(app.Lifetime.ApplicationStopping);
app.MapPost("/messages", async (
NewMessage input, MessageStore store, CancellationToken cancellationToken) =>
{
if (string.IsNullOrWhiteSpace(input.Text) || input.Text.Length > 200)
{
return Results.BadRequest("Text must be 1 to 200 characters.");
}
Message message = await store.AddAsync(input.Text, cancellationToken);
return Results.Created($"/messages/{message.Id}", message);
});
app.MapGet("/messages/{id:int}", async (
int id, MessageStore store, CancellationToken cancellationToken) =>
await store.GetAsync(id, cancellationToken) is Message message
? Results.Ok(message)
: Results.NotFound());
app.Run();
record NewMessage(string Text);
record Message(int Id, string Text, DateTimeOffset CreatedAt);
sealed class MessageStore(IConfiguration configuration)
{
private readonly string _connectionString =
configuration.GetConnectionString("Quickstart")
?? throw new InvalidOperationException(
"Set the ConnectionStrings:Quickstart configuration value.");
public async Task EnsureTableAsync(CancellationToken cancellationToken)
{
const string sql = """
IF OBJECT_ID(N'dbo.SqlClientQuickstart', N'U') IS NULL
BEGIN
CREATE TABLE dbo.SqlClientQuickstart
(
Id int IDENTITY(1, 1) PRIMARY KEY,
Message nvarchar(200) NOT NULL,
CreatedAt datetimeoffset NOT NULL
CONSTRAINT DF_SqlClientQuickstart_CreatedAt
DEFAULT sysdatetimeoffset()
);
END;
""";
await using var connection = new SqlConnection(_connectionString);
await connection.OpenAsync(cancellationToken);
await using var command =
new SqlCommand(sql, connection) { CommandTimeout = 30 };
await command.ExecuteNonQueryAsync(cancellationToken);
}
public async Task<Message> AddAsync(
string text, CancellationToken cancellationToken)
{
const string sql = """
INSERT INTO dbo.SqlClientQuickstart (Message)
OUTPUT INSERTED.Id, INSERTED.Message, INSERTED.CreatedAt
VALUES (@message);
""";
await using var connection = new SqlConnection(_connectionString);
await connection.OpenAsync(cancellationToken);
await using var command =
new SqlCommand(sql, connection) { CommandTimeout = 30 };
command.Parameters.Add("@message", SqlDbType.NVarChar, 200).Value = text;
await using SqlDataReader reader =
await command.ExecuteReaderAsync(cancellationToken);
await reader.ReadAsync(cancellationToken);
return new Message(
reader.GetInt32(0), reader.GetString(1), reader.GetDateTimeOffset(2));
}
public async Task<Message?> GetAsync(
int id, CancellationToken cancellationToken)
{
const string sql = """
SELECT Id, Message, CreatedAt
FROM dbo.SqlClientQuickstart
WHERE Id = @id;
""";
await using var connection = new SqlConnection(_connectionString);
await connection.OpenAsync(cancellationToken);
await using var command =
new SqlCommand(sql, connection) { CommandTimeout = 30 };
command.Parameters.Add("@id", SqlDbType.Int).Value = id;
await using SqlDataReader reader =
await command.ExecuteReaderAsync(cancellationToken);
return await reader.ReadAsync(cancellationToken)
? new Message(
reader.GetInt32(0), reader.GetString(1), reader.GetDateTimeOffset(2))
: null;
}
}
執行應用程式
在固定連接埠上啟動應用程式:
dotnet run --urls http://localhost:5000
啟動時,如果表格不存在,應用程式會建立該表格。 當應用程式準備好時,輸出內容包括以下幾行:
info: Microsoft.Hosting.Lifetime[14]
Now listening on: http://localhost:5000
info: Microsoft.Hosting.Lifetime[0]
Application started. Press Ctrl+C to shut down.
info: Microsoft.Hosting.Lifetime[0]
Hosting environment: Development
如果應用程式無法存取資料庫,啟動時會因 SqlException 而停止。 常見原因請參見 故障排除。
呼叫 API
讓應用程式繼續運行,然後開啟第二個終端機。 新增一個帶有 POST 請求的訊息,然後用 GET 請求依照 ID 讀回來。 如果表格已經有資料列,例如來自主控台快速入門的資料列,請將 GET 要求中的 1 替換為 POST 要求傳回的 id。
對於 PowerShell:
Invoke-RestMethod -Method Post -Uri http://localhost:5000/messages -ContentType application/json -Body (@{ text = 'Hello from ASP.NET Core' } | ConvertTo-Json)
Invoke-RestMethod http://localhost:5000/messages/1
PowerShell 會將每個 JSON 回應格式化為表格。 第一列是 201 Created 對 POST 請求的回應,第二列是 GET 回應:
id text createdAt
-- ---- ---------
1 Hello from ASP.NET Core 2026-10-21T00:04:43.3588978+00:00
1 Hello from ASP.NET Core 2026-10-21T00:04:43.3588978+00:00
Windows PowerShell 5.1 會將 createdAt 顯示為 API 回傳的字串。 PowerShell 7 將其轉換為當地時間的日期,例如 10/20/2026 7:04:43 PM。
在 Windows PowerShell 中,curl 是 Invoke-WebRequest 的別名,而 Invoke-WebRequest 不接受 curl 選項。 使用 PowerShell 指令,或直接從命令提示字元執行 curl.exe 。
針對命令提示字元:
curl -X POST http://localhost:5000/messages -H "Content-Type: application/json" -d "{\"text\":\"Hello from ASP.NET Core\"}"
curl http://localhost:5000/messages/1
命令提示字元不會把單引號當作引號字元,所以 JSON 主體會使用以反斜線跳脫的雙引號。 每個指令都會印出 JSON 回應:
{"id":1,"text":"Hello from ASP.NET Core","createdAt":"2026-10-21T00:05:15.4936763+00:00"}
{"id":1,"text":"Hello from ASP.NET Core","createdAt":"2026-10-21T00:05:15.4936763+00:00"}
針對 Bash:
curl -X POST http://localhost:5000/messages -H "Content-Type: application/json" -d '{"text":"Hello from ASP.NET Core"}'
curl http://localhost:5000/messages/1
{"id":1,"text":"Hello from ASP.NET Core","createdAt":"2026-10-20T20:44:17.8634925+00:00"}
{"id":1,"text":"Hello from ASP.NET Core","createdAt":"2026-10-20T20:44:17.8634925+00:00"}
你的ID和時間戳記不同。 如果你先跑控制台快速啟動,ID 會從那些資料列繼續。 若請求不存在的 ID,則會回傳 404 Not Found。 空白訊息會傳回 400 Bad Request。
在第一個終端機按 Ctrl+C 停止應用程式。
程式碼運作方式
- 應用程式會將
MessageStore註冊為單例。 它只儲存 連接字串,並只會從IConfiguration讀取一次。 它沒有保持連線。 - 每個方法都會建立一個
SqlConnection,打開它,執行一個指令,並用await using處理它。 Disposing 會將實體連線回傳給連線池,下一個請求會重複使用。 連線池預設是開啟的,所以你不需要特別設定。 關於調整選項,請參閱使用 Microsoft.Data.SqlClient 的 SQL Server 連線池。 - ASP.NET Core 會將
CancellationToken參數繫結至要求。 如果客戶端斷線,權杖會取消開啟作業、指令和讀取。 -
@message和@id參數符合欄位類型與大小。 API 在將值傳送到資料庫前,先驗證訊息長度。 -
OUTPUT INSERTED.Id, INSERTED.Message, INSERTED.CreatedAt回傳插入的列,包括伺服器產生的 ID 與時間戳,無需第二次查詢。 - 在其他環境中,ASP.NET Core 會從環境變數(如
ConnectionStrings:Quickstart)或其他設定提供者(如 Azure Key Vault)讀取相同的ConnectionStrings__Quickstart金鑰。
Troubleshoot
| 錯誤或症狀 | 要檢查的事項 | 更多資訊 |
|---|---|---|
Set the ConnectionStrings:Quickstart configuration value. |
應用程式找不到那個 連接字串。 在專案資料夾執行 dotnet user-secrets list ,並確認應用程式是否能在 Development 環境中運行。 |
開發 ASP.NET Core 應用程式秘密的安全存儲 |
System.ArgumentException: Cannot find an authentication provider for 'ActiveDirectoryDefault' 啟動時 |
連接字串 使用Active Directory認證模式,但專案未參考 Microsoft.Data.SqlClient.Extensions.Azure。 加入與 Microsoft.Data.SqlClient 相同版本的封包。 |
Microsoft Entra 認證在 7.0 版本中移至擴充套件套件 |
SqlException 啟動時 |
應用程式無法連線或建立資料表。 錯誤編號標示原因,例如登入失敗的 18456。 | 主控台快速入門中的疑難排解 |
415 Unsupported Media Type |
請求未設定 Content-Type: application/json。 |
基本 API 快速參考 |
Cannot bind parameter 'Headers' |
你在 Windows PowerShell 裡執行了 curl 指令,其中 curl 會執行 Invoke-WebRequest. 請使用 Call the API 裡的 PowerShell 指令。 |
Invoke-RestMethod |
''' is an invalid start of a value |
你在命令提示字元執行了 Bash curl 指令,它會將單引號作為要求本文的一部分傳送。 請使用 「呼叫 API」中的命令提示字元指令。 | 呼叫 API |
清理資源
用任何查詢工具刪除資料表:
DROP TABLE IF EXISTS dbo.SqlClientQuickstart;
移除儲存的 連接字串。 在專案資料夾中執行:
dotnet user-secrets clear
然後刪除專案資料夾。 從父資料夾中,請執行以下 PowerShell 指令:
Remove-Item -Recurse -Force SqlClientWebQuickstart
針對 Bash:
rm -rf SqlClientWebQuickstart