Apakah ada pengurai string koneksi di C #?

181

Saya memiliki string koneksi dan saya ingin dapat mengintip misalnya "Sumber Data". Apakah ada pengurai, atau apakah saya harus mencari string?

Amir Rezaei
sumber

Jawaban:

305

Ya, ada System.Data.Common.DbConnectionStringBuilderkelasnya.

Kelas DbConnectionStringBuilder menyediakan kelas dasar dari mana pembangun string koneksi sangat diketik (SqlConnectionStringBuilder, OleDbConnectionStringBuilder, dan sebagainya) berasal. Pembuat string koneksi memungkinkan pengembang membuat string koneksi yang benar secara sintaksis, dan mem-parsing dan membangun kembali string koneksi yang ada.

Subclass yang menarik adalah:

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

Misalnya, untuk "mengintip Sumber Data" dari string koneksi SQL-server, Anda dapat melakukan:

var builder = new SqlConnectionStringBuilder(connectionString);
var dataSource = builder.DataSource;
Ani
sumber
6
Kelas dasar DbConnectionStringBuildermemiliki fitur pemrosesan generik yang dapat digunakan tanpa menggunakan subclass:if (builder.TryGetValue("Password", out var pwd)) { string decrypted = SomehowDecrypt(pwd); builder["Password"] = decrypted; }
Olivier Jacot-Descombes
41

Ada penjual koneksi string spesifik pembangun dari berbagai penyedia seperti SqlConnectionStringBuilder, MySqlConnectionStringBuilder,SQLiteConnectionStringBuilder dll (sayangnya tidak ada antarmuka publik dari MS saat ini). Kalau tidak, Anda memiliki DbProviderFactory.CreateConnectionStringBuilder yang akan memberi Anda cara alternatif untuk menuliskannya dengan cara provider-agnostic. Anda perlu menentukan penyedia dalam file konfigurasi dan memiliki versi dll yang tepat tersedia. Untuk mis.,

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"];

Saya pernah menulis parsing manual untuk diri saya sendiri yang tidak memberi saya masalah. Akan sepele untuk memperluas ini untuk memberikan info tentang parameter lain (saat ini hanya untuk hal-hal sederhana seperti nama db, sumber data, nama pengguna dan kata sandi). Seperti ini atau lebih:

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

Untuk ini, Anda tidak perlu sesuatu yang khusus dalam file konfigurasi, atau dll sama sekali. Containsdalam Whereklausa penting hanya jika Anda perlu mem-bypass koneksi yang diformat dengan buruk seperti di server = localhost;pp;mana tidak ppmenambah apa pun. Untuk berperilaku seperti pembangun normal (yang akan meledak dalam kasus ini) ubah Whereke

.Where(kvp => !string.IsNullOrWhitespace(kvp))
nawfal
sumber
@Icarus tidak benar-benar karena pembanding utama kamus StringComparer.InvariantCultureIgnoreCase. Lihat ToDictionarykelebihan
nawfal
1
Ya, Anda benar, saya baru saja menulis tes cepat. Akan menghapus komentar asli saya karena salah.
Icarus
3
Anda metode GetValue () tidak akan bekerja dalam kasus di mana misalnya pengguna memiliki ';'atau '='password mereka. Saya telah menulis implementasi serupa dan belajar bahwa itu tidak bekerja dengan cara yang sulit. Astaga, koneksi string parsing sebenarnya jauh lebih sulit daripada yang saya kira!
Philip Atz
@ Yosua, saya harap Anda berbicara tentang bagian penguraian manual. Silakan ambil jawaban di sini sebagai titik awal yang dapat dikerjakan alih-alih solusi yang mudah dan teruji pertempuran. Saya berharap mereka lebih berharga daripada komentar yang tidak meninggalkan informasi. Anda juga bebas untuk melakukan downvote. Sejauh yang saya tahu, apa yang perlu dilakukan selanjutnya adalah mematuhi standar parsing. MS memiliki satu di msdn dan sudah lama dalam pikiran saya untuk mengubah. Kalau saja kita semua punya waktu. '@' semua tolong ingat kasus tepi, khususnya dalam komentar Philip Atz.
nawfal
@nawfal: Saya datang dan meninggalkan jawaban begitu saya menyelesaikannya.
Joshua
15

Berikut adalah beberapa baris kode yang akan menguraikan string koneksi apa pun ke dalam kamus:

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

Dan kemudian Anda dapat mengakses bagian mana saja:

string dataSource = connStringParts["Data Source"];
codeprose-sam
sumber
3
Cerdas, satu-satunya hal yang akan saya ubah adalah dimasukkan StringSplitOptions.RemoveEmptyEntrieske split pertama karena akan menyebabkan IndexOutOfRangepengecualian jika ada trailing;
Scott Chamberlain
2
Ini berfungsi, tetapi pembangun string koneksi lebih kuat. Kode seperti ini akan memunculkan eksepsi tingkat rendah alih-alih kesalahan parsing yang lebih bermakna dalam kasus string koneksi yang tidak valid.
Sam
Ini membantu saya mengurai string koneksi ADO sehingga saya bisa membangun yang setara SqlConnectiondengan SqlConnectionStringBuilder.
Pengembang Holistik
Beberapa peringatan di sini. Nilai string koneksi dapat dimasukkan dalam tanda kutip, misalnya.
Seva Alekseyev
6

Gunakan SqlConnectionStringBuilder Sayangnya Anda harus menggunakan DB ConnectionStringBuilder khusus karena string koneksi berbeda.

Erno
sumber
4

Ya, Anda bisa melakukan ini menggunakan kelas ConnectionStringBuilder. Berikut adalah daftar implementasi DbConnectionStringBuilder yang tersedia untuk penyedia data standar:

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

berikut adalah contoh contoh string koneksi parse dan menampilkan elemen-elemennya.

 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);
Jayesh Sorathia
sumber
4

Anda dapat menggunakan DbConnectionStringBuilder, dan Anda tidak memerlukan penyedia spesifik:

Kode berikut:

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

Output ke konsol:

Data Source: data source value
Server: ServerValue

EDIT:

Karena DbConnectionStringBuilder mengimplementasikan IDictionary Anda dapat menyebutkan parameter string koneksi:

foreach (KeyValuePair<string, object> kv in builder)
{
    Console.WriteLine("{0}: {1}", kv.Key, kv.Value);
}
Jesús López
sumber
Ini mengasumsikan Anda sudah tahu bahwa string koneksi memiliki nilai "Sumber Data", dll., Yang tidak selalu benar, seperti yang tercantum di stackoverflow.com/a/15529085/534109 , di atas.
Tieson T.
Jawaban saya menambahkan secara spesifik apa yang diminta oleh op: "Saya ingin dapat mengintip misalnya" Sumber Data "
Jesús López
Saya mengeditnya untuk menampilkan semua parameter string koneksi.
Jesús López
1

Saya tidak terlalu menyukai semua jawaban di sini. Jadi inilah yang saya temukan.

Dengan .NET Core

Anda dapat menggunakan DbConnectionStringBuildersecara langsung:

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

Jadi saya menemukan semua jawaban yang ada kurang lebih salah. Saya berakhir dengan solusi sepele berikut:

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

Parser ada di DbConnectionStringBuilder dan cukup mudah untuk didapatkan. Satu-satunya hal konyol yang harus kita lakukan adalah mengatur ShouldSerialize untuk selalu mengembalikan true untuk mencegah kehilangan komponen ketika mencoba untuk membulatkan string koneksi arbitrer.

Joshua
sumber
2
Apa yang salah dengan jawaban yang ada? Atau apa yang diperbaiki oleh solusi Anda. Penjelasan akan sangat membantu.
nawfal