C#に接続文字列パーサーはありますか?


181

接続文字列があり、たとえば「データソース」などを調べられるようにしたい。パーサーはありますか、それとも文字列を検索する必要がありますか?

回答:


305

はい、System.Data.Common.DbConnectionStringBuilderクラスがあります。

DbConnectionStringBuilderクラスは、厳密に型指定された接続文字列ビルダー(SqlConnectionStringBuilder、OleDbConnectionStringBuilderなど)が派生する基本クラスを提供します。接続文字列ビルダーを使用すると、開発者は構文的に正しい接続文字列をプログラムで作成し、既存の接続文字列を解析して再構築できます。

対象のサブクラスは次のとおりです。

System.Data.EntityClient.EntityConnectionStringBuilder
System.Data.Odbc.OdbcConnectionStringBuilder
System.Data.OleDb.OleDbConnectionStringBuilder
System.Data.OracleClient.OracleConnectionStringBuilder
System.Data.SqlClient.SqlConnectionStringBuilder

たとえば、SQLサーバー接続文字列から「データソースを調べる」には、次のようにします。

var builder = new SqlConnectionStringBuilder(connectionString);
var dataSource = builder.DataSource;

6
基本クラスは、DbConnectionStringBuilderサブクラスを使用することなく使用することができる汎用の処理機能を有している:if (builder.TryGetValue("Password", out var pwd)) { string decrypted = SomehowDecrypt(pwd); builder["Password"] = decrypted; }
オリヴィエJacot-Descombes

41

以下のようなさまざまなプロバイダからベンダー固有の接続文字列ビルダーがありますがSqlConnectionStringBuilderMySqlConnectionStringBuilderSQLiteConnectionStringBuilderなど(残念ながらMS、この時点からのパブリックインターフェイスはありません)。それ以外の場合は、プロバイダーに依存しない方法で別の方法で書き込むことができるDbProviderFactory.CreateConnectionStringBuilderがあります。設定ファイルでプロバイダーを指定し、適切なバージョンのdllを使用できるようにする必要があります。たとえば、

var c = "server=localhost;User Id=root;database=ppp";
var f = DbProviderFactories.GetFactory("MySql.Data.MySqlClient"); //your provider
var b = f.CreateConnectionStringBuilder();
b.ConnectionString = c;
var s = b["data source"];
var d = b["database"];

私はかつて自分のために手作業で構文解析を書いていたが、問題はなかった。これを拡張して他のパラメーターに関する情報を提供するのは簡単です(現在のところ、これはdb名、データソース、ユーザー名、パスワードなどの単純なものに対してのみです)。このように:

static readonly string[] serverAliases = { "server", "host", "data source", "datasource", "address", 
                                           "addr", "network address" };
static readonly string[] databaseAliases = { "database", "initial catalog" };
static readonly string[] usernameAliases = { "user id", "uid", "username", "user name", "user" };
static readonly string[] passwordAliases = { "password", "pwd" };

public static string GetPassword(string connectionString)
{
    return GetValue(connectionString, passwordAliases);
}

public static string GetUsername(string connectionString)
{
    return GetValue(connectionString, usernameAliases);
}

public static string GetDatabaseName(string connectionString)
{
    return GetValue(connectionString, databaseAliases);
}

public static string GetServerName(string connectionString)
{
    return GetValue(connectionString, serverAliases);
}

static string GetValue(string connectionString, params string[] keyAliases)
{
    var keyValuePairs = connectionString.Split(';')
                                        .Where(kvp => kvp.Contains('='))
                                        .Select(kvp => kvp.Split(new char[] { '=' }, 2))
                                        .ToDictionary(kvp => kvp[0].Trim(),
                                                      kvp => kvp[1].Trim(),
                                                      StringComparer.InvariantCultureIgnoreCase);
    foreach (var alias in keyAliases)
    {
        string value;
        if (keyValuePairs.TryGetValue(alias, out value))
            return value;
    }
    return string.Empty;
}

このため、設定ファイルに特別なものや、dllはまったく必要ありません。Containsin Where節はserver = localhost;pp;、where ppが何も追加しないなど、形式が正しくない接続文字列をバイパスする必要がある場合にのみ重要です。通常のビルダー(これらの場合は爆発する)のように動作するにはWhere

.Where(kvp => !string.IsNullOrWhitespace(kvp))

@Icarusは、辞書のキー比較子がであるため、実際にはそうではありませんStringComparer.InvariantCultureIgnoreCaseToDictionary過負荷を参照
nawfal 2013年

1
ええ、あなたは正しいです、私は簡単なテストを書いただけです。元のコメントが間違っているので削除します。
イカルス2013年

3
GetValue()メソッドは、たとえばユーザーがパスワードに';'またはを持っている場合には機能しません'='。私は同様の実装を書いていて、それが難しい方法で機能しないことを学びました。まあ、接続文字列の解析は実際には思ったよりもずっと難しいです!
Philip Atz

@ジョシュア私はあなたが手動の解析部分について話していることを望みます。間違いのない、テスト済みのソリューションではなく、取り組むことができる出発点として、ここで回答してください。情報を残さないコメントよりも価値があると思います。また、自由に反対投票することもできます。私が知る限り、さらに実行する必要があるのは解析標準に準拠することです。MSにはmsdnがあり、それを改めるのは長い間考えられていました。私たち全員に時間があったら。「@」はすべて、特にPhilip Atzのコメントにあるエッジケースに留意してください。
nawfal 2017

@nawfal:私がやって来て、解決したら答えを残しました。
Joshua

15

以下は、接続文字列を解析して辞書に入れる2、3行のコードです。

Dictionary<string, string> connStringParts = connString.Split(';')
    .Select(t => t.Split(new char[] { '=' }, 2))
    .ToDictionary(t => t[0].Trim(), t => t[1].Trim(), StringComparer.InvariantCultureIgnoreCase);

そして、あなたはどの部分にもアクセスできます:

string dataSource = connStringParts["Data Source"];

3
スマート、私が変更する唯一のことはStringSplitOptions.RemoveEmptyEntries、最初のスプリットに含めることIndexOutOfRangeです。これは、後続がある場合に例外が発生するためです;
スコットチェン

2
これは機能しますが、接続文字列ビルダーはより堅牢です。このようなコードは、無効な接続文字列の場合、より意味のある解析エラーではなく、低レベルの例外をスローします。
サム

これは、ADOの接続文字列を解析するのに役立ちましSqlConnectionSqlConnectionStringBuilder
Holistic Developer

ここでいくつかの注意点があります。たとえば、接続文字列の値は引用符で囲むことができます。
Seva Alekseyev



4

はい、ConnectionStringBuilderクラスを使用してこれを行うことができます。以下は、標準データプロバイダーで使用可能なDbConnectionStringBuilder実装のリストです。

System.Data.Odbc.OdbcConnectionStringBuilder
System.Data.OleDb.OleDbConnectionStringBuilder
System.Data.OracleClient.OracleConnectionStringBuilder
System.Data.SqlClient.SqlConnectionStringBuilder

解析接続文字列のサンプル例とその要素を表示します。

 string conString = @"Data Source=.\sqlexpress;" +
                        "Database=Northwind;Integrated Security=SSPI;" +
                        "Min Pool Size=5;Max Pool Size=15;Connection Reset=True;" +
                        "Connection Lifetime=600;";
    // Parse the SQL Server connection string and display it's properties

    SqlConnectionStringBuilder objSB1 = new SqlConnectionStringBuilder(conString);
    Response.Write("<b>Parsed SQL Connection String Parameters:</b>");
    Response.Write(" <br/>  Database Source = " + objSB1.DataSource);
    Response.Write(" <br/>  Database = " + objSB1.InitialCatalog);
    Response.Write(" <br/>  Use Integrated Security = " + objSB1.IntegratedSecurity);
    Response.Write(" <br/>  Min Pool Size = " + objSB1.MinPoolSize);
    Response.Write(" <br/>  Max Pool Size = " + objSB1.MaxPoolSize);
    Response.Write(" <br/>  Lifetime = " + objSB1.LoadBalanceTimeout);

4

DbConnectionStringBuilderを使用でき、特定のプロバイダーは必要ありません。

次のコード:

var cnstr = "Data Source=data source value;Server=ServerValue";
var builder = new DbConnectionStringBuilder();
builder.ConnectionString = cnstr;
Console.WriteLine("Data Source: {0}", builder["Data Source"]);
Console.WriteLine("Server: {0}", builder["Server"]);

コンソールへの出力:

Data Source: data source value
Server: ServerValue

編集:

DbConnectionStringBuilderはIDictionaryを実装しているため、接続文字列パラメーターを列挙できます。

foreach (KeyValuePair<string, object> kv in builder)
{
    Console.WriteLine("{0}: {1}", kv.Key, kv.Value);
}

これは、上記のstackoverflow.com/a/15529085/534109に記載されているように、接続文字列に「データソース」値などがあることをすでに知っていることを前提としています。
Tieson T.

私の答えのaddrees特に何opが尋ねる:「私は例えば外を覗くことができるようにしたい『データソース』」
ヘスス・ロペス

すべての接続文字列パラメーターを表示するように編集しました。
ヘスス・ロペス

1

ここですべての答えが気に入らなかった。だからここに私が見つけたものがあります。

.NET Coreを使用

DbConnectionStringBuilder直接使用できます:

var builder = new System.Data.Common.DbConnectionStringBuilder();
builder.ConnectionString = settings.ConnectionString;
var server = builder["server"];

0

だから私は既存の答えのすべてが多かれ少なかれ間違っていたことがわかりました。私は次の簡単な解決策に終わりました:

class ConnectionStringParser: DbConnectionStringBuilder {
    ConnectionStringParser(string c) { Connection = c; }
    public override bool ShouldSerialize(string keyword) => true;
}

パーサーはDbConnectionStringBuilderにあり、非常に簡単に取得できます。私たちがしなければならない唯一のばかげたことは、任意の接続文字列をラウンドトリップしようとするときにコンポーネントが失われないようにするために常にtrueを返すようにShouldSerializeを設定することです。


2
既存の回答の何が問題でしたか?または、ソリューションは何を修正しますか。説明が参考になります。
nawfal 2017
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.