快速入門:在 ASP.NET Core 應用程式中使用 Microsoft.Data.SqlClient

在這個快速入門中,你將使用 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

目前的 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

下一步