Quickstart: Verwenden Sie Microsoft. Data.SqlClient in einer ASP.NET Core-App

In diesem Quickstart baust du mit Microsoft.Data.SqlClient 7.1.1 eine ASP.NET Core-Minimal-API.

Du startest mit einem leeren Ordner, dem .NET SDK und einer SQL Server- oder Azure SQL-Datenbank, die du von deinem Computer aus erreichen kannst. Am Ende haben Sie eine Web-API, die eine Nachricht zu einer Tabelle hinzufügt und sie per ID zurückliest.

Dabei:

  • Liest seine Verbindungszeichenfolge aus der ASP.NET Core-Konfiguration. Für lokale Entwicklung kommt der Wert von Benutzergeheimnissen, daher bleibt es außerhalb deines Projektordners.
  • Registriert eine Datenklasse mit Abhängigkeitsinjektion.
  • Öffnet und gibt für jede Anfrage eine Verbindung frei, wodurch der Standard-Verbindungspool physische Verbindungen wiederverwenden kann.
  • Gibt das CancellationToken der Anfrage an jeden Datenbankaufruf weiter.

Die App verwendet dieselbe dbo.SqlClientQuickstart Tabelle wie in Quickstart: Verbinden und Abfragen mit Microsoft.Data.SqlClient. Du kannst zuerst einen der beiden Quickstarts machen.

Voraussetzungen

Der aktuelle ASP.NET Core läuft auf .NET, nicht auf dem .NET Framework. Um den Treiber von .NET Framework zu verwenden, siehe .NET Framework-Projekte.

Die Datenbankidentität benötigt die Berechtigung, um sich zu verbinden und eine Tabelle zu erstellen, einzufügen und daraus auszuwählen.

Erstelle das Projekt

Führe in einem leeren Ordner folgende Befehle aus:

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 fügt ein UserSecretsId zur Projektdatei hinzu. ASP.NET Core lädt Benutzergeheimnisse nur, wenn die App in der Umgebung Development läuft, was der Standard für dotnet runist.

Das Erweiterungspaket stellt die Microsoft Entra-Authentifizierungsmodi des Treibers bereit. Wenn deine App nur SQL-Authentifizierung verwendet, kannst du Microsoft.Data.SqlClient.Extensions.Azure weglassen. Wenn du beide Pakete verwendest, achte darauf, dass sie dieselbe Version haben.

Konfigurieren Sie die Verbindung

Speichere die Verbindungszeichenfolge als ConnectionStrings:Quickstart in Benutzergeheimnissen. Benutzergeheimnisse werden in deinem Benutzerprofil gespeichert, nicht im Projektordner, daher werden sie nicht in die Versionsverwaltung eingecheckt. Gib kein Passwort oder keinen Production Connection String in appsettings.json ein.

Wählen Sie einen dieser Ausgangspunkte und ersetzen Sie die Platzhalter. Die Befehle dotnet user-secrets set verwenden einfache Anführungszeichen für PowerShell und Bash. Im Kommandoprompt verwenden Sie stattdessen doppelte Anführungszeichen, da die Eingabeaufforderung einzelne Anführungszeichen als Teil des Schlüssels und des Werts speichert.

Azure SQL mit Microsoft Entra ID

Melden Sie sich mit einer Microsoft Entra-Identität an, die Zugriff auf die Datenbank hat. Für lokale Entwicklung verwenden Sie ein Entwickler-Tool wie die Azure CLI:

az login

Dann speichern Sie den Verbindungszeichenfolge. Kopiere die genauen Server- und Datenbanknamen aus der Azure SQL-Datenbank. Der gleiche Verbindungszeichenfolge funktioniert für SQL-Datenbanken in Microsoft Fabric, wenn man die Server- und Datenbanknamen aus dem SQL-Datenbankelement verwendet, wie im Konsolen-Quickstart beschrieben.

dotnet user-secrets set 'ConnectionStrings:Quickstart' 'Server=tcp:<server>,1433;Database=<database>;Authentication=Active Directory Default;Encrypt=Strict;Connect Timeout=30'

Diese Verbindungszeichenfolge enthält keinen Geheimniswert. Active Directory Default verwendet deine Entwickler-Anmeldung lokal. Wenn Sie auf Azure App Service oder Azure Container Apps deployen, gewähren Sie der verwalteten Identität der App Zugriff auf die Datenbank, ändern Sie den Wert auf Authentication=Active Directory Managed Identity, und setzen Sie ihn in der Konfiguration des Hosts als ConnectionStrings__Quickstart. Für weitere Optionen siehe Microsoft Entra-Authentifizierung mit Microsoft.Data.SqlClient.

Lokaler SQL Server mit SQL-Authentifizierung

Speichere die Verbindungszeichenfolge für eine lokale Entwicklungsinstanz, die kein vertrauenswürdiges Zertifikat hat. Verwenden Sie einzelne Anführungszeichen, um zu verhindern, dass PowerShell und Bash das Zeichen $ im Passwort erweitern.

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 Überspringt die Serverzertifikatsvalidierung. Verwenden Sie es nur mit einer lokalen Entwicklungsinstanz. Für geteilte oder Produktions-SQL Server-Instanzen installieren Sie ein Zertifikat, dem der Client vertraut, und entfernen Sie TrustServerCertificate=true. Weitere Informationen finden Sie unter Verschlüsselungs- und Zertifikatüberprüfung in Microsoft.Data.SqlClient.

Hinzufügen des Codes

Ersetzen Sie den Inhalt von Program.cs durch den folgenden Code:

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;
    }
}

App starten

Starte die App auf einem festen Port:

dotnet run --urls http://localhost:5000

Beim Start erstellt die App die Tabelle, falls sie nicht existiert. Wenn die App bereit ist, enthält die Ausgabe folgende Zeilen:

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

Wenn die App die Datenbank nicht erreichen kann, stoppt sie beim Start und zeigt SqlException an. Für häufige Ursachen siehe Fehlersuche.

Aufrufen der API

Lass die App laufen und öffne ein zweites Terminal. Füge eine Nachricht mit einer POST-Anfrage hinzu und lies sie dann per ID mit einer GET-Anfrage zurück. Wenn die Tabelle bereits Zeilen hat, wie zum Beispiel aus dem Konsolen-Quickstart, ersetze 1 in der GET-Anfrage durch die id, die deine POST-Anfrage zurückgibt.

Für 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 formatiert jede JSON-Antwort als Tabelle. Die erste Zeile ist die 201 Created Antwort auf die POST-Anfrage, und die zweite Zeile ist die GET-Antwort:

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 zeigt createdAt als die Zeichenfolge an, die von der API zurückgegeben wird. PowerShell 7 wandelt es in ein Datum in der lokalen Zeit um, wie zum Beispiel 10/20/2026 7:04:43 PM.

In Windows PowerShell curl ist ein Alias für Invoke-WebRequest, das die Curl-Optionen nicht akzeptiert. Verwenden Sie die PowerShell-Befehle, oder führen Sie curl.exe über die Eingabeaufforderung aus.

Für die Eingabeaufforderung:

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

Die Eingabeaufforderung behandelt einzelne Anführungszeichen nicht als Anführungszeichen, daher verwendet der JSON-Körper doppelte Anführungszeichen, die mit Backslashes maskiert werden. Jeder Befehl druckt die JSON-Antwort aus:

{"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"}

Für 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"}

Deine IDs und Zeitstempel unterscheiden sich. Wenn du zuerst den Konsolen-Quickstart ausgeführt hast, werden die IDs aus dessen Zeilen fortgesetzt. Eine Anfrage nach einer nicht existierenden ID liefert 404 Not Found. Eine leere Nachricht gibt 400 Bad Request zurück.

Drücke Strg+C im ersten Terminal, um die App zu stoppen.

Funktionsweise des Codes

  • Die App registriert MessageStore als Singleton. Er enthält nur den Verbindungszeichenfolge, den er einmal aus IConfiguration liest. Es hält die Verbindung nicht.
  • Jede Methode erstellt ein SqlConnection, öffnet es, führt einen Befehl aus und entsorgt es mit await using. Das Freigeben gibt die physische Verbindung an den Verbindungspool zurück, und die nächste Anfrage verwendet sie wieder. Connection Pooling ist standardmäßig aktiviert, du musst es also nicht konfigurieren. Für Tuning-Optionen siehe SQL Server Connection Pooling mit Microsoft.Data.SqlClient.
  • ASP.NET Core bindet den CancellationToken-Parameter an die Anforderung. Wenn der Client die Verbindung trennt, bricht das Token das Öffnen, den Befehl und das Lesen ab.
  • Die @id und @message Parameter stimmen mit den Spaltentypen und -größen überein. Die API validiert die Nachrichtenlänge, bevor sie den Wert an die Datenbank sendet.
  • OUTPUT INSERTED.Id, INSERTED.Message, INSERTED.CreatedAt gibt die eingefügte Zeile, einschließlich der servergenerierten ID und des Zeitstempels, ohne eine zweite Abfrage zurück.
  • In anderen Umgebungen liest ASP.NET Core denselben ConnectionStrings:Quickstart Schlüssel aus Umgebungsvariablen wie ConnectionStrings__Quickstart, oder von einem anderen Konfigurationsanbieter, wie Azure Key Vault.

Troubleshoot

Fehler oder Symptom Was soll überprüft werden? Mehr erfahren
Set the ConnectionStrings:Quickstart configuration value. Die App hat die Verbindungszeichenfolge nicht gefunden. Führe dotnet user-secrets list im Projektordner aus und prüfe, ob die App in der Umgebung Development läuft. Sichere Speicherung von geheimen App-Daten bei der Entwicklung in ASP.NET Core
System.ArgumentException: Cannot find an authentication provider for 'ActiveDirectoryDefault' Beim Startup Die Verbindungszeichenfolge verwendet einen Active Directory Authentifizierungsmodus, aber das Projekt referenziert Microsoft.Data.SqlClient.Extensions.Azurenicht . Füge das Paket mit derselben Version wie Microsoft.Data.SqlClienthinzu. Die Microsoft Entra-Authentifizierung wechselt in 7.0 auf ein Erweiterungspaket
SqlException beim Start Die App konnte sich nicht verbinden oder die Tabelle erstellen. Die Fehlernummer identifiziert die Ursache, zum Beispiel 18456 für einen fehlgeschlagenen Login. Fehlerbehebung im Konsolen-Schnellstart
415 Unsupported Media Type Die Anfrage setzt Content-Type: application/json nicht. Minimal-APIs: Kurzreferenz
Cannot bind parameter 'Headers' Du hast den curl-Befehl in Windows PowerShell ausgeführt, wobei curlInvoke-WebRequest ausgeführt wird. Verwenden Sie die PowerShell-Befehle in Die API aufrufen. Invoke-RestMethod
''' is an invalid start of a value Du hast den Bash-Curl-Befehl in der Eingabeaufforderung ausgeführt, der die einzelnen Anführungszeichen als Teil des Body sendet. Verwenden Sie die Eingabeaufforderungsbefehle in Aufrufen der API. Ruf die API auf

Bereinigen von Ressourcen

Löschen Sie die Tabelle mit einem beliebigen Abfragetool:

DROP TABLE IF EXISTS dbo.SqlClientQuickstart;

Entferne den gespeicherten Verbindungszeichenfolge. Vom Projektordner aus ausführen:

dotnet user-secrets clear

Dann lösche den Projektordner. Vom Elternordner aus führen Sie in PowerShell folgenden Befehl aus:

Remove-Item -Recurse -Force SqlClientWebQuickstart

Für Bash:

rm -rf SqlClientWebQuickstart

Nächste Schritte