Konstruktory parametrów połączenia w Microsoft.Data.SqlClient

Użyj SqlConnectionStringBuilder, aby tworzyć i edytować ciągi połączeń za pomocą typowanych właściwości. Dziedziczy z elementu DbConnectionStringBuilder. Używaj go zawsze, gdy Twój kod dodaje lub zmienia wartość, zamiast łączyć ciągi znaków.

Budowniczka:

  • Udostępnia każde słowo kluczowe jako właściwość o określonym typie, taką jak ConnectTimeout jako int oraz Encrypt jako SqlConnectionEncryptOption.
  • Odrzuca nieznane słowa kluczowe i wiele wartości poza zakresem za pomocą ArgumentException podczas ich ustawiania.
  • Odwzorowuje synonimy takie jak Server i uid na kanoniczne słowa kluczowe, takie jak Data Source i User ID.
  • Ujmuje w cudzysłów wartości zawierające średniki, cudzysłowy lub początkowe bądź końcowe spacje.

Listę słów znajdziesz w Opcjach połączenia. Informacje o formacie tekstu znajdziesz w zasadach parsowania.

Każda próbka to kompletny program. Zakładki .NET Framework używają C# 7.3. Aby stworzyć projekt, który uruchamia próbki, zobacz Utwórz projekt.

Zapobieganie wstrzykiwaniu parametrów połączenia

Gdy Twój kod wstawia niezaufany tekst do ciągu połączenia, średnik w tym tekście może dodać słowo kluczowe lub zastąpić wcześniejsze, ponieważ wygrywa ostatnia wartość. Konstruktor przechowuje całą wartość w jednej właściwości i ujmuje ją w cudzysłów, więc tekst nie może stać się kolejnym słowem kluczowym.

Ten program ustawia InitialCatalog na wartość, która próbuje wyłączyć pulowanie:

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

Dane wyjściowe to:

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

Konstruktor ujmuje wartość w cudzysłów, a Pooling pozostaje True. Sterownik wysyła do serwera Orders;Pooling=false jako nazwę bazy danych.

Ujęcie w cudzysłów zatrzymuje wstrzykiwanie słów kluczowych. Nie decyduje, czy wartość jest dozwolona. Sprawdź nieufne dane wejściowe względem listy dozwolonych serwerów lub baz danych przed ich użyciem.

Uzupełnij bazowy parametry połączenia

Przechowuj części parametry połączenia, które się nie zmieniają, takie jak serwer i baza danych, w konfiguracji. Dodawaj wartości sekretów i wartości specyficzne dla obciążenia w czasie wykonywania. Przekaż ciąg bazowy do konstruktora klasy Builder, a następnie ustaw właściwości.

Program ten odczytuje bazowy ciąg i hasło z oddzielnych zmiennych środowiskowych, łączy się za pomocą uwierzytelniania SQL i potwierdza, że hasło nie jest widoczne po otwarciu połączenia.

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

Ustaw SQL_BASE_CONNECTION_STRING na wartość taką jak Server=tcp:<server>,1433;Database=<database>;User ID=<user>;Encrypt=true. Dane wyjściowe to:

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

Persist Security Info domyślnie używa false, więc sterownik usuwa hasło z SqlConnection.ConnectionString po otwarciu połączenia. Zachowaj tę wartość domyślną.

Preferuj metodę uwierzytelniania bez hasła, taką jak zintegrowane uwierzytelnianie Windows lub zarządzaną tożsamość Microsoft Entra ID. Więcej informacji można znaleźć w sekcji Uwierzytelnianie Microsoft Entra ID oraz Ochrona informacji o połączeniu.

Odczytuj i zmieniaj wartości

Kreator działa także jako słownik. Indekser, ContainsKey, Remove i TryGetValue akceptują słowo kluczowe lub dowolny z jego synonimów.

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

Dane wyjściowe to:

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 zwraca false dla słowa kluczowego, które nie znajduje się w ciągu danych. ContainsKey zwraca true dla każdego obsługiwanego słowa kluczowego, niezależnie od tego, czy ciąg je ustawia. Właściwość ConnectionString zawiera tylko te słowa kluczowe, które ustaliłeś.

Dowiedz się, czego builder nie sprawdza

Kreator odrzuca nieznane słowa kluczowe i wiele nieprawidłowych wartości, ale nie sprawdza każdej wartości. Na przykład akceptuje dowolny tekst dla Type System Version i Transaction Binding, i nie sprawdza długości ciągów znaków. Nie sprawdza też kombinacji słów kluczowych, więc akceptuje Authentication=Active Directory Default razem z Integrated Security=true. SqlConnection odrzuca to połączenie z ArgumentException, gdy przekazujesz mu ten ciąg znaków. Pełną listę reguł można znaleźć w sekcji Reguły walidacji.

Konstruktor zapisuje wartości Authentication bez spacji, takie jak Authentication=ActiveDirectoryDefault. Sterownik akceptuje obie formy.

Builder też nie chroni hasła po wejściu do pamięci procesu i nie decyduje, czy ustawienie serwera, tożsamości lub certyfikatu jest bezpieczne.

Zachowaj jeden kanoniczny parametry połączenia

Każdy odrębny parametry połączenia otrzymuje własną pulę połączeń. Dwa ręcznie zapisane ciągi znaków, które różnią się jedynie kolejnością słów kluczowych lub synonimami, tworzą dwie pule. Konstruktor zapisuje kanoniczne słowa kluczowe w spójnej kolejności, więc Server=a;Database=d i Database=d;Server=a oba stają się Data Source=a;Initial Catalog=d. Zbuduj parametry połączenia raz przy starcie i użyj ponowniebuilder.ConnectionString. Nie dodawaj wartości specyficznych dla żądania, takich jak nazwy użytkowników czy identyfikatory żądań. Więcej wskazówek dotyczących poolingu znajdziesz w artykule Używanie puli połączeń.