มีตัวแยกวิเคราะห์สตริงการเชื่อมต่อใน 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; }
Olivier Jacot-Descombes

41

มีผู้สร้างสตริงการเชื่อมต่อเฉพาะของผู้ขายจากผู้ให้บริการที่หลากหลายเช่นSqlConnectionStringBuilder, MySqlConnectionStringBuilderและSQLiteConnectionStringBuilderอื่น ๆ (น่าเสียดายที่ไม่มีอินเทอร์เฟซสาธารณะจาก 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;
}

สำหรับสิ่งนี้คุณไม่ต้องการอะไรเป็นพิเศษในไฟล์ config หรือ dll ใด ๆ เลย ContainsในWhereข้อมีความสำคัญเฉพาะในกรณีที่คุณต้องหลีกเลี่ยงการเชื่อมต่อรูปแบบการเชื่อมต่อที่ไม่ดีเช่นserver = localhost;pp;ที่ppเพิ่มอะไร การทำตัวเหมือนผู้สร้างปกติ (ซึ่งจะระเบิดในกรณีเหล่านี้) เปลี่ยนWhereไป

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

@Icarus ไม่ได้จริงๆตั้งแต่พจนานุกรมของ Comparer StringComparer.InvariantCultureIgnoreCaseที่สำคัญคือ ดูToDictionaryเกินพิกัด
nawfal

1
ใช่คุณพูดถูกฉันเพิ่งเขียนแบบทดสอบสั้น ๆ จะลบความคิดเห็นดั้งเดิมของฉันเพราะมันผิด
อิคารัส

3
วิธี GetValue () ของคุณจะไม่ทำงานในกรณีที่ตัวอย่างเช่นผู้ใช้มี';'หรือ'='ในรหัสผ่านของพวกเขา ฉันเขียนการใช้งานที่คล้ายกันและเรียนรู้ว่ามันไม่ได้ทำงานอย่างหนัก เอ้วววววววววววการแยกวยวกับสตริงแล้วจะหนักกว่
Philip Atz

@ โจชัวฉันหวังว่าคุณกำลังพูดถึงส่วนแยกวิเคราะห์ด้วยตนเอง โปรดใช้คำตอบที่นี่เป็นจุดเริ่มต้นที่สามารถใช้งานได้มากกว่าที่จะเข้าใจผิดและวิธีการทดสอบการต่อสู้ ฉันหวังว่าพวกเขาจะมีค่ามากกว่าความคิดเห็นที่ไม่มีข้อมูล คุณมีอิสระที่จะลงคะแนน เท่าที่ฉันรู้สิ่งที่ต้องทำต่อไปเป็นไปตามมาตรฐานการแยก MS มีหนึ่งอันบน msdn และอยู่ในใจฉันนานแล้วที่จะทำลาย ถ้าเพียงเราทุกคนมีเวลา '@' ทั้งหมดโปรดจำไว้ในกรณีที่ขอบ, หนึ่งในความคิดเห็นของ Philip Atz
nawfal

@nawfal: ฉันมาแล้วทิ้งคำตอบเมื่อฉันแก้ไขมัน
Joshua

15

นี่คือโค้ดสองสามบรรทัดที่จะแยกสตริงการเชื่อมต่อใด ๆ ลงในพจนานุกรม:

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ข้อยกเว้นหากมีการติดตาม;
Scott Chamberlain

2
ใช้งานได้ แต่ผู้สร้างสตริงการเชื่อมต่อมีความแข็งแกร่งมากขึ้น รหัสเช่นนี้จะส่งข้อยกเว้นระดับต่ำแทนข้อผิดพลาดในการแยกวิเคราะห์ที่มีความหมายมากขึ้นในกรณีที่สตริงการเชื่อมต่อไม่ถูกต้อง
Sam

นี้ช่วยให้ฉันแยกสตริงเชื่อมต่อ ADO ดังนั้นฉันสามารถสร้างเทียบเท่ากับSqlConnection SqlConnectionStringBuilder
นักพัฒนาแบบองค์รวม

คำเตือนบางอย่างที่นี่ ค่าสตริงการเชื่อมต่อสามารถอยู่ในเครื่องหมายคำพูดตัวอย่างเช่น
Seva Alekseyev

6

ใช้SqlConnectionStringBuilder น่าเสียดายที่คุณจะต้องใช้ ConnectionStringBuilder เฉพาะของ DB เนื่องจากสตริงการเชื่อมต่อแตกต่างกัน


6

คุณต้องการใช้DbProviderFactory.CreateConnectionStringBuilder ()ซึ่งให้ตัวสร้างสตริงการเชื่อมต่อ / parser เฉพาะสำหรับตัวเชื่อมต่อของคุณ แต่ไม่ต้องการให้คุณใช้คลาสเฉพาะของตัวเชื่อมต่อใด ๆ


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.

คำตอบของฉันเพิ่มเฉพาะสิ่งที่ op ถาม: 'ฉันต้องการที่จะสามารถดูตัวอย่างเช่น "Data Source"'
JesúsLópez

ฉันแก้ไขมันเพื่อแสดงพารามิเตอร์สตริงการเชื่อมต่อทั้งหมด
JesúsLópez

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

parser อยู่ใน DbConnectionStringBuilder และง่ายมากที่จะไปที่ สิ่งเดียวที่เราต้องทำคือการตั้งค่า ShouldSerialize ให้คืนค่าจริงเสมอเพื่อป้องกันการสูญเสียส่วนประกอบเมื่อพยายามที่จะเดินทางไปรอบ ๆ สตริงการเชื่อมต่อโดยพลการ


2
เกิดอะไรขึ้นกับคำตอบที่มีอยู่ หรือโซลูชันของคุณแก้ไขอะไร คำอธิบายจะเป็นประโยชน์
nawfal
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.