Есть ли в 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; }
Оливье Жако-Дескомбс

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

Однажды я написал для себя ручной анализ, который не доставлял мне никаких проблем. Было бы тривиально расширить это, чтобы предоставить информацию о других параметрах (сейчас это только для простых вещей, таких как имя базы данных, источник данных, имя пользователя и пароль). Как это или так:

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;где ppничего не добавляет. Для того, чтобы вести себя как нормальные строители (которые взрываются в этих случаях) изменить WhereTo

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

@Icarus не совсем, так как ключевой компаратор словаря есть StringComparer.InvariantCultureIgnoreCase. Смотрите ToDictionaryперегрузку
nawfal

1
Да, вы правы, я только что написал быстрый тест. Удалит мой оригинальный комментарий, так как это неправильно.
Икар

3
Ваш метод GetValue () не будет работать в тех случаях, когда, например, у пользователя есть пароль ';'или '='пароль. Я написал аналогичную реализацию и узнал, что она не работает сложным путем. Черт возьми, разбор строки соединения на самом деле намного сложнее, чем я думал!
Филипп Ац

@ Джошуа, я надеюсь, ты говоришь о ручном разборе. Пожалуйста, примите ответы здесь как отправную точку, над которой можно работать, а не надёжными и проверенными в бою решениями. Я надеюсь, что они более ценны, чем комментарии, которые не оставляют информации. Вы также можете понизить голос. Насколько я знаю, что нужно сделать дальше - придерживаться стандартов разбора. У MS есть один на MSDN, и я долго думал, что исправить. Если бы у всех нас было время. '@' все, пожалуйста, помните о крайних случаях, особенно в комментарии Филиппа Аца.
nawfal

@nawfal: я пришел и оставил ответ, как только решил.
Джошуа

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исключение, если есть трейлинг;
Скотт Чемберлен

2
Это работает, но компоновщики строки соединения более надежны. Подобный код будет генерировать низкоуровневые исключения вместо более значимых ошибок синтаксического анализа в случае недопустимых строк подключения.
Сэм

Это помогло мне разобрать строку подключения ADO, чтобы я мог создать эквивалент SqlConnectionс SqlConnectionStringBuilder.
Целостный разработчик

Некоторые предостережения здесь. Например, значения строки подключения могут быть заключены в кавычки.
Сева Алексеев

6

Используйте SqlConnectionStringBuilder. К сожалению, вам придется использовать специфичный для БД ConnectionStringBuilder, поскольку строки подключения различаются.


6

Вы хотите использовать DbProviderFactory.CreateConnectionStringBuilder (), который предоставляет вам компоновщик / синтаксический анализатор строки соединения, специфичный для вашего коннектора, но не требует использования каких-либо классов, специфичных для коннектора.


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.

Мой ответ точно соответствует тому, что спрашивают оперы: «Я хочу иметь возможность посмотреть, например,« Источник данных »»
Хесус Лопес

Я отредактировал его, чтобы показать все параметры строки подключения.
Хесус Лопес

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 и довольно прост в обращении. Единственная глупость, которую мы должны сделать, - это установить ShouldSerialize так, чтобы он всегда возвращал true, чтобы предотвратить потерю компонентов при попытке обхода произвольных строк соединения.


2
Что не так с существующими ответами? Или что исправляет ваше решение. Объяснение было бы полезно.
Nawfal
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.