Notitie
Voor toegang tot deze pagina is autorisatie vereist. U kunt proberen u aan te melden of de directory te wijzigen.
Voor toegang tot deze pagina is autorisatie vereist. U kunt proberen de mappen te wijzigen.
SqlConnectionvertegenwoordigt één logische verbinding met SQL Server, Azure SQL Database, Azure SQL Managed Instance, of SQL-database in Microsoft Fabric. Bij het openen van het object wordt een fysieke verbinding uit de verbindingspool verkregen wanneer er een beschikbaar is. Het sluiten of weggooien ervan geeft die fysieke verbinding met het zwembad terug.
Gebruik kortstondige SqlConnection objecten als werkeenheden. Houd niet één globale verbinding open voor de applicatie.
Prerequisites
- De .NET 10 SDK of een nieuwere ondersteunde .NET SDK. De SDK draait op Windows, Linux en macOS. Het bouwt ook de .NET Framework-versie van elk voorbeeld, die alleen op Windows draait en .NET Framework 4.8.1 nodig heeft.
- Een database waarmee je verbinding kunt maken in SQL Server, Azure SQL Database, Azure SQL Managed Instance, of SQL-database in Microsoft Fabric.
Het project maken
Microsoft. Data.SqlClient 7.0 en latere versies vereisen het versie-matched Microsoft.Data.SqlClient.Extensions.Azure pakket voor door drivers geleverde Microsoft Entra ID-authenticatiemodi, zoals Active Directory Default. Als je app alleen SQL-authenticatie of Windows-geïntegreerde authenticatie gebruikt, kun je het weglaten.
Voer in een lege map deze commando's uit:
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
De voorbeelden in dit artikel lezen de verbindingsreeks uit de SQL_CONNECTION_STRING omgevingsvariabele. Stel het in voordat je een voorbeeld uitvoert. Voor verbindingsreeks-formaten, zie Connection strings.
Elke sample behalve de transaction sample is een compleet programma. Om er één uit te voeren, vervang je de inhoud van Program.cs ermee, en voer vervolgens dotnet run uit. Het transactievoorbeeld is een fragment voor je eigen methode. Het tabblad .NET gebruikt top-level statements, impliciete using richtlijnen en await using. Het tabblad .NET Framework gebruikt C# 7.3, dat geen await using heeft, dus gebruikt het in plaats daarvan using-statements.
Open een verbinding
Roep OpenAsync in asynchrone code of Open in synchrone code aan. Declareer de verbinding met await using of using zodat deze wordt opgeruimd wanneer de code de scope verlaat, zelfs als er een uitzondering wordt gegooid.
Met Windows-geïntegreerde authenticatie gebruikt de verbinding de identiteit van het proces. Voor een webapplicatie of een Windows-dienst is dat de applicatiepool of serviceaccount, niet de ingelogde gebruiker. Voor meer informatie, zie Een authenticatiepatroon kiezen.
Dit volledige programma opent een verbinding, rapporteert elke toestandswijziging en leest twee servereigenschappen:
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)}");
}
Ten opzichte van SQL Server 2025 Enterprise-editie is de uitkomst:
State: Closed to Open
Edition: Enterprise Edition: Core-based Licensing (64-bit)
EngineEdition: 3
State: Open to Closed
De laatste regel verschijnt wanneer de verbinding aan het einde van het programma wordt vrijgegeven.
Verbindingen sluiten en vrijgeven
Sluit altijd een verbinding zodra je klaar bent zodat de fysieke verbinding terugkeert naar de pool. De using- en await using-instructies geven de verbinding vrij wanneer de code het blok verlaat, inclusief wanneer een niet-behandelde uitzondering wordt gegooid. Je kunt ook Dispose of Close direct bellen.
Close en Dispose hebben hetzelfde effect op de fysieke verbinding.
Volg deze regels:
- Geef readers en opdrachten vrij vóór de verbinding waartoe ze behoren.
- Vertrouw niet op garbagecollection om een verbinding terug te brengen naar de pool. Een verbinding die buiten bereik valt zonder te worden gesloten, wordt niet snel aan de pool teruggegeven en de pool kan zonder verbindingen komen te zitten.
- Roep
CloseofDisposeniet aan op een verbinding, een lezer of een ander beheerd object in een klasse-finalizer. Een finalizer zou alleen niet-beheerde resources moeten vrijgeven die zijn klasse direct bezit. Voor meer informatie, raadpleeg Garbage collection. - Na
Closekun jeOpenopnieuw aanroepen op hetzelfde object. NaDispose, maak een nieuw object aan.
Met pooling ingeschakeld geeft het sluiten van een verbinding deze terug naar de pool zonder de netwerkverbinding te sluiten. De pool reset de sessiestatus wanneer de verbinding opnieuw wordt gebruikt. Voor meer informatie, zie SQL Server connection pooling.
Asynchrone API's gebruiken
Gebruik asynchrone aanroepen voor netwerkgebonden databasewerk in webservers, services, gebruikersinterfaces en workers:
OpenAsync(cancellationToken)ExecuteNonQueryAsync(cancellationToken)ExecuteReaderAsync(cancellationToken)ExecuteScalarAsync(cancellationToken)ReadAsync(cancellationToken)
Start geen nieuwe bewerking op een verbinding, commando of lezer voordat de huidige asynchrone bewerking is voltooid.
Annuleren en time-outs toepassen
Geef de CancellationToken van de aanroeper door aan iedere asynchrone databaseaanroep. Annuleren verzoekt de chauffeur het lopende werk te stoppen, maar dit wordt niet onmiddellijk voltooid. Blijf begrensde verbinding en commando-timeouts gebruiken.
Deze bedieningselementen hebben aparte scopes:
| Beheersen | Scope |
|---|---|
Connect Timeout |
Verbinding tot stand brengen, of het wachten op een gepoolde verbinding |
SqlCommand.CommandTimeout |
Een opdrachtuitvoering |
CancellationToken |
Door de beller gevraagde annulering van een asynchrone operatie |
Een time-out of annulering bewijst niet dat de server een operatie heeft teruggedraaid. Gebruik een transactie wanneer meerdere wijzigingen als één geheel moeten worden doorgevoerd of teruggedraaid, en baseer beslissingen over nieuwe pogingen op de idempotentie en de uitkomst van de transactie van de bewerking.
Verbindingsstatus bijhouden
De State eigenschap geeft een momentopname terug uit de ConnectionState enumeratie.
| State | Meaning |
|---|---|
Closed |
De logische verbinding is niet open. |
Connecting |
Er is een open operatie gaande. |
Open |
De logische verbinding is geopend. |
Het StateChange event treedt op wanneer de toestand verandert. Het StateChangeEventArgs argument heeft twee eigenschappen:
-
OriginalStateis de status vóór de verandering. -
CurrentStateis de toestand na de wijziging.
De driver rapporteert de overgangen van Closed naar Open en van Open naar Closed, zoals het voorbeeld in Open a connection laat zien. Vertrouw niet op observatie Executing, Fetching, of Broken als fasen van de applicatielevenscyclus.
Gebruik het niet State als gezondheidscheck voor elk commando. Het netwerk kan na elke controle falen. Voer de bewerking uit en handel de resulterende uitzondering af. Gebruik StateChange voor diagnostiek, niet voor het coördineren van gelijktijdig werk.
Ontvang informatieve berichten
Het InfoMessage event levert berichten die de server stuurt zonder een foutmelding te geven. Deze berichten bevatten PRINT output, RAISERROR berichten met een ernst van 10 of lager, en serverwaarschuwingen. Fouten met een ernst van 11 of hoger genereren in plaats daarvan een SqlException. Voor ernstniveaus, zie ernstniveaus van Database Engine-fouten.
De event handler ontvangt een SqlInfoMessageEventArgs object. De eigenschap Errors bevat een verzameling SqlError objecten. Elk item bevat het berichtnummer, tekst, ernstklasse, procedure en regelnummer.
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();
De uitvoer is:
Message 0, severity 0: Starting the batch.
Message 50000, severity 0: Processed 42 rows.
De server geeft een RAISERROR ernst van 10 als klasse 0 aan, dus SqlError.Class toont 0 voor beide berichten.
Behandel gebruikersfouten als informatieve berichten
Standaard rapporteert de driver een fout met een ernst van 11 of hoger door een SqlException te genereren. Die uitzondering betekent niet dat de server de batch heeft gestopt. Veel fouten, waaronder RAISERROR met een ernst van 16, laten de server de resterende statements uitvoeren, zodat latere statements data kunnen wijzigen, zelfs als je code de uitzondering opvangt. Om deze fouten als berichten in plaats van uitzonderingen te ontvangen, zet FireInfoMessageEventOnUserErrors op true. De driver stuurt vervolgens fouten met een ernst van 16 of lager naar de gebeurtenis InfoMessage in plaats van een uitzondering op te werpen. Deze eigenschap verandert hoe het stuurprogramma fouten rapporteert. Het verandert niet welke statements de server uitvoert.
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());
}
De uitvoer is:
Message 50000, severity 16: Row 7 failed validation.
The batch continued.
Fouten met een ernst van 17 of hoger werpen nog steeds een SqlException op, ongeacht deze instelling. Wanneer je deze eigenschap inschakelt, is je handler verantwoordelijk voor het opsporen van fouten. Code dat voor elke fout een uitzondering verwacht, krijgt er geen te zien.
Rapporteer de applicatie-identiteit
Vanaf Microsoft.Data.SqlClient 7.1.0 kan een framework, tool of andere middleware rapporteren welke applicatie een verbinding heeft geopend. Stel RegisteredApplication in op een RegisteredApplication-waarde voordat je de verbinding opent. De driver stuurt de waarde één keer naar de server, tijdens het inloggen.
Volg deze regels:
- Stel de waarde in via de eigenschap. Er bestaat geen verbindingsreeks-sleutelwoord daarvoor.
- Stel de waarde in voordat je de verbinding opent. Als je het instelt terwijl de verbinding wordt geopend of openstaat, wordt er een InvalidOperationException opgeworpen.
- Behandel de waarde als telemetrie. De client levert de waarde en kan elke identifier rapporteren, dus de server authenticeert het niet.
- Verwacht dat gepoolde verbindingen de oorspronkelijke identiteit rapporteren. De waarde maakt geen deel uit van de poolsleutel. Een verbinding die vanuit de pool wordt bediend, rapporteert de identiteit van de logische verbinding die de fysieke verbinding heeft laten aanmaken.
Caution
Gebruik RegisteredApplication nooit voor autorisatie of andere beveiligingsbeslissingen. Elke klant kan elke identificator rapporteren.
Kies een id
De standaardwaarde is Unknown, wat is 0. De enumeratie heeft een onderliggend type ushort, dus identifiers variëren van 0 tot en met 0xFFFF.
| Bereik | Gebruiken |
|---|---|
0x0001 tot en met 0x7FFF |
Microsoft-gedefinieerde applicaties. Leden van benoemde enumeraties gebruiken dit bereik. |
0x8000 tot en met 0xBFFF |
Gereserveerd voor kleinschalig gebruik. |
0xC000 tot en met 0xFFFF |
Openbaar gebruik en gebruik door ontwikkelaars. |
De genoemde leden zijn SqlToolsService, AspNetCoreDistributedSqlServerCache, EntityFramework, OrleansAdoNet, AzureFunctionsSqlExtension, DurableTaskSqlServer, SqlPackage, DataApiBuilder, DataTierApplicationFramework, SqlManagementObjects, ManagementStudio, SemanticKernel en EntityFrameworkCore. Om een id te melden dat geen benoemd lid heeft, cast je het getal naar RegisteredApplication.
Het RegisteredApplication-type en de eigenschap zijn niet CLS-conform omdat de enumeratie ushort gebruikt. C#-code kan ze direct gebruiken.
Stel de identificator in
Dit programma rapporteert een identifier uit het ontwikkelaarsbereik en toont vervolgens wat er gebeurt wanneer code de waarde verandert nadat de verbinding is geopend:
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}");
}
De uitvoer is:
Reported identifier: 0xC001
InvalidOperationException: Not allowed to change the 'RegisteredApplication' property. The connection's current state is open.
Begrijp pooling-effecten
De driver rapporteert de identificatiecode alleen wanneer hij een nieuwe fysieke verbinding aanmaakt. Met pooling ingeschakeld:
- Een verbinding die een gepoolde fysieke verbinding hergebruikt, rapporteert de identiteit van de verbinding die de fysieke verbinding heeft gemaakt, niet die van hemzelf.
- Fysieke verbindingen die de pool op de achtergrond opent om te voldoen aan
Min Pool Sizerapporteren aanUnknown.
Als één verbindingsreeks meerdere identiteiten bedient, behandel dan de gerapporteerde waarde als benaderend. Schakel pooling uit voor die verbindingsreeks wanneer je exacte attributie nodig hebt, en meet eerst de extra verbindingskosten.
SqlConnection.Clone kopieert de RegisteredApplication waarde naar de nieuwe verbinding.
Deel geen verbinding tegelijk
SqlConnection, SqlCommand, SqlDataReader, en SqlTransaction ondersteunen geen gelijktijdig gebruik door meerdere threads. Geef elke gelijktijdige bewerking een eigen verbinding en laat verbindingspooling de fysieke verbindingen hergebruiken.
Multiple Active Result Sets (MARS) staat meerdere actieve batches op één verbinding toe in ondersteunde scenario's. Het maakt SqlClient-objecten niet thread-veilig en voegt sessie- en transactieregels toe. Laat het uitgeschakeld tenzij één operatie het specifiek nodig heeft.
Registreer een open SqlConnection niet als singleton in dependency injection. Registreer de verbindingsreeks, een immutable options-object, of een fabriek die een nieuwe verbinding aanmaakt.
Gebruik transacties bewust
Een lokale transactie is gekoppeld aan de verbinding. Elk commando in de transactie moet die verbinding gebruiken en de eigenschap ervan Transaction instellen.
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);
Als de operatie faalt vóór de commit, wordt de transactie teruggedraaid door de transactie vrij te geven. Houd transacties kort. Doe geen netwerkoproepen, gebruikersinteractie of niet-gerelateerde berekeningen terwijl een databasetransactie vergrendeld is.
Wanneer System.Transactions.Transaction.Current actief is, worden Open en OpenAsync standaard automatisch geregistreerd. Stel alleen in Enlist=false wanneer de bewerking buiten de omringende transactie moet blijven.
Meet één logische verbinding
Stel StatisticsEnabled in op true om driverstatistieken voor één SqlConnection-object te verzamelen:
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}");
De uitvoer toont één round trip. Het aantal rijen hangt af van het aantal databases op de server:
ServerRoundtrips: 1
SelectRows: 14
BytesReceived > 0: True
RetrieveStatistics geeft een snapshot terug.
ResetStatistics start een nieuwe meetgrens. Zet StatisticsEnabled op false om het verzamelen te stoppen. De tot nu toe verzamelde waarden zijn nog beschikbaar. Statistieken worden per verbindingsobject gebruikt en voegen overhead toe, dus maak ze mogelijk voor gerichte diagnose in plaats van elke productieverzoek.
Verbindingsfouten afhandelen
Vang SqlException op aan een grens die de fout kan loggen, vertalen of opnieuw proberen. Record:
NumberStateClassClientConnectionId- De bewerkingsnaam en geconfigureerde server- en database-identificaties
Leg de verbindingsreeks, het wachtwoord, het client secret of het toegangstoken niet vast.
Verwijder een verbroken verbinding. De pool verwijdert ongeldige fysieke verbindingen wanneer ze worden gedetecteerd. Als een credential, token, certificaat, DNS-doel of server is veranderd, corrigeer dan de configuratie voordat je het opnieuw probeert.
Gebruik begrensde herprobeerlogica alleen voor tijdelijke storingen. Opnieuw proberen bij het initiële openen, herstel van inactieve verbindingen en opnieuw proberen van opdrachten zijn verschillende mechanismen. Voor meer informatie, zie Configureable retry-logica en de opties voor verbindingsherstel in Connection-opties.