Kapcsolati karakterlánc-készítők a Microsoft.Data.SqlClientben

Használd a(z) SqlConnectionStringBuilder elemet a kapcsolati karakterláncok létrehozására és szerkesztésére típusos tulajdonságokkal. Az DbConnectionStringBuilder-t örökli. Használd, amikor a kódod hozzáad vagy módosít egy értéket, ahelyett, hogy stringeket kötnél össze.

Az építő:

  • Minden kulcsszót típusos tulajdonságként jelenít meg, például ConnectTimeout mint int, és Encrypt mint SqlConnectionEncryptOption.
  • Elutasítja az ismeretlen kulcsszavakat és sok tartományon kívüli értéket a(z) ArgumentException értékkel beállításkor.
  • A(z) Server és uid szinonimákat a(z) Data Source és User ID kanonikus kulcsszavakhoz rendeli.
  • Idézőjelek közé teszi azokat az értékeket, amelyek pontosvesszőket, idézőjeleket vagy kezdő vagy záró szóközöket tartalmaznak.

A kulcsszólistát lásd itt: Kapcsolódási beállítások. A szöveg formátumához lásd: feldolgozási szabályok.

Minden minta egy teljes program. A .NET Framework fülek C# 7.3-at használnak. Ha szeretnél létrehozni egy olyan projektet, amely a mintákat futtatja, lásd: A projekt létrehozása.

A kapcsolati karakterlánc-befecskendezés megelőzése

Amikor a kódod megbízhatatlan szöveget helyez be egy kapcsolati karakterlánc-be, egy pontosvesszővel hozzáadhat egy kulcsszót vagy helyettesíthet egy korábbit, mert az utolsó érték nyer. Az építő az egész értéket egy tulajdonságban tárolja, és idézi azt, így a szöveg nem válhat újabb kulcsszóvá.

Ez a program a pooling kikapcsolását célzó értékre állítja a InitialCatalog értékét:

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

A kimenet a következő:

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

A szerkesztő idézőjelek közé teszi az értéket, és Pooling változatlan marad True. Az illesztőprogram Orders;Pooling=false-t adatbázisnévként küldi el a szervernek.

Az idézőjelek használata megállítja a kulcsszó beinjekcióját. Nem dönti el, hogy engedélyezett-e egy érték. Ellenőrizd a megbízhatatlan bemenetet az engedélyezett szerverek vagy adatbázisok listájával, mielőtt használnád.

Egészítse ki az alap kapcsolati karakterláncot

Tárold a kapcsolati karakterlánc nem változó részeit, például a szervert és az adatbázist konfigurációban. Adja hozzá a titkot és a munkaterhelés-specifikus értékeket futásidőben. Add át az alap stringet a builder konstruktornak, majd állítsd be a tulajdonságokat.

Ez a program egy alap stringet és jelszót olvas különböző környezeti változókból, SQL hitelesítéssel csatlakozik, és megerősíti, hogy a jelszó nem látható a kapcsolat megnyitása után.

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

Állítsunk SQL_BASE_CONNECTION_STRING be olyan értékre, mint Server=tcp:<server>,1433;Database=<database>;User ID=<user>;Encrypt=true. A kimenet a következő:

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

Persist Security Info alapértelmezés szerint false, így a meghajtó eltávolítja a jelszót a SqlConnection.ConnectionString elemből a kapcsolat megnyitása után. Tartsd meg ezt alapértelmezésként.

Előnyben részesítsd az olyan hitelesítési módszert, amely nem igényel jelszót, például a Windows integrált hitelesítést vagy a Microsoft Entra ID-vel kezelt identitást. További információkért lásd: Microsoft Entra ID-hitelesítés és A kapcsolati adatok védelme.

Értékek olvasása és módosítása

A builder szótárként is működik. Az indexelő, ContainsKey, Remove és TryGetValue elfogadnak egy kulcsszót vagy annak bármely szinonimáját.

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

A kimenet a következő:

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 false értéket ad vissza egy olyan kulcsszó esetén, amely nincs a karakterláncban. ContainsKey minden támogatott kulcsszó esetén true értéket ad vissza, függetlenül attól, hogy a karakterlánc beállítja-e vagy sem. A ConnectionString tulajdonság csak azokat a kulcsszavakat tartalmazza, amelyeket Ön állított be.

Értsd meg, mit nem ellenőriz a Builder

Az építő elutasítja az ismeretlen kulcsszavakat és sok érvénytelen értéket, de nem ellenőriz minden értéket. Például a Type System Version és Transaction Binding helyén bármilyen szöveget elfogad, és nem ellenőrzi a stringek hosszát. A kulcsszavak kombinációit sem ellenőrzi, így a Authentication=Active Directory Default és a Integrated Security=true együttes használatát is elfogadja. SqlConnection elutasítja ezt a kombinációt, amikor átadod neki a karakterláncot ArgumentException használatával. A szabályok teljes listájáért lásd: Validációs szabályok.

Az építő szóközök nélküli értékeket ír, például Authentication=ActiveDirectoryDefault. Az illesztőprogram mindkét formátumot elfogadja.

A builder nem védi a jelszót, miután a jelszó a folyamat memóriájába került, és nem dönti el, hogy egy szerver-, identitás- vagy tanúsítványbeállítás biztonságos-e.

Tarts egy egységes kapcsolati karakterláncot

Minden különálló kapcsolati karakterlánc saját kapcsolatkészletet kap. Két kézzel írt string, amelyek csak kulcsszavak sorrendjében vagy szinonimáiban különböznek, két poolt alkotnak. A készítő következetes sorrendben írja a kanonikus kulcsszavakat, így Server=a;Database=d és Database=d;Server=a mindkettő Data Source=a;Initial Catalog=d lesz. Egyszer építsd fel a kapcsolati karakterlánc-et az indításkor, és használd builder.ConnectionStringújra. Ne adj hozzá kérésenkénti értékeket, például felhasználói neveket vagy kérelmazonosítókat. További pooling-útmutatásért lásd: Kapcsolatkészletezés használata.