Existe-t-il un analyseur de chaîne de connexion en C #?

181

J'ai une chaîne de connexion et je veux pouvoir voir par exemple "Source de données". Existe-t-il un analyseur ou dois-je rechercher la chaîne?

Amir Rezaei
la source

Réponses:

305

Oui, il y a la System.Data.Common.DbConnectionStringBuilderclasse.

La classe DbConnectionStringBuilder fournit la classe de base à partir de laquelle dérivent les générateurs de chaînes de connexion fortement typées (SqlConnectionStringBuilder, OleDbConnectionStringBuilder, etc.). Les générateurs de chaînes de connexion permettent aux développeurs de créer par programme des chaînes de connexion syntaxiquement correctes, et d'analyser et de reconstruire les chaînes de connexion existantes.

Les sous-classes d'intérêt sont:

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

Par exemple, pour "jeter un œil à la source de données" à partir d'une chaîne de connexion SQL-server, vous pouvez faire:

var builder = new SqlConnectionStringBuilder(connectionString);
var dataSource = builder.DataSource;
Ani
la source
6
La classe de base DbConnectionStringBuildera des fonctionnalités de traitement génériques qui peuvent être utilisées sans utiliser de sous-classes:if (builder.TryGetValue("Password", out var pwd)) { string decrypted = SomehowDecrypt(pwd); builder["Password"] = decrypted; }
Olivier Jacot-Descombes
41

Il y a des constructeurs de chaîne de connexion spécifique des fournisseurs de divers fournisseurs tels que SqlConnectionStringBuilder, MySqlConnectionStringBuilder, SQLiteConnectionStringBuilderetc (malheureusement il n'y a pas d' interface publique de MS cette fois -ci ). Sinon, vous avez DbProviderFactory.CreateConnectionStringBuilder qui vous donnera une autre façon de l'écrire de manière indépendante du fournisseur. Vous devrez spécifier le fournisseur dans le fichier de configuration et disposer de la bonne version de la dll. Par exemple.,

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

J'avais une fois écrit une analyse manuelle pour moi-même, ce qui ne me posait aucun problème. Il serait trivial d'étendre cela pour donner des informations sur d'autres paramètres (pour le moment, ce n'est que pour des choses simples comme le nom de la base de données, la source de données, le nom d'utilisateur et le mot de passe). Comme ceci ou deux:

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

Pour cela, vous n'avez besoin de rien de spécial dans le fichier de configuration, ni d'aucune dll. ContainsLa Whereclause in n'est importante que si vous avez besoin de contourner les chaînes de connexion mal formatées comme server = localhost;pp;ppn'ajoute rien. Pour se comporter comme les constructeurs normaux (qui exploserait dans ces cas) changer Whereà

.Where(kvp => !string.IsNullOrWhitespace(kvp))
nawfal
la source
@Icarus pas vraiment puisque le comparateur clé du dictionnaire est StringComparer.InvariantCultureIgnoreCase. Voir la ToDictionarysurcharge
nawfal
1
Oui, vous avez raison, je viens d'écrire un test rapide. Va supprimer mon commentaire d'origine car il est faux.
Icarus
3
Votre méthode GetValue () ne fonctionnera pas dans les cas où, par exemple, l'utilisateur a un ';'ou un '='dans son mot de passe. J'avais écrit une implémentation similaire et appris qu'elle ne fonctionnait pas à la dure. Gosh, l'analyse des chaînes de connexion est en fait beaucoup plus difficile que je ne le pensais!
Philip Atz
@Joshua J'espère que vous parlez de la partie d'analyse manuelle. Veuillez prendre les réponses ici comme point de départ sur lequel travailler plutôt que sur des solutions infaillibles et testées au combat. J'espère qu'ils sont plus précieux que les commentaires qui ne laissent aucune information. Vous êtes également libre de voter contre. Autant que je sache, ce qui doit être fait, c'est adhérer aux normes d'analyse. MS en a un sur msdn et cela fait longtemps que je pense à l'amender. Si seulement nous avions tous le temps. '@', veuillez tous garder à l'esprit les cas extrêmes, en particulier un dans le commentaire de Philip Atz.
nawfal
@nawfal: Je suis venu et j'ai laissé une réponse une fois que je l'ai résolue.
Joshua du
15

Voici quelques lignes de code qui analysent n'importe quelle chaîne de connexion dans un dictionnaire:

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

Et puis vous pouvez accéder à n'importe quelle partie:

string dataSource = connStringParts["Data Source"];
codeprose-sam
la source
3
Intelligent, la seule chose que je changerais serait d'inclure StringSplitOptions.RemoveEmptyEntriesla première division, car cela causera une IndexOutOfRangeexception s'il y a un suivi;
Scott Chamberlain
2
Cela fonctionne, mais les générateurs de chaînes de connexion sont plus robustes. Un code comme celui-ci lèvera des exceptions de bas niveau au lieu d'erreurs d'analyse plus significatives dans le cas de chaînes de connexion non valides.
Sam le
Cela m'a aidé à analyser une chaîne de connexion ADO afin que je puisse créer un équivalent SqlConnectionavec le SqlConnectionStringBuilder.
Développeur holistique
Quelques mises en garde ici. Les valeurs de chaîne de connexion peuvent être placées entre guillemets, par exemple.
Seva Alekseyev
6

Utilisez le SqlConnectionStringBuilder Malheureusement, vous devrez utiliser un ConnectionStringBuilder spécifique à la base de données car les chaînes de connexion diffèrent.

Euh non
la source
4

Oui, vous pouvez le faire à l'aide des classes ConnectionStringBuilder. Voici la liste des implémentations DbConnectionStringBuilder disponibles pour les fournisseurs de données standard:

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

Voici un exemple d'exemple d'analyse de la chaîne de connexion et d'afficher ses éléments.

 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
la source
4

Vous pouvez utiliser DbConnectionStringBuilder et vous n'avez besoin d'aucun fournisseur spécifique:

Le code suivant:

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

Sorties vers la console:

Data Source: data source value
Server: ServerValue

ÉDITER:

Puisque DbConnectionStringBuilder implémente IDictionary, vous pouvez énumérer les paramètres de la chaîne de connexion:

foreach (KeyValuePair<string, object> kv in builder)
{
    Console.WriteLine("{0}: {1}", kv.Key, kv.Value);
}
Jesús López
la source
Cela suppose que vous savez déjà que la chaîne de connexion a une valeur "Source de données", etc., ce qui n'est pas toujours vrai, comme indiqué dans stackoverflow.com/a/15529085/534109 , ci-dessus.
Tieson T.
Ma réponse contient spécifiquement ce que l’op a demandé: «Je veux pouvoir jeter un coup d’œil, par exemple« Source de données »»
Jesús López
Je l'ai modifié pour afficher tous les paramètres de chaîne de connexion.
Jesús López
1

Je n'ai pas vraiment aimé toutes les réponses ici. Voici donc ce que j'ai trouvé.

Avec .NET Core

Vous pouvez utiliser DbConnectionStringBuilderdirectement:

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

J'ai donc trouvé que toutes les réponses existantes étaient plus ou moins fausses. J'ai fini avec la solution triviale suivante:

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

L'analyseur est dans DbConnectionStringBuilder et assez facile d'accès. La seule chose idiote que nous devons faire est de définir ShouldSerialize pour toujours retourner true pour éviter de perdre des composants lorsque vous essayez d'aller-retour des chaînes de connexion arbitraires.

Joshua
la source
2
Quel était le problème avec les réponses existantes? Ou qu'est-ce que votre solution corrige. Une explication serait utile.
nawfal