2011-01-26 14 views

Odpowiedz

262

Tak, istnieje klasa System.Data.Common.DbConnectionStringBuilder.

klasie DbConnectionStringBuilder zapewnia klasę bazową, z której silnie wpisany ciąg połączenia budowniczych (SqlConnectionStringBuilder, OleDbConnectionStringBuilder, i tak dalej) wyprowadzić. Łańcuch połączenia konstruktorów umożliwia programistom programowe tworzenie syntaktycznie poprawnych ciągów połączenia i analizowanie i odbudowywanie istniejących połączeń ciągów.

podklas miejsca to:

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

Na przykład, aby "wyglądać źródła danych" z ciągu połączenia SQL Server, można zrobić:

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

Użyj SqlConnectionStringBuilder Niestety, będziesz musiał użyć specyficznego dla DB ConnectionStringBuilder jako ciągów połączenia diffe r.

4

Tak, możesz to zrobić, używając klas ConnectionStringBuilder. Oto lista dostępnych wdrożeń DbConnectionStringBuilder standardowych dostawców danych:

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

oto próbka przykładem parse ciąg połączenia i wyświetli jego elementy.

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); 
30

Istnieją specyficzne sprzedawca ciąg połączenia budowniczych z różnych dostawców, jak SqlConnectionStringBuilderMySqlConnectionStringBuilder, SQLiteConnectionStringBuilder itp (niestety nie ma public interface z MS tym razem). W przeciwnym razie masz DbProviderFactory.CreateConnectionStringBuilder, który da ci alternatywny sposób, aby napisać to, co nie jest agnostyczne. Będziesz musiał określić dostawcę w pliku konfiguracyjnym i mieć odpowiednią wersję biblioteki dll. Na przykład:

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

Raz napisałem sobie ręczne parsowanie, które nie sprawiało mi żadnych kłopotów. Byłoby trywialne, aby rozszerzyć to, aby podać informacje na temat innych parametrów (teraz jest to tylko dla prostych rzeczy, takich jak nazwa bazy danych, źródło danych, nazwa użytkownika i hasło). Tak lub inaczej:

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

Do tego nie potrzeba niczego specjalnego w pliku konfiguracyjnym lub jakiejkolwiek dll w ogóle. Contains w klauzuli Where jest ważna tylko wtedy, gdy trzeba ominąć źle sformatowane ciągi połączeń, takie jak server = localhost;pp;, gdzie pp nie dodaje nic.Zachowywać się jak normalne budowniczych (które wybuchają w tych przypadkach) zmienić Where do

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

@Icarus nie jest tak naprawdę, ponieważ słownik porównywania słów jest "StringComparer.InvariantCultureIgnoreCase". Zobacz przeciążenie 'ToDictionary' – nawfal

+1

Tak, masz rację, właśnie napisałem szybki test. Usunie mój oryginalny komentarz, ponieważ jest nieprawidłowy. – Icarus

+2

Twoja metoda GetValue() nie będzie działać w przypadkach, gdy użytkownik ma na przykład hasło ""; "" lub "" = "" w swoim haśle. Napisałem podobną implementację i dowiedziałem się, że to nie działa na swój sposób. Gosh, parsowanie połączenia jest w rzeczywistości o wiele trudniejsze, niż myślałem! –

11

Oto kilka linijek kodu, które zanalizować dowolny ciąg połączenia do słownika:

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

a następnie mogą uzyskać dostęp do każdej części:

string dataSource = connStringParts["Data Source"]; 
+2

Inteligentne, jedyne, co chciałbym zmienić, to "StringSplitOptions.RemoveEmptyEntries" do pierwszego podziału, ponieważ spowoduje on wyjątek 'IndexOutOfRange', jeśli istnieje końcowe'; ' –

+2

To działa, ale konstruktory połączeń są bardziej niezawodne . Kod taki jak ten spowoduje odrzucanie wyjątków niskiego poziomu zamiast bardziej znaczących błędów analizy w przypadku nieprawidłowych ciągów połączeń. – Sam

+0

Pomogło mi to przetworzyć ciąg połączenia ADO, tak żebym mógł zbudować odpowiednik 'SqlConnection' z' SqlConnectionStringBuilder'. –

2

można użyć DbConnectionStringBuilder, i nie trzeba żadnego konkretnego dostawcy:

Poniższy kod:

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

Wyjścia pocieszyć:

Data Source: data source value 
Server: ServerValue 

EDIT:

Od DbConnectionStringBuilder implementuje IDictionary można wyliczyć parametry ciągu połączenia:

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

Zakłada to, że już wiesz, że ciąg połączenia ma wartość "Źródło danych" itp., Co nie zawsze jest prawdą, jak wspomniano powyżej w http://stackoverflow.com/a/15529085/534109. –

+0

Moja odpowiedź dodaje konkretnie, co op pyta: "Chcę mieć możliwość podglądu na przykład" Źródło danych "' –

+0

Edytowałem to, aby pokazać wszystkie parametry ciągu połączenia. –

0

Więc znalazłem wszystko, co istnieje odpowiedzi były mniej lub bardziej błędne. Skończyło się następujące rozwiązanie trywialne:

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

Parser jest w DbConnectionStringBuilder i dość dużo łatwo dotrzeć. Jedyną głupią rzeczą, którą musimy zrobić, to ustawić opcję ShouldSerialize tak, aby zawsze zwracała wartość true, aby zapobiec utracie komponentów podczas próby oblężenia arbitralnych ciągów połączeń.

+1

Co było nie tak z istniejącymi odpowiedziami? Albo co rozwiązuje twoje rozwiązanie. Pomocne byłoby wyjaśnienie. – nawfal

Powiązane problemy