Existe algum analisador de cadeia de conexão em c #?


181

Eu tenho uma cadeia de conexão e desejo poder visualizar, por exemplo, "Fonte de dados". Existe um analisador ou tenho que pesquisar a string?

Respostas:


305

Sim, tem a System.Data.Common.DbConnectionStringBuilderaula.

A classe DbConnectionStringBuilder fornece a classe base da qual derivam os construtores de cadeias de conexão fortemente tipadas (SqlConnectionStringBuilder, OleDbConnectionStringBuilder e assim por diante). Os construtores de cadeias de conexão permitem que os desenvolvedores criem programaticamente cadeias de conexão sintaticamente corretas e analisem e reconstruam as cadeias de conexão existentes.

As subclasses de interesse são:

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

Por exemplo, para "descobrir a fonte de dados" de uma cadeia de conexão do servidor SQL, você pode:

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

6
A classe base DbConnectionStringBuildertem características de processamento genéricas que podem ser usados sem usar subclasses:if (builder.TryGetValue("Password", out var pwd)) { string decrypted = SomehowDecrypt(pwd); builder["Password"] = decrypted; }
Olivier Jacot-Descombes

41

Há fornecedores construtores de cadeia de ligação específica de vários fornecedores como SqlConnectionStringBuilder, MySqlConnectionStringBuilder, SQLiteConnectionStringBuilderetc (infelizmente não há nenhuma interface pública de MS neste momento). Caso contrário, você tem o DbProviderFactory.CreateConnectionStringBuilder, que fornecerá uma maneira alternativa de escrevê-lo de maneira independente de provedor. Você precisaria especificar o provedor no arquivo de configuração e ter a versão correta da DLL disponível. Por exemplo,

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

Uma vez eu escrevi uma análise manual para mim, o que não me causou nenhum problema. Seria trivial estender isso para fornecer informações sobre outros parâmetros (agora é apenas para coisas simples, como nome db, fonte de dados, nome de usuário e senha). Assim ou assim:

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

Para isso, você não precisa de nada de especial no arquivo de configuração ou de qualquer dll. Containsna Wherecláusula é importante apenas se você precisar ignorar as cadeias de conexão mal formatadas, como server = localhost;pp;where ppadiciona a nada. Para se comportar como construtores normais (que explodiriam nesses casos), mude Wherepara

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

@ Ícarus não é verdade, pois é o comparador de chaves do dicionário StringComparer.InvariantCultureIgnoreCase. Veja a ToDictionarysobrecarga
nawfal /

1
Sim, você está certo, acabei de escrever um teste rápido. Excluirá meu comentário original, pois está errado.
Ícaro

3
Seu método GetValue () não funcionará nos casos em que, por exemplo, o usuário tenha uma ';'ou uma '='senha. Eu escrevi uma implementação semelhante e aprendi que não funciona da maneira mais difícil. Puxa, a análise de cadeia de conexão é realmente muito mais difícil do que eu pensava!
Philip Atz

@ Josué Espero que você esteja falando sobre a parte de análise manual. Por favor, tome as respostas aqui como ponto de partida que poderiam ser trabalhadas em vez de soluções infalíveis e testadas em batalha. Espero que sejam mais valiosos do que comentários que não deixam informações. Você também é livre para votar. Até onde eu sei, o que precisa ser feito é aderir aos padrões de análise. MS tem um no msdn e tem sido muito em minha mente para corrigir. Se ao menos todos tivéssemos tempo. '@' todos tenham em mente os casos extremos, especialmente um no comentário de Philip Atz.
Nawfal,

@nawfal: Eu vim e deixei uma resposta depois que a resolvi.
Joshua

15

Aqui estão algumas linhas de código que analisariam qualquer cadeia de conexão em um dicionário:

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

E então você pode acessar qualquer parte:

string dataSource = connStringParts["Data Source"];

3
Inteligente, a única coisa que mudaria seria incluir StringSplitOptions.RemoveEmptyEntriesa primeira divisão, uma vez que irá causar uma IndexOutOfRangeexceção se houver uma fuga;
Scott Chamberlain

2
Isso funciona, mas os construtores de cadeias de conexão são mais robustos. Um código como esse lançará exceções de baixo nível em vez de erros de análise mais significativos no caso de cadeias de conexão inválidas.
26413 Sam

Isso me ajudou a analisar uma cadeia de conexão ADO para que eu pudesse criar um equivalente SqlConnectioncom o SqlConnectionStringBuilder.
Holistic Developer

Algumas advertências aqui. Os valores da cadeia de conexão podem ser colocados entre aspas, por exemplo.
Seva Alekseyev



4

Sim, você pode fazer isso usando as classes ConnectionStringBuilder. Aqui está a lista de implementações disponíveis do DbConnectionStringBuilder para provedores de dados padrão:

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

Aqui está um exemplo de cadeia de conexão de análise e exibe seus elementos.

 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

Você pode usar o DbConnectionStringBuilder e não precisa de nenhum provedor específico:

O código a seguir:

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

Saídas para o console:

Data Source: data source value
Server: ServerValue

EDITAR:

Como o DbConnectionStringBuilder implementa o IDictionary, você pode enumerar os parâmetros da cadeia de conexão:

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

Isso pressupõe que você já sabe que a cadeia de conexão tem um valor "Fonte de dados" etc., o que nem sempre é verdadeiro, conforme observado em stackoverflow.com/a/15529085/534109 , acima.
Tieson T.

Minha resposta acrescenta especificamente o que a operação pergunta: 'Eu quero ser capaz de espreitar, por exemplo, "Fonte de dados" "
Jesús López

Editei-o para mostrar todos os parâmetros da cadeia de conexão.
Jesús López

1

Eu realmente não gostei de todas as respostas aqui. Então aqui está o que eu encontrei.

Com o .NET Core

Você pode usar DbConnectionStringBuilderdiretamente:

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

0

Então, descobri que todas as respostas existentes estavam mais ou menos erradas. Acabei com a seguinte solução trivial:

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

O analisador está no DbConnectionStringBuilder e é muito fácil de acessar. A única coisa boba que precisamos fazer é definir ShouldSerialize para sempre retornar true, a fim de evitar a perda de componentes ao tentar arredondar seqüências de conexão arbitrárias.


2
O que havia de errado com as respostas existentes? Ou o que sua solução corrige. A explicação seria útil.
Nawfal
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.