Is there any connection string parser in C#?

Solution 1:

Yes, there's the System.Data.Common.DbConnectionStringBuilder class.

The DbConnectionStringBuilder class provides the base class from which the strongly typed connection string builders (SqlConnectionStringBuilder, OleDbConnectionStringBuilder, and so on) derive. The connection string builders let developers programmatically create syntactically correct connection strings, and parse and rebuild existing connection strings.

The subclasses of interest are:

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

For example, to "peek out the Data Source" from a SQL-server connection string, you can do:

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

Solution 2:

There are vendor specific connection string builders from various providers like SqlConnectionStringBuilder, MySqlConnectionStringBuilder, SQLiteConnectionStringBuilder etc (unfortunately there is no public interface from MS this time). Otherwise you have DbProviderFactory.CreateConnectionStringBuilder which will give you an alternate way to write it provider-agnostic way. You would need to specify provider in config file and have the right version of dll available. For eg.,

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

I had once written manual parsing for myself which did not give me any trouble. It would be trivial to extend this to give info on other parameters (right now its only for simple things like db name, data source, username and password). Like this or so:

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

For this you don't need anything special in config file, or any dll at all. Contains in Where clause is important only if you need to bypass poorly formatted connectionstrings like server = localhost;pp; where pp adds to nothing. To behave like normal builders (which would explode in these cases) change the Where to

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

Solution 3:

Here's a couple lines of code that would parse any connection string into a dictionary:

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

And then you can access any part:

string dataSource = connStringParts["Data Source"];