Esiste un parser di stringhe di connessione in C #?


181

Ho una stringa di connessione e voglio essere in grado di dare un'occhiata ad esempio "Origine dati". Esiste un parser o devo cercare la stringa?

Risposte:


305

Sì, c'è la System.Data.Common.DbConnectionStringBuilderclasse.

La classe DbConnectionStringBuilder fornisce la classe base da cui derivano i costruttori di stringhe di connessione fortemente tipizzati (SqlConnectionStringBuilder, OleDbConnectionStringBuilder e così via). I costruttori di stringhe di connessione consentono agli sviluppatori di creare a livello di codice stringhe di connessione sintatticamente corrette e di analizzare e ricostruire stringhe di connessione esistenti.

Le sottoclassi di interesse sono:

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

Ad esempio, per "sbirciare l'origine dati" da una stringa di connessione del server SQL, è possibile eseguire:

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

6
La classe base DbConnectionStringBuilderha funzionalità di elaborazione generiche che possono essere utilizzate senza l'utilizzo di sottoclassi:if (builder.TryGetValue("Password", out var pwd)) { string decrypted = SomehowDecrypt(pwd); builder["Password"] = decrypted; }
Olivier Jacot-Descombes,

41

Ci sono vendor costruttori stringa di connessione specifica di diversi fornitori come SqlConnectionStringBuilder, MySqlConnectionStringBuilder, SQLiteConnectionStringBuilderecc (purtroppo non c'è interfaccia pubblica da MS questa volta). Altrimenti hai DbProviderFactory.CreateConnectionStringBuilder che ti darà un modo alternativo per scriverlo in modo indipendente dal provider. Dovresti specificare il provider nel file di configurazione e avere la versione corretta di dll disponibile. Per es.,

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 volta avevo scritto l'analisi manuale per me stesso, il che non mi dava problemi. Sarebbe banale estenderlo per fornire informazioni su altri parametri (in questo momento è solo per cose semplici come nome db, origine dati, nome utente e password). In questo modo:

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

Per questo non hai bisogno di nulla di speciale nel file di configurazione o di alcuna dll. Containsnella Whereclausola in è importante solo se è necessario bypassare stringhe di connessione scarsamente formattate come server = localhost;pp;dove non si ppaggiunge nulla. Per comportarsi come normali costruttori (che esploderebbero in questi casi), cambia Wherein

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

@Icarus non proprio dal momento che il comparatore chiave del dizionario è StringComparer.InvariantCultureIgnoreCase. Vedi il ToDictionarysovraccarico
nawfal

1
Sì, hai ragione, ho appena scritto un test rapido. Eliminerà il mio commento originale poiché è sbagliato.
Icaro

3
Il metodo GetValue () non funzionerà nei casi in cui ad esempio l'utente ha un ';'o un '='nella propria password. Avevo scritto un'implementazione simile e ho imparato che non funziona nel modo più duro. Accidenti, l'analisi delle stringhe di connessione è in realtà molto più difficile di quanto pensassi!
Philip Atz,

@Joshua Spero che tu stia parlando della parte di analisi manuale. Prendi le risposte qui come punto di partenza su cui si potrebbe lavorare piuttosto che soluzioni infallibili e testate in battaglia. Spero che siano più preziosi dei commenti che non lasciano informazioni. Sei anche libero di votare. Per quanto ne so, ciò che deve essere ulteriormente fatto è aderire agli standard di analisi. MS ne ha uno su msdn ed è passato molto tempo nella mia mente per ammendare. Se solo avessimo avuto del tempo. '@' tutti, per favore, tieni a mente i casi limite, specialmente uno nel commento di Philip Atz.
nawfal,

@nawfal: sono venuto in giro e ho lasciato una risposta dopo averlo risolto.
Joshua,

15

Ecco un paio di righe di codice che analizzerebbero qualsiasi stringa di connessione in un dizionario:

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 quindi puoi accedere a qualsiasi parte:

string dataSource = connStringParts["Data Source"];

3
Intelligente, l'unica cosa che cambierei sarebbe includere StringSplitOptions.RemoveEmptyEntriesnella prima divisione in quanto causerebbe IndexOutOfRangeun'eccezione se c'è un trailing;
Scott Chamberlain

2
Funziona, ma i costruttori di stringhe di connessione sono più robusti. Codice come questo genererà eccezioni di basso livello anziché errori di analisi più significativi nel caso di stringhe di connessione non valide.
Sam,

Questo mi ha aiutato ad analizzare una stringa di connessione ADO in modo da poter costruire un equivalente SqlConnectioncon SqlConnectionStringBuilder.
Sviluppatore olistico,

Alcuni avvertimenti qui. I valori della stringa di connessione possono essere racchiusi tra virgolette, ad esempio.
Seva Alekseyev,



4

Sì, puoi farlo utilizzando le classi ConnectionStringBuilder. Ecco l'elenco delle implementazioni DbConnectionStringBuilder disponibili per i fornitori di dati standard:

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

ecco un esempio di stringa di connessione di analisi e mostra i suoi elementi.

 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

È possibile utilizzare DbConnectionStringBuilder e non è necessario alcun provider specifico:

Il seguente codice:

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

Uscite per console:

Data Source: data source value
Server: ServerValue

MODIFICARE:

Poiché DbConnectionStringBuilder implementa IDictionary, è possibile enumerare i parametri della stringa di connessione:

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

Ciò presuppone che tu sappia già che la stringa di connessione ha un valore "Origine dati", ecc., Che non è sempre vero, come indicato in stackoverflow.com/a/15529085/534109 , sopra.
Tieson T.

La mia risposta aggiunge in particolare ciò che l'opera chiede: 'Voglio essere in grado di dare un'occhiata ad esempio "Fonte dei dati"'
Jesús López,

L'ho modificato per mostrare tutti i parametri della stringa di connessione.
Jesús López,

1

Non mi sono piaciute davvero tutte le risposte qui. Quindi ecco quello che ho trovato.

Con .NET Core

Puoi usare DbConnectionStringBuilderdirettamente:

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

0

Quindi ho scoperto che tutte le risposte esistenti erano più o meno sbagliate. Ho finito con la seguente banale soluzione:

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

Il parser è in DbConnectionStringBuilder ed è praticamente facile da raggiungere. L'unica cosa sciocca che dobbiamo fare è impostare ShouldSerialize in modo che ritorni sempre true per evitare la perdita di componenti quando si tenta di far circolare le stringhe di connessione arbitrarie.


2
Cosa c'era di sbagliato nelle risposte esistenti? O cosa risolve la tua soluzione. La spiegazione sarebbe utile.
nawfal,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.