SqlConnectionStringBuilderを使って、型指定プロパティを通じて接続文字列を作成・編集できます。 DbConnectionStringBuilderから継承されます。 コードが値を追加または変更するたびに、文字列をつなぐ代わりにこれを使ってください。
建築業者:
- 各キーワードを型付きプロパティとして公開します。例えば、
ConnectTimeoutを 整数 型として、EncryptをSqlConnectionEncryptOption型として扱います。 - 設定した際に、未知のキーワードや多くの範囲外の値は ArgumentException で却下されます。
-
Serverやuidのような同義語を、Data SourceやUser IDといった標準的なキーワードにマッピングします。 - セミコロン、引用符、または先頭や末尾のスペースを含む値を引用符で囲みます。
キーワードリストについては「接続オプション」をご覧ください。 テキスト形式については、 パーシングルールを参照してください。
各サンプルは完全なプログラムです。 .NETフレームワークのタブはC# 7.3を使用しています。 サンプルを実行するプロジェクトを作成するには、「 プロジェクトを作成」をご覧ください。
接続文字列 injectionを防止する
コードが信頼できないテキストを接続文字列に挿入すると、そのテキストのセミコロンでキーワードを追加したり、前のものを置き換えたりできます。なぜなら、最後の値が勝つからです。 ビルダーは値全体を一つのプロパティに保存し、引用符で囲むため、テキストが別のキーワードになることはありません。
このプログラムは InitialCatalog をプーリングをオフにしようとする値に設定します:
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}");
出力は次のとおりです。
Data Source=tcp:sql.example.com,1433;Initial Catalog="Orders;Pooling=false";Integrated Security=True;Encrypt=Strict
Pooling: True
ビルダーが値を引用し、Pooling は Trueのままです。 ドライバーはデータベース名として Orders;Pooling=false をサーバーに送信します。
引用符で囲むとキーワードの挿入が停止します。 その値が許可されるかどうかを決めるものではありません。 使用前に、信頼できない入力を許可されているサーバーやデータベースのリストと照らし合わせて確認してください。
基本接続文字列を完成させる
サーバーやデータベースなど、変更されない接続文字列の部分を設定に保存します。 実行時にシークレット値とワークロード固有の値を追加します。 ベース文字列をビルダーコンストラクタに渡し、プロパティを設定します。
このプログラムは、接続文字列とパスワードを別々の環境変数から読み取り、SQL認証で接続し、接続が開かれた後にパスワードが見えないことを確認します。
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}");
SQL_BASE_CONNECTION_STRING を Server=tcp:<server>,1433;Database=<database>;User ID=<user>;Encrypt=true のような値に設定します。 出力は次のとおりです。
APP_NAME(): Orders.Worker
Password visible after open: False
Persist Security Info のデフォルトは falseで、接続が開いた後、ドライバーが SqlConnection.ConnectionString からパスワードを削除します。 既定値のままにしてください
Windows 統合認証や Microsoft Entra ID のマネージド ID など、パスワードを必要としない認証方法を優先してください。 詳細については、Microsoft Entra ID認証および接続情報を保護するをご覧ください。
値を読み取って変更します
ビルダーは辞書としても機能します。 インデクサー、 ContainsKey、 Remove、 TryGetValue はキーワードまたはその同義語のいずれかを受け入れます。
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}"); }
出力は次のとおりです。
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 を返します。
ContainsKey は、文字列で設定されているかどうかにかかわらず、サポートされているすべてのキーワードに対して true を返します。
ConnectionStringプロパティには設定したキーワードのみが含まれます。
ビルダーがチェックしない点を理解しましょう
ビルダーは未知のキーワードや多くの無効な値を却下しますが、すべての値をチェックするわけではありません。 例えば、文字列の長さは確認せず、Type System Version や Transaction Binding には任意のテキストを受け付けます。 また、キーワードの組み合わせもチェックしないため、Integrated Security=true を Authentication=Active Directory Default と一緒に受け入れます。
SqlConnection は、文字列を渡すと、ArgumentException とのその組み合わせを拒否します。 ルールの全リストについては 、検証ルールを参照してください。
ビルダーはAuthenticationのように、スペースのないAuthentication=ActiveDirectoryDefault値を書きます。 ドライバーは両方の形式を受け付けます。
また、ビルダーはプロセスメモリに入ったパスワードを保護せず、サーバー設定、ID設定、証明書設定の安全性を判断しません。
正規の 接続文字列 を 1 つ保持してください
それぞれ異なる接続文字列は独自の接続プールを持ちます。 キーワードの順序や同義語だけが異なる手動で作成された文字列が2つのプールを作ります。 ビルダーは標準キーワードを一貫した順序で書くため、 Server=a;Database=d と Database=d;Server=a の両方が Data Source=a;Initial Catalog=dになります。 起動時に一度builder.ConnectionStringを組み立てて、それを再利用してください。 ユーザー名やリクエストIDなどのリクエストごとの値は追加しないでください。 プーリングの詳細については、「接続プーリングを使用する」をご覧ください。