Costruttori di stringhe di connessione in Microsoft. Data.SqlClient

Da usare SqlConnectionStringBuilder per creare e modificare stringhe di connessione tramite proprietà tipizzate. Eredita da DbConnectionStringBuilder. Usalo ogni volta che il tuo codice aggiunge o cambia un valore, invece di unire stringhe.

Il costruttore:

  • Espone ogni parola chiave come proprietà tipizzata, ad esempio, ConnectTimeout come un int e Encrypt come una SqlConnectionEncryptOption.
  • Rifiuta parole chiave sconosciute e molti valori fuori intervallo con ArgumentException quando li imposti.
  • Mappa sinonimi come Server e uid a parole chiave canoniche come Data Source e User ID.
  • Mette tra virgolette i valori che contengono punti e virgola, virgolette o spazi iniziali o finali.

Per la lista delle parole chiave, vedi Opzioni di connessione. Per il formato testuale, vedi Regole di analisi.

Ogni campione è un programma completo. Le schede del framework .NET utilizzano C# 7.3. Per creare un progetto che esegue gli esempi, vedi Crea il progetto.

Prevenire l'iniezione di stringa di connessione

Quando il tuo codice inserisce testo non affidabile in una stringa di connessione, un punto e virgola in quel testo può aggiungere una parola chiave o sostituirne una precedente, perché vince l'ultimo valore. Il costruttore memorizza l'intero valore di una proprietà e lo cita, così il testo non può diventare un'altra parola chiave.

Questo programma imposta InitialCatalog a un valore che cerca di disattivare il pooling:

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

L'output è il seguente:

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

Il builder racchiude il valore tra virgolette e Pooling rimane True. Il driver invia Orders;Pooling=false al server come nome del database.

Fare una citazione ferma l'iniezione di parole chiave. Non decide se un valore è consentito. Controlla l'input non affidabile con una lista di server o database consentiti prima di usarlo.

Completare una stringa di connessione base

Memorizza le parti di una stringa di connessione che non cambiano, come il server e il database, nella configurazione. Aggiungi i valori segreti e specifici del carico di lavoro in tempo reale. Passa la stringa base al costruttore costruttore, poi imposta le proprietà.

Questo programma legge una stringa base e una password da variabili di ambiente separate, si collega con l'autenticazione SQL e conferma che la password non è visibile dopo l'apertura della connessione.

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

Impostate SQL_BASE_CONNECTION_STRING a un valore come Server=tcp:<server>,1433;Database=<database>;User ID=<user>;Encrypt=true. L'output è il seguente:

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

Persist Security Info è impostato su false, quindi il driver rimuove la password da SqlConnection.ConnectionString dopo l'apertura della connessione. Mantieni quel predefinito.

Preferisci un metodo di autenticazione che non richiede password, come l'autenticazione integrata di Windows o un'identità gestita da Microsoft Entra ID. Per ulteriori informazioni, consulta l'autenticazione di Microsoft Entra ID e Proteggere le informazioni di connessione.

Lettura e modifica dei valori

Il costruttore funziona anche come dizionario. L'indicizzatore, ContainsKey, Remove, e TryGetValue accetta una parola chiave o uno qualsiasi dei suoi sinonimi.

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

L'output è il seguente:

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 ritorna false per una parola chiave che non è nella stringa. ContainsKey restituisce true per ogni parola chiave supportata, indipendentemente dal fatto che la stringa la imposti o meno. La ConnectionString proprietà include solo le parole chiave che hai impostato.

Capire cosa il builder non controlla

Il builder rifiuta parole chiave sconosciute e molti valori non validi, ma non controlla ogni valore. Ad esempio, accetta qualsiasi testo per Type System Version e Transaction Binding, e non controlla la lunghezza delle stringhe. Inoltre non controlla le combinazioni di parole chiave, quindi accetta Authentication=Active Directory Default insieme a Integrated Security=true. SqlConnection rifiuta quella combinazione con ArgumentException quando gli passi la stringa. Per l'elenco completo delle regole, vedi Regole di validazione.

Il costruttore scrive Authentication valori senza spazi, come Authentication=ActiveDirectoryDefault. Il driver accetta entrambe le forme.

Il builder inoltre non protegge una password dopo che questa entra nella memoria del processo, e non decide se un'impostazione di server, identità o certificato sia sicura.

Tieni una stringa di connessione canonica

Ogni distinta stringa di connessione ha il proprio pool di connessioni. Due stringhe scritte a mano che differiscono solo per l'ordine delle parole chiave o per i sinonimi creano due pool. Il builder scrive parole chiave canoniche in un ordine coerente, quindi Server=a;Database=d e Database=d;Server=a entrambe diventano Data Source=a;Initial Catalog=d. Costruisci la stringa di connessione una volta all'avvio e riutilizzabuilder.ConnectionString. Non aggiungere valori per richiesta, come nomi utente o ID richieste. Per ulteriori indicazioni sul pooling, vedi Usa il pool di connessioni.