Koppla upp dig mot en datakälla med Microsoft. Data.SqlClient

SqlConnectionrepresenterar en logisk koppling till SQL Server, Azure SQL Database, Azure SQL Managed Instance eller SQL-databas i Microsoft Fabric. När objektet öppnas får man en fysisk anslutning från anslutningspoolen när en sådan är tillgänglig. Att stänga eller göra sig av med den återställer den fysiska kopplingen till poolen.

Använd kortlivade SqlConnection objekt för arbetsenheter. Håll inte en global anslutning öppen för applikationen.

Prerequisites

  • .NET 10 SDK eller en senare stödd .NET SDK. SDK:n körs på Windows, Linux och macOS. Den kompilerar också .NET Framework-versionen av varje exempel, som endast körs på Windows och kräver .NET Framework 4.8.1.
  • En databas som du kan ansluta till i SQL Server, Azure SQL Database, Azure SQL Managed Instance eller SQL-databas i Microsoft Fabric.

Skapa projektet

Microsoft. Data.SqlClient 7.0 och senare versioner behöver versionsmatchade Microsoft.Data.SqlClient.Extensions.Azure paket för drivrutinslevererade Microsoft Entra ID-autentiseringslägen, såsom služba Active Directory Default. Om din app endast använder SQL-autentisering eller Windows-integrerad autentisering kan du utelämna det.

I en tom mapp, kör dessa kommandon:

dotnet new console --framework net10.0 --name SqlClientConnect
cd SqlClientConnect
dotnet add package Microsoft.Data.SqlClient --version 7.1.1
dotnet add package Microsoft.Data.SqlClient.Extensions.Azure --version 7.1.1

Kodexemplen i denna artikel läser anslutningssträngen från miljövariabeln SQL_CONNECTION_STRING. Ställ in före du kör ett sample. För reťazec pripojenia-format, se Connection strings.

Varje prov utom transaktionsprovet är ett komplett program. För att köra en av dem, ersätt innehållet i Program.cs med den och kör sedan dotnet run. Transaktionsexemplet är ett fragment för din egen metod. .NET-fliken använder toppnivåsatser, implicita using direktiv och await using. Fliken .NET Framework använder C# 7.3, som inte har await using, så den använder using satser istället.

Öppna en anslutning

Anrop OpenAsync i asynkron kod eller Open i synkron kod. Deklarera anslutningen med await using eller using så att den frigörs när koden lämnar scopen, även när ett undantag kastas.

Med Windows integrerad autentisering använder anslutningen processens identitet. För en webbapplikation eller en Windows-tjänst är det applikationspoolen eller tjänstekontot, inte den inloggade användaren. För mer information, se Val av autentiseringsmönster.

Detta kompletta program öppnar en anslutning, rapporterar varje tillståndsändring och läser två serveregenskaper:

using Microsoft.Data.SqlClient;

string connectionString =
    Environment.GetEnvironmentVariable("SQL_CONNECTION_STRING")
    ?? throw new InvalidOperationException(
        "Set the SQL_CONNECTION_STRING environment variable.");

await using var connection = new SqlConnection(connectionString);
connection.StateChange += (_, e) =>
    Console.WriteLine($"State: {e.OriginalState} to {e.CurrentState}");

await connection.OpenAsync();

await using var command = new SqlCommand(
    """
    SELECT CAST(SERVERPROPERTY('Edition') AS nvarchar(128)),
           CAST(SERVERPROPERTY('EngineEdition') AS int);
    """,
    connection);

await using (SqlDataReader reader = await command.ExecuteReaderAsync())
{
    await reader.ReadAsync();
    Console.WriteLine($"Edition: {reader.GetString(0)}");
    Console.WriteLine($"EngineEdition: {reader.GetInt32(1)}");
}

Jämfört med SQL Server 2025 Enterprise-utgåvan är resultatet:

State: Closed to Open
Edition: Enterprise Edition: Core-based Licensing (64-bit)
EngineEdition: 3
State: Open to Closed

Den sista raden visas när anslutningen avslutas i slutet av programmet.

Stäng och frigör anslutningar

Stäng alltid en anslutning när du är klar med den så att den fysiska anslutningen återvänder till anslutningspoolen. satserna using och await using frigör anslutningen när koden lämnar blocket, inklusive när ett ohanterat undantag kastas. Du kan också ringa Close eller Dispose direkt. Close och Dispose har samma effekt på den fysiska kopplingen.

Följ dessa regler:

  • Frigör dataläsare och kommandon före anslutningen som äger dem.
  • Lita inte på skräpinsamling för att lämna tillbaka en anslutning till poolen. En anslutning som hamnar utanför scope utan att stängas returneras inte snabbt, och poolen kan få slut på anslutningar.
  • Anropa inte Close eller Dispose på en anslutning, en läsare eller något annat hanterat objekt i en klassfinaliserare. En finalizer bör endast släppa ohanterade resurser som dess klass äger direkt. För mer information, se Garbage Collection.
  • Efter Close, kan du anropa Open igen på samma objekt. Efter Dispose, skapa ett nytt objekt.

När pooling är aktiverat returneras en anslutning till poolen när den stängs, utan att nätverksanslutningen stängs. Poolen återställer sessionstillståndet när anslutningen återanvänds. För mer information, se SQL Server connection pooling.

Använd asynkrona API:er

Använd asynkrona anrop för nätverksbundet databasarbete i webbservrar, tjänster, användargränssnitt och arbetare:

  • OpenAsync(cancellationToken)
  • ExecuteNonQueryAsync(cancellationToken)
  • ExecuteReaderAsync(cancellationToken)
  • ExecuteScalarAsync(cancellationToken)
  • ReadAsync(cancellationToken)

Starta inte en ny operation på en anslutning, ett kommando eller en läsare innan den nuvarande asynkrona operationen är klar.

Använd annullering och tidsgränser

Skicka anroparens anrop CancellationToken genom varje asynkront databasanrop. Avbokning ber drivrutinen att stoppa det väntande arbetet, men slutförandet är inte garanterat omedelbart. Fortsätt använda begränsade anslutnings- och kommandotimeouts.

Dessa kontroller har olika omfattningar:

Control Scope
Connect Timeout Etablering av anslutning, eller väntan på en poolad anslutning
SqlCommand.CommandTimeout En kommandoexekvering
CancellationToken Annullering av en asynkron operation som begärts av anroparen

Att en tidsgräns överskrids eller en annullering sker innebär inte att servern återställde en åtgärd. Använd en transaktion när flera ändringar måste genomföras eller återställas som en enhet, och fatta beslut om återförsök utifrån operationens idempotens och transaktionens utfall.

Spåra anslutningsstatus

Egenskapen State returnerar en ögonblicksbild från uppräkningen ConnectionState .

Stat/län Meaning
Closed Den logiska kopplingen är inte öppen.
Connecting En öppen operation pågår.
Open Den logiska kopplingen är öppen.

Händelsen StateChange aktiveras när tillståndet ändras. Argumentet StateChangeEventArgs har två egenskaper:

  • OriginalState är tillståndet före förändringen.
  • CurrentState är tillståndet efter ändringen.

Drivrutinen rapporterar övergångarna Closed till Open och Open till Closed, som exemplet i Öppna en anslutning visar. Förlita dig inte på att observera Executing, Fetching, eller Broken som applikationens livscykelfaser.

Använd det inte State som hälsokontroll före varje kommando. Nätverket kan gå sönder efter vilken kontroll som helst. Kör operationen och hantera det resulterande undantaget. Använd StateChange för diagnostik, inte för att samordna samtidiga arbetsuppgifter.

Ta emot informationsmeddelanden

Händelsen InfoMessage returnerar meddelanden som servern skickar utan att ge något fel. Dessa meddelanden inkluderar PRINT utdata, RAISERROR meddelanden med en allvarlighetsgrad på 10 eller lägre, samt servervarningar. Fel med en allvarlighetsgrad på 11 eller högre höjer istället en SqlException a. För allvarlighetsgrader, se Database Engine-felnivåer.

Händelsehanteraren tar emot ett SqlInfoMessageEventArgs objekt. Dess Errors-egenskap innehåller en samling SqlError-objekt. Varje del innehåller meddelandenummer, text, allvarlighetsgradsklass, procedur och radnummer.

using Microsoft.Data.SqlClient;

string connectionString =
    Environment.GetEnvironmentVariable("SQL_CONNECTION_STRING")
    ?? throw new InvalidOperationException(
        "Set the SQL_CONNECTION_STRING environment variable.");

await using var connection = new SqlConnection(connectionString);
connection.InfoMessage += (_, e) =>
{
    foreach (SqlError error in e.Errors)
    {
        Console.WriteLine(
            $"Message {error.Number}, severity {error.Class}: {error.Message}");
    }
};

await connection.OpenAsync();

await using var command = new SqlCommand(
    """
    PRINT 'Starting the batch.';
    RAISERROR('Processed %d rows.', 10, 1, 42);
    """,
    connection);

await command.ExecuteNonQueryAsync();

Resultatet är:

Message 0, severity 0: Starting the batch.
Message 50000, severity 0: Processed 42 rows.

Servern rapporterar en RAISERROR allvarlighetsgrad på 10 som klass 0, så SqlError.Class visar 0 för båda meddelandena.

Hantera användarfel som informationsmeddelanden

Som standard rapporterar drivrutinen ett fel med en allvarlighetsgrad på 11 eller högre genom att kasta en SqlException. Detta undantag innebär inte att servern stoppade batchen. Många fel, inklusive RAISERROR med en svårighetsgrad på 16, låter servern köra de återstående satserna, så senare satser kan ändra data även när din kod fångar undantaget. För att ta emot dessa fel som meddelanden istället för undantag, sätt FireInfoMessageEventOnUserErrors till true. Drivrutinen skickar sedan fel med allvarlighetsgrad 16 eller lägre till händelsen InfoMessage i stället för att generera ett undantag. Denna egenskap ändrar hur drivrutinen rapporterar fel. Det ändrar inte vilka instruktioner servern kör.

using Microsoft.Data.SqlClient;

string connectionString =
    Environment.GetEnvironmentVariable("SQL_CONNECTION_STRING")
    ?? throw new InvalidOperationException(
        "Set the SQL_CONNECTION_STRING environment variable.");

await using var connection = new SqlConnection(connectionString)
{
    FireInfoMessageEventOnUserErrors = true,
};
connection.InfoMessage += (_, e) =>
{
    foreach (SqlError error in e.Errors)
    {
        Console.WriteLine(
            $"Message {error.Number}, severity {error.Class}: {error.Message}");
    }
};

await connection.OpenAsync();

await using var command = new SqlCommand(
    """
    RAISERROR('Row 7 failed validation.', 16, 1);
    SELECT 'The batch continued.';
    """,
    connection);

await using (SqlDataReader reader = await command.ExecuteReaderAsync())
{
    do
    {
        while (await reader.ReadAsync())
        {
            Console.WriteLine(reader.GetString(0));
        }
    }
    while (await reader.NextResultAsync());
}

Resultatet är:

Message 50000, severity 16: Row 7 failed validation.
The batch continued.

Fel med en allvarlighetsgrad på 17 eller högre utlöser fortfarande en SqlException, oavsett denna inställning. När du aktiverar denna egenskap är din hanterare ansvarig för att upptäcka fel. Kod som förväntar sig ett undantag för varje fel får inget undantag.

Rapportera programmets identitet

Från och med Microsoft.Data.SqlClient 7.1.0 kan ett ramverk, ett verktyg eller annan middleware rapportera vilken applikation som öppnade en anslutning. Sätt RegisteredApplication till ett RegisteredApplication värde innan du öppnar anslutningen. Drivern skickar värdet till servern en gång, under inloggning.

Följ dessa regler:

  • Sätt värdet genom egenskapen. Det finns inget reťazec pripojenia-nyckelord för det.
  • Ställ in värdet innan du öppnar anslutningen. Att ställa in den medan anslutningen öppnas eller är öppen ger en InvalidOperationException.
  • Behandla värdet som telemetri. Klienten tillhandahåller värdet och kan rapportera vilken identifierare som helst, så servern autentiserar det inte.
  • Räkna med att poolade anslutningar rapporterar den ursprungliga identiteten. Värdet ingår inte i poolnyckeln. En anslutning som serveras från poolen rapporterar identiteten på den logiska anslutning som orsakade att den fysiska anslutningen skapades.

Caution

Använd aldrig RegisteredApplication för auktorisering eller något annat säkerhetsbeslut. Vilken klient som helst kan rapportera vilken identifierare som helst.

Välj en identifierare

Standardvärdet är Unknown, vilket är 0. Uppräkningen har en underliggande typ av ushort, så identifierarna varierar från 0 till 0xFFFF.

Räckvidd Använd
0x0001 genom 0x7FFF Microsoft-definierade applikationer. Namngivna medlemmar i uppräkningstypen använder detta intervall.
0x8000 genom 0xBFFF Reserverad för småskalig användning.
0xC000 genom 0xFFFF För allmänheten och utvecklare.

De namngivna medlemmarna är EntityFrameworkCore, SemanticKernel, ManagementStudio, SqlManagementObjects, DataTierApplicationFramework, SqlToolsService, AzureFunctionsSqlExtension, OrleansAdoNet, EntityFramework, DurableTaskSqlServer, AspNetCoreDistributedSqlServerCache, SqlPackage och DataApiBuilder. För att rapportera en identifierare som inte har någon namngiven medlem, typomvandla talet till RegisteredApplication.

Typen RegisteredApplication och egenskapen är inte CLS-kompatibla eftersom uppräkningen använder ushort. C#-kod kan använda dem direkt.

Ange identifieraren

Detta program rapporterar en identifierare från utvecklarområdet och visar sedan vad som händer när koden ändrar värdet efter att anslutningen öppnats:

using Microsoft.Data.SqlClient;

string connectionString =
    Environment.GetEnvironmentVariable("SQL_CONNECTION_STRING")
    ?? throw new InvalidOperationException(
        "Set the SQL_CONNECTION_STRING environment variable.");

await using var connection = new SqlConnection(connectionString)
{
    RegisteredApplication = (RegisteredApplication)0xC001,
};

await connection.OpenAsync();
Console.WriteLine(
    $"Reported identifier: 0x{(ushort)connection.RegisteredApplication:X4}");

try
{
    connection.RegisteredApplication = RegisteredApplication.Unknown;
}
catch (InvalidOperationException ex)
{
    Console.WriteLine($"{ex.GetType().Name}: {ex.Message}");
}

Resultatet är:

Reported identifier: 0xC001
InvalidOperationException: Not allowed to change the 'RegisteredApplication' property. The connection's current state is open.

Förstå poolningseffekter

Drivrutinen rapporterar identifieraren endast när den skapar en ny fysisk anslutning. Med pooling aktiverat:

  • En anslutning som återanvänder en poolad fysisk anslutning rapporterar identiteten för den anslutning som skapade den fysiska anslutningen, inte sin egen.
  • Fysiska anslutningar som poolen öppnar i bakgrunden för att uppfylla Min Pool Size rapporterar till Unknown.

Om en reťazec pripojenia tjänar flera identiteter, behandla det rapporterade värdet som ungefärligt. Inaktivera pooling för den anslutningssträngen när du behöver exakt attribuering, och mät den extra anslutningskostnaden först.

SqlConnection.Clone kopierar RegisteredApplication värdet till den nya anslutningen.

Dela inte en anslutning samtidigt

SqlConnection, SqlCommand, SqlDataReader, och SqlTransaction stöder inte samtidig användning av flera trådar. Ge varje samtidig operation en egen anslutning och låt anslutningspooling återanvända de fysiska kopplingarna.

Multiple Active Result Sets (MARS) tillåter flera aktiva batcher på en anslutning i stödda scenarier. Det gör inte SqlClient-objekt trådsäkra, och det lägger till sessions- och transaktionsregler. Låt den vara avstängd om inte en operation specifikt behöver det.

Registrera inte en öppen SqlConnection som singleton i dependensinjektion. Registrera en anslutningssträng, ett oföränderligt alternativobjekt eller en fabrik som skapar en ny anslutning.

Använd transaktioner medvetet

En lokal transaktion tillhör dess anslutning. Varje kommando i transaktionen måste använda den anslutningen och sätta dess Transaction egenskap.

await using var connection = new SqlConnection(connectionString);
await connection.OpenAsync(cancellationToken);

await using SqlTransaction transaction =
    (SqlTransaction)await connection.BeginTransactionAsync(cancellationToken);

using var command = new SqlCommand(sql, connection, transaction);
command.Parameters.Add(
    new SqlParameter("@value", SqlDbType.Int) { Value = value });
await command.ExecuteNonQueryAsync(cancellationToken);

await transaction.CommitAsync(cancellationToken);

Om operationen misslyckas innan commiten, rullas transaktionen tillbaka när transaktionen avvecklas. Håll transaktionerna korta. Gör inte nätverkssamtal, användarinteraktion eller orelaterad beräkning medan en databastransaktion håller lås.

När System.Transactions.Transaction.Current är aktiv, Open och OpenAsync anmäler sig automatiskt som standard. Ställ in Enlist=false endast när operationen måste ligga utanför den omgivande transaktionen.

Mät en logisk koppling

Ställ StatisticsEnabled in på true för att samla in förarstatistik för ett objekt SqlConnection :

using System.Collections;
using Microsoft.Data.SqlClient;

string connectionString =
    Environment.GetEnvironmentVariable("SQL_CONNECTION_STRING")
    ?? throw new InvalidOperationException(
        "Set the SQL_CONNECTION_STRING environment variable.");

await using var connection = new SqlConnection(connectionString)
{
    StatisticsEnabled = true,
};

await connection.OpenAsync();
connection.ResetStatistics();

await using var command = new SqlCommand("SELECT name FROM sys.databases;", connection);
await using (SqlDataReader reader = await command.ExecuteReaderAsync())
{
    while (await reader.ReadAsync())
    {
    }
}

IDictionary statistics = connection.RetrieveStatistics();
Console.WriteLine($"ServerRoundtrips: {statistics["ServerRoundtrips"]}");
Console.WriteLine($"SelectRows: {statistics["SelectRows"]}");
Console.WriteLine($"BytesReceived > 0: {(long)statistics["BytesReceived"]! > 0}");

Resultatet visar en tur och retur. Antal rader beror på antalet databaser på servern:

ServerRoundtrips: 1
SelectRows: 14
BytesReceived > 0: True

RetrieveStatistics ger en ögonblicksbild. ResetStatistics påbörjar en ny mätgräns. Ställ StatisticsEnabled in på false för att sluta samla in. De insamlade värdena hittills finns fortfarande tillgängliga. Statistik är per anslutningsobjekt och lägger till overhead, så aktivera dem för riktad diagnos istället för varje produktionsförfrågan.

Hantera anslutningsfel

Fånga SqlException vid en gräns som kan logga, translatera eller försöka om felet. Post:

  • Number
  • State
  • Class
  • ClientConnectionId
  • Operationsnamnet samt konfigurerade server- och databasidentifierare

Logga inte anslutningssträngen, lösenordet, klienthemligheten eller åtkomsttokenen.

Gör dig av med en trasig anslutning. Poolen tar bort ogiltiga fysiska anslutningar när den upptäcker dem. Om en legitimation, token, certifikat, DNS-mål eller server har ändrats, korrigera konfigurationen innan du försöker igen.

Använd begränsad återförsökslogik endast för tillfälliga fel. Återförsök vid initial öppning, återställning av overksamma anslutningar och återförsök av kommandon är olika mekanismer. För mer information, se Konfigurerbar återförsökslogik och alternativen för anslutningsåterställning i Anslutningsalternativ.