¿Hay algún analizador de cadenas de conexión en C #?

181

Tengo una cadena de conexión y quiero poder ver, por ejemplo, "Fuente de datos". ¿Hay un analizador o tengo que buscar la cadena?

Amir Rezaei
fuente

Respuestas:

305

Sí, ahí está la System.Data.Common.DbConnectionStringBuilderclase.

La clase DbConnectionStringBuilder proporciona la clase base de la que derivan los constructores de cadenas de conexión fuertemente tipados (SqlConnectionStringBuilder, OleDbConnectionStringBuilder, etc.). Los creadores de cadenas de conexión permiten a los desarrolladores crear mediante programación cadenas de conexión sintácticamente correctas, y analizar y reconstruir cadenas de conexión existentes.

Las subclases de interés son:

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

Por ejemplo, para "ver el origen de datos" desde una cadena de conexión de servidor SQL, puede hacer lo siguiente:

var builder = new SqlConnectionStringBuilder(connectionString);
var dataSource = builder.DataSource;
Y yo
fuente
66
La clase base DbConnectionStringBuildertiene características de procesamiento genéricas que se pueden usar sin usar subclases:if (builder.TryGetValue("Password", out var pwd)) { string decrypted = SomehowDecrypt(pwd); builder["Password"] = decrypted; }
Olivier Jacot-Descombes
41

Hay proveedores constructores de cadena de conexión específica de diversos proveedores, como SqlConnectionStringBuilder, MySqlConnectionStringBuilder, SQLiteConnectionStringBuilderetc (por desgracia no hay ninguna interfaz pública de la MS en esta ocasión). De lo contrario, tiene DbProviderFactory.CreateConnectionStringBuilder que le dará una forma alternativa de escribirlo de manera independiente del proveedor. Debería especificar el proveedor en el archivo de configuración y tener disponible la versión correcta de dll. Por ej.

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

Una vez había escrito un análisis manual para mí, lo que no me dio ningún problema. Sería trivial extender esto para dar información sobre otros parámetros (en este momento es solo para cosas simples como nombre de base de datos, fuente de datos, nombre de usuario y contraseña). Así o más o menos:

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 esto, no necesita nada especial en el archivo de configuración, ni ningún dll. Containsen la Wherecláusula es importante solo si necesita omitir cadenas de conexiones mal formateadas como server = localhost;pp;donde no se ppagrega nada. Para comportarse como constructores normales (que explotarían en estos casos) cambie el Wherea

.Where(kvp => !string.IsNullOrWhitespace(kvp))
nawfal
fuente
@Icarus en realidad no, ya que el comparador clave del diccionario es StringComparer.InvariantCultureIgnoreCase. Ver la ToDictionarysobrecarga
nawfal
1
Sí, tienes razón, acabo de escribir una prueba rápida. Eliminaré mi comentario original ya que está mal.
Icarus
3
Su método GetValue () no funcionará en casos donde, por ejemplo, el usuario tiene una ';'o una '='contraseña. Había escrito una implementación similar y aprendí que no funciona de la manera difícil. Gosh, el análisis de la cadena de conexión es en realidad mucho más difícil de lo que pensaba.
Philip Atz
@Joshua Espero que estés hablando de la parte de análisis manual. Tome las respuestas aquí como un punto de partida en el que se podría trabajar en lugar de soluciones infalibles y probadas en batalla. Espero que sean más valiosos que los comentarios que no dejan información. También eres libre de votar a favor. Hasta donde yo sé, lo que hay que hacer más es cumplir con los estándares de análisis. MS tiene uno en msdn y me ha llevado mucho tiempo enmendarlo. Si tan solo todos tuviéramos tiempo. '@' todo, tenga en cuenta los casos extremos, especialmente uno en el comentario de Philip Atz.
nawfal
@nawfal: di la vuelta y dejé una respuesta una vez que la resolví.
Joshua
15

Aquí hay un par de líneas de código que analizarían cualquier cadena de conexión en un diccionario:

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

Y luego puedes acceder a cualquier parte:

string dataSource = connStringParts["Data Source"];
codeprose-sam
fuente
3
Inteligente, lo único que cambiaría sería incluir StringSplitOptions.RemoveEmptyEntriesen la primera división, ya que causará una IndexOutOfRangeexcepción si hay un final;
Scott Chamberlain
2
Esto funciona, pero los constructores de cadenas de conexión son más robustos. Un código como este arrojará excepciones de bajo nivel en lugar de errores de análisis más significativos en el caso de cadenas de conexión no válidas.
Sam
Esto me ayudó a analizar una cadena de conexión ADO para poder construir un equivalente SqlConnectioncon el SqlConnectionStringBuilder.
Desarrollador holístico el
Algunas advertencias aquí. Los valores de cadena de conexión se pueden incluir entre comillas, por ejemplo.
Seva Alekseyev
6

Use el SqlConnectionStringBuilder Lamentablemente, tendrá que usar un ConnectionStringBuilder específico de la base de datos, ya que las cadenas de conexión difieren.

Erno
fuente
4

Sí, puede hacerlo utilizando las clases ConnectionStringBuilder. Aquí está la lista de implementaciones de DbConnectionStringBuilder disponibles para proveedores de datos estándar:

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

Aquí hay un ejemplo de una cadena de conexión de análisis y muestra sus 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);
Jayesh Sorathia
fuente
4

Puede usar DbConnectionStringBuilder y no necesita ningún proveedor específico:

El siguiente código:

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

Salidas a la consola:

Data Source: data source value
Server: ServerValue

EDITAR:

Como DbConnectionStringBuilder implementa IDictionary, puede enumerar los parámetros de la cadena de conexión:

foreach (KeyValuePair<string, object> kv in builder)
{
    Console.WriteLine("{0}: {1}", kv.Key, kv.Value);
}
Jesús López
fuente
Esto supone que ya sabe que la cadena de conexión tiene un valor de "Fuente de datos", etc., que no siempre es cierto, como se indica en stackoverflow.com/a/15529085/534109 , arriba.
Tieson T.
Mi respuesta responde específicamente a lo que pregunta el operador: "Quiero poder mirar por ejemplo" Fuente de datos ""
Jesús López
Lo edité para mostrar todos los parámetros de la cadena de conexión.
Jesús López
1

Realmente no me gustaron todas las respuestas aquí. Así que aquí está lo que encontré.

Con .NET Core

Puedes usar DbConnectionStringBuilderdirectamente:

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

Entonces descubrí que todas las respuestas existentes estaban más o menos equivocadas. Terminé con la siguiente solución trivial:

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

El analizador está en DbConnectionStringBuilder y es bastante fácil de encontrar. La única cosa tonta que tenemos que hacer es configurar a DoesSerialize para que siempre devuelva verdadero para evitar la pérdida de componentes cuando se intentan las cadenas de conexión arbitrarias de ida y vuelta.

Joshua
fuente
2
¿Qué estaba mal con las respuestas existentes? O qué soluciona su solución. La explicación sería útil.
nawfal