Bouwers voor verbindingsreeksen in Microsoft.Data.SqlClient

Gebruik SqlConnectionStringBuilder om verbindingsstrings te maken en te bewerken via getypeerde eigenschappen. Het neemt over van DbConnectionStringBuilder. Gebruik het telkens wanneer je code een waarde toevoegt of verandert, in plaats van strings te joinen.

De bouwer:

  • Stelt elk trefwoord beschikbaar als een getypeerde eigenschap, zoals ConnectTimeout als een int en Encrypt als een SqlConnectionEncryptOption.
  • Weigert onbekende trefwoorden en veel waarden buiten het bereik wanneer je deze instelt ArgumentException.
  • Wijst synoniemen zoals Server en uid toe aan canonieke trefwoorden zoals Data Source en User ID.
  • Plaatst aanhalingstekens rond waarden die puntkomma's, aanhalingstekens of voor- of achterliggende spaties bevatten.

Zie Verbindingsopties voor de trefwoordenlijst. Voor het tekstformaat, zie Parseerregels.

Elke sample is een compleet programma. De .NET Framework-tabbladen gebruiken C# 7.3. Om een project te maken dat de samples uitvoert, zie Het project maken.

Voorkom verbindingsreeks injection

Wanneer je code onvertrouwde tekst in een verbindingsreeks invoegt, kan een puntkomma in die tekst een trefwoord toevoegen of een eerder trefwoord vervangen, omdat de laatste waarde wint. De bouwer slaat de volledige waarde op in één eigenschap en zet deze tussen aanhalingstekens, zodat de tekst geen nieuw trefwoord kan worden.

Dit programma zet InitialCatalog op een waarde die probeert pooling uit te schakelen:

using Microsoft.Data.SqlClient;

// Simulates a value that came from a user or another untrusted source.
string databaseFromUser = "Orders;Pooling=false";

var builder = new SqlConnectionStringBuilder
{
    DataSource = "tcp:sql.example.com,1433",
    InitialCatalog = databaseFromUser,
    IntegratedSecurity = true,
    Encrypt = SqlConnectionEncryptOption.Strict,
};

Console.WriteLine(builder.ConnectionString);
Console.WriteLine($"Pooling: {builder.Pooling}");

De uitvoer is:

Data Source=tcp:sql.example.com,1433;Initial Catalog="Orders;Pooling=false";Integrated Security=True;Encrypt=Strict
Pooling: True

De builder zet de waarde tussen aanhalingstekens en Pooling blijft True. De driver stuurt Orders;Pooling=false naar de server als databasenaam.

Aanhalingstekens gebruiken stopt trefwoordinjectie. Het bepaalt niet of een waarde is toegestaan. Controleer onbetrouwbare invoer aan de hand van een lijst met toegestane servers of databases voordat je het gebruikt.

Voltooi een basis-verbindingsreeks

Sla de delen van een verbindingsreeks die niet veranderen, zoals de server en database, op in de configuratie. Voeg de geheime en workload-specifieke waarden toe tijdens runtime. Geef de basisstring door aan de builder-constructor en stel vervolgens eigenschappen in.

Dit programma leest een basisstring en een wachtwoord uit aparte omgevingsvariabelen, maakt verbinding met SQL-authenticatie en bevestigt dat het wachtwoord niet zichtbaar is nadat de verbinding is geopend.

using Microsoft.Data.SqlClient;

// The base string holds no secret. The password comes from a separate secret source.
string baseConnectionString =
    Environment.GetEnvironmentVariable("SQL_BASE_CONNECTION_STRING")
    ?? throw new InvalidOperationException(
        "Set the SQL_BASE_CONNECTION_STRING environment variable.");
string password =
    Environment.GetEnvironmentVariable("SQL_PASSWORD")
    ?? throw new InvalidOperationException(
        "Set the SQL_PASSWORD environment variable.");

var builder = new SqlConnectionStringBuilder(baseConnectionString)
{
    Password = password,
    ApplicationName = "Orders.Worker",
};

await using var connection = new SqlConnection(builder.ConnectionString);
await connection.OpenAsync();

await using var command = new SqlCommand("SELECT APP_NAME();", connection);
Console.WriteLine($"APP_NAME(): {await command.ExecuteScalarAsync()}");

var opened = new SqlConnectionStringBuilder(connection.ConnectionString);
Console.WriteLine($"Password visible after open: {opened.ContainsKey("Password") && opened.Password.Length > 0}");

Stel SQL_BASE_CONNECTION_STRING op een waarde zoals Server=tcp:<server>,1433;Database=<database>;User ID=<user>;Encrypt=true. De uitvoer is:

APP_NAME(): Orders.Worker
Password visible after open: False

Persist Security Info staat standaard op false, dus de driver verwijdert het wachtwoord van SqlConnection.ConnectionString nadat de verbinding is geopend. Behoud die standaardinstelling.

Geef de voorkeur aan een authenticatiemethode die geen wachtwoord vereist, zoals Windows-geïntegreerde authenticatie of een Microsoft Entra ID managed identity. Voor meer informatie, zie Microsoft Entra ID-authenticatie en Verbindingsgegevens beveiligen.

Lees en verander waarden

De builder fungeert ook als woordenboek. De indexer, ContainsKey, Remove en TryGetValue accepteert een trefwoord of een van de synoniemen ervan.

using Microsoft.Data.SqlClient;

var b = new SqlConnectionStringBuilder("Server=sql.example.com;Database=Orders;uid=app_user;pwd=x");
b["server"] = "tcp:sql2.example.com,1433";
Console.WriteLine($"DataSource: {b.DataSource}");
Console.WriteLine($"ContainsKey(\"uid\"): {b.ContainsKey("uid")}");
Console.WriteLine($"Remove(\"pwd\"): {b.Remove("pwd")}");
Console.WriteLine($"TryGetValue: {b.TryGetValue("Database", out object? db)} {db}");
Console.WriteLine($"ShouldSerialize(\"Pooling\"): {b.ShouldSerialize("Pooling")}");
Console.WriteLine(b.ConnectionString);
try { b["Bogus"] = 1; } catch (Exception e) { Console.WriteLine($"{e.GetType().Name}: {e.Message}"); }
try { b.ConnectTimeout = -1; } catch (Exception e) { Console.WriteLine($"{e.GetType().Name}: {e.Message}"); }

De uitvoer is:

DataSource: tcp:sql2.example.com,1433
ContainsKey("uid"): True
Remove("pwd"): True
TryGetValue: True Orders
ShouldSerialize("Pooling"): False
Data Source=tcp:sql2.example.com,1433;Initial Catalog=Orders;User ID=app_user
ArgumentException: Keyword not supported: 'Bogus'.
ArgumentException: Invalid value for key 'Connect Timeout'.

ShouldSerialize geeft terug false voor een trefwoord dat niet in de string zit. ContainsKey geeft terug true voor elk ondersteund trefwoord, ongeacht of de string het instelt of niet. De ConnectionString eigenschap bevat alleen de trefwoorden die je hebt ingesteld.

Begrijp wat de builder niet controleert

De builder wijst onbekende trefwoorden en veel ongeldige waarden af, maar controleert niet elke waarde. Bijvoorbeeld, het accepteert elke tekst voor Type System Version en Transaction Binding, en controleert geen tekenreekslengtes. Het controleert ook geen combinaties van trefwoorden, dus accepteert het Authentication=Active Directory Default samen met Integrated Security=true. SqlConnection wijst die combinatie met ArgumentException af wanneer je de tekenreeks eraan doorgeeft. Voor de volledige lijst met regels, zie Validatieregels.

De bouwer schrijft Authentication waarden zonder ruimtes, zoals Authentication=ActiveDirectoryDefault. Het stuurprogramma accepteert beide vormen.

De builder beschermt ook geen wachtwoord nadat het in het procesgeheugen terechtkomt, en bepaalt niet of een server-, identiteits- of certificaatinstelling veilig is.

Houd één standaard verbindingsreeks

Elke afzonderlijke verbindingsreeks krijgt zijn eigen connection pool. Twee handgeschreven strings die alleen verschillen in trefwoordvolgorde of synoniemen creëren twee pools. De bouwer schrijft canonieke trefwoorden in een consistente volgorde, dus Server=a;Database=d en Database=d;Server=a beide worden Data Source=a;Initial Catalog=d. Bouw de verbindingsreeks één keer bij het opstarten en hergebruik builder.ConnectionString. Voeg geen per-request waarden toe, zoals gebruikersnamen of request ID's. Raadpleeg Verbindingspooling gebruiken voor meer richtlijnen voor pooling.