How to read a connectionString WITH PROVIDER in .NET Core?










6















I added



.AddJsonFile("Connections.json", optional: true, reloadOnChange: true)


in



 public Startup(IHostingEnvironment env)


Connections.json contains:




"ConnectionStrings":
"DefaultConnection": "Server=(localdb)\mssqllocaldb;Database=DATABASE;Trusted_Connection=True;MultipleActiveResultSets=true",
"COR-W81-101": "Data Source=DATASOURCE;Initial Catalog=P61_CAFM_Basic;User Id=USERID;Password=PASSWORD;Persist Security Info=False;MultipleActiveResultSets=False;Packet Size=4096;",
"COR-W81-100": "Data Source=DATASOURCE;Initial Catalog=Post_PS;User Id=USERID;Password=PASSWORD;Persist Security Info=False;MultipleActiveResultSets=False;Packet Size=4096;",
"MSEDGEWIN10": "Data Source=DATASOURCE; Initial Catalog=COR_Basic; Persist Security Info=False;Integrated Security=true;MultipleActiveResultSets=False;Packet Size=4096;Application Name="COR_Basic"",

"server": "Data Source=DATASOURCE; Initial Catalog=COR_Basic; Persist Security Info=False;User Id=USERID;Password=PASSWORD;MultipleActiveResultSets=False;Packet Size=4096;Application Name="COR_Basic""
,


"conStrings": [

"name": "COR-W81-101",
"connectionString": "Data Source=DATASOURCE; Initial Catalog=COR_Basic; Persist Security Info=False;Integrated Security=true;MultipleActiveResultSets=False;Packet Size=4096;Application Name="COR_Basic"",
"providerName": "System.Data.SqlClient"


,


"name": "server",
"connectionString": "Data Source=DATASOURCE; Initial Catalog=COR_Basic; Persist Security Info=False;Integrated Security=true;MultipleActiveResultSets=False;Packet Size=4096;Application Name="COR_Basic"",
"providerName": "System.Data.SqlClient"

],



"conStringDictionary":
"COR-W81-101":
"connectionString": "Data Source=DATASOURCE; Initial Catalog=COR_Basic; Persist Security Info=False;Integrated Security=true;MultipleActiveResultSets=False;Packet Size=4096;Application Name="COR_Basic"",
"providerName": "System.Data.SqlClient"
,

"server":
"connectionString": "Data Source=DATASOURCE; Initial Catalog=COR_Basic; Persist Security Info=False;Integrated Security=true;MultipleActiveResultSets=False;Packet Size=4096;Application Name="COR_Basic"",
"providerName": "System.Data.SqlClient"



}


Now I wanted to read the connectionStrings:



public class ConnectionString

public string name get; set;
public string connectionString get; set;
public string providerName get; set;



like this:



//Microsoft.Extensions.DependencyInjection.OptionsConfigurationServiceCollectionExtensions.Configure<ConnectionString>(services, Configuration.GetSection("conStrings"));

// https://stackoverflow.com/questions/31929482/retrieve-sections-from-config-json-in-asp-net-5
//var objectSections = Configuration.GetSection("conStringDictionary").GetChildren();
//foreach (var x in objectSections)
//
// System.Console.WriteLine(x.Key);
// var cs = new ConnectionString();
// ConfigurationBinder.Bind(x, cs);
// System.Console.WriteLine(cs);
//

// http://andrewlock.net/how-to-use-the-ioptions-pattern-for-configuration-in-asp-net-core-rc2/
Microsoft.Extensions.DependencyInjection.OptionsConfigurationServiceCollectionExtensions.Configure<Dictionary<string, ConnectionString>>(services, Configuration.GetSection("conStrings"));


But I can't get it to read the array or the dictionary. I need the providerName for each connectionString, and I want to have it in the same entry as the connection string, but not as a joined string.










share|improve this question
























  • Your Connections.json is invalid. Your "conStrings" array have to much "}" . It should look like jsoneditoronline.org/?id=a00f0105a65d6a651d872ea9688d6147

    – M. Wiśnicki
    Nov 28 '16 at 13:57






  • 5





    Dude, you just posted connection string to your databases to public view. Consider to remove passwords at least!

    – Maris
    Nov 28 '16 at 14:09











  • @Maris: Doesn't matter, changed them before I posted - forgot one, but it was TrippleDES encrypted anyway. The datasource isn't confidential anyway.

    – user6038265
    Nov 28 '16 at 17:12
















6















I added



.AddJsonFile("Connections.json", optional: true, reloadOnChange: true)


in



 public Startup(IHostingEnvironment env)


Connections.json contains:




"ConnectionStrings":
"DefaultConnection": "Server=(localdb)\mssqllocaldb;Database=DATABASE;Trusted_Connection=True;MultipleActiveResultSets=true",
"COR-W81-101": "Data Source=DATASOURCE;Initial Catalog=P61_CAFM_Basic;User Id=USERID;Password=PASSWORD;Persist Security Info=False;MultipleActiveResultSets=False;Packet Size=4096;",
"COR-W81-100": "Data Source=DATASOURCE;Initial Catalog=Post_PS;User Id=USERID;Password=PASSWORD;Persist Security Info=False;MultipleActiveResultSets=False;Packet Size=4096;",
"MSEDGEWIN10": "Data Source=DATASOURCE; Initial Catalog=COR_Basic; Persist Security Info=False;Integrated Security=true;MultipleActiveResultSets=False;Packet Size=4096;Application Name="COR_Basic"",

"server": "Data Source=DATASOURCE; Initial Catalog=COR_Basic; Persist Security Info=False;User Id=USERID;Password=PASSWORD;MultipleActiveResultSets=False;Packet Size=4096;Application Name="COR_Basic""
,


"conStrings": [

"name": "COR-W81-101",
"connectionString": "Data Source=DATASOURCE; Initial Catalog=COR_Basic; Persist Security Info=False;Integrated Security=true;MultipleActiveResultSets=False;Packet Size=4096;Application Name="COR_Basic"",
"providerName": "System.Data.SqlClient"


,


"name": "server",
"connectionString": "Data Source=DATASOURCE; Initial Catalog=COR_Basic; Persist Security Info=False;Integrated Security=true;MultipleActiveResultSets=False;Packet Size=4096;Application Name="COR_Basic"",
"providerName": "System.Data.SqlClient"

],



"conStringDictionary":
"COR-W81-101":
"connectionString": "Data Source=DATASOURCE; Initial Catalog=COR_Basic; Persist Security Info=False;Integrated Security=true;MultipleActiveResultSets=False;Packet Size=4096;Application Name="COR_Basic"",
"providerName": "System.Data.SqlClient"
,

"server":
"connectionString": "Data Source=DATASOURCE; Initial Catalog=COR_Basic; Persist Security Info=False;Integrated Security=true;MultipleActiveResultSets=False;Packet Size=4096;Application Name="COR_Basic"",
"providerName": "System.Data.SqlClient"



}


Now I wanted to read the connectionStrings:



public class ConnectionString

public string name get; set;
public string connectionString get; set;
public string providerName get; set;



like this:



//Microsoft.Extensions.DependencyInjection.OptionsConfigurationServiceCollectionExtensions.Configure<ConnectionString>(services, Configuration.GetSection("conStrings"));

// https://stackoverflow.com/questions/31929482/retrieve-sections-from-config-json-in-asp-net-5
//var objectSections = Configuration.GetSection("conStringDictionary").GetChildren();
//foreach (var x in objectSections)
//
// System.Console.WriteLine(x.Key);
// var cs = new ConnectionString();
// ConfigurationBinder.Bind(x, cs);
// System.Console.WriteLine(cs);
//

// http://andrewlock.net/how-to-use-the-ioptions-pattern-for-configuration-in-asp-net-core-rc2/
Microsoft.Extensions.DependencyInjection.OptionsConfigurationServiceCollectionExtensions.Configure<Dictionary<string, ConnectionString>>(services, Configuration.GetSection("conStrings"));


But I can't get it to read the array or the dictionary. I need the providerName for each connectionString, and I want to have it in the same entry as the connection string, but not as a joined string.










share|improve this question
























  • Your Connections.json is invalid. Your "conStrings" array have to much "}" . It should look like jsoneditoronline.org/?id=a00f0105a65d6a651d872ea9688d6147

    – M. Wiśnicki
    Nov 28 '16 at 13:57






  • 5





    Dude, you just posted connection string to your databases to public view. Consider to remove passwords at least!

    – Maris
    Nov 28 '16 at 14:09











  • @Maris: Doesn't matter, changed them before I posted - forgot one, but it was TrippleDES encrypted anyway. The datasource isn't confidential anyway.

    – user6038265
    Nov 28 '16 at 17:12














6












6








6








I added



.AddJsonFile("Connections.json", optional: true, reloadOnChange: true)


in



 public Startup(IHostingEnvironment env)


Connections.json contains:




"ConnectionStrings":
"DefaultConnection": "Server=(localdb)\mssqllocaldb;Database=DATABASE;Trusted_Connection=True;MultipleActiveResultSets=true",
"COR-W81-101": "Data Source=DATASOURCE;Initial Catalog=P61_CAFM_Basic;User Id=USERID;Password=PASSWORD;Persist Security Info=False;MultipleActiveResultSets=False;Packet Size=4096;",
"COR-W81-100": "Data Source=DATASOURCE;Initial Catalog=Post_PS;User Id=USERID;Password=PASSWORD;Persist Security Info=False;MultipleActiveResultSets=False;Packet Size=4096;",
"MSEDGEWIN10": "Data Source=DATASOURCE; Initial Catalog=COR_Basic; Persist Security Info=False;Integrated Security=true;MultipleActiveResultSets=False;Packet Size=4096;Application Name="COR_Basic"",

"server": "Data Source=DATASOURCE; Initial Catalog=COR_Basic; Persist Security Info=False;User Id=USERID;Password=PASSWORD;MultipleActiveResultSets=False;Packet Size=4096;Application Name="COR_Basic""
,


"conStrings": [

"name": "COR-W81-101",
"connectionString": "Data Source=DATASOURCE; Initial Catalog=COR_Basic; Persist Security Info=False;Integrated Security=true;MultipleActiveResultSets=False;Packet Size=4096;Application Name="COR_Basic"",
"providerName": "System.Data.SqlClient"


,


"name": "server",
"connectionString": "Data Source=DATASOURCE; Initial Catalog=COR_Basic; Persist Security Info=False;Integrated Security=true;MultipleActiveResultSets=False;Packet Size=4096;Application Name="COR_Basic"",
"providerName": "System.Data.SqlClient"

],



"conStringDictionary":
"COR-W81-101":
"connectionString": "Data Source=DATASOURCE; Initial Catalog=COR_Basic; Persist Security Info=False;Integrated Security=true;MultipleActiveResultSets=False;Packet Size=4096;Application Name="COR_Basic"",
"providerName": "System.Data.SqlClient"
,

"server":
"connectionString": "Data Source=DATASOURCE; Initial Catalog=COR_Basic; Persist Security Info=False;Integrated Security=true;MultipleActiveResultSets=False;Packet Size=4096;Application Name="COR_Basic"",
"providerName": "System.Data.SqlClient"



}


Now I wanted to read the connectionStrings:



public class ConnectionString

public string name get; set;
public string connectionString get; set;
public string providerName get; set;



like this:



//Microsoft.Extensions.DependencyInjection.OptionsConfigurationServiceCollectionExtensions.Configure<ConnectionString>(services, Configuration.GetSection("conStrings"));

// https://stackoverflow.com/questions/31929482/retrieve-sections-from-config-json-in-asp-net-5
//var objectSections = Configuration.GetSection("conStringDictionary").GetChildren();
//foreach (var x in objectSections)
//
// System.Console.WriteLine(x.Key);
// var cs = new ConnectionString();
// ConfigurationBinder.Bind(x, cs);
// System.Console.WriteLine(cs);
//

// http://andrewlock.net/how-to-use-the-ioptions-pattern-for-configuration-in-asp-net-core-rc2/
Microsoft.Extensions.DependencyInjection.OptionsConfigurationServiceCollectionExtensions.Configure<Dictionary<string, ConnectionString>>(services, Configuration.GetSection("conStrings"));


But I can't get it to read the array or the dictionary. I need the providerName for each connectionString, and I want to have it in the same entry as the connection string, but not as a joined string.










share|improve this question
















I added



.AddJsonFile("Connections.json", optional: true, reloadOnChange: true)


in



 public Startup(IHostingEnvironment env)


Connections.json contains:




"ConnectionStrings":
"DefaultConnection": "Server=(localdb)\mssqllocaldb;Database=DATABASE;Trusted_Connection=True;MultipleActiveResultSets=true",
"COR-W81-101": "Data Source=DATASOURCE;Initial Catalog=P61_CAFM_Basic;User Id=USERID;Password=PASSWORD;Persist Security Info=False;MultipleActiveResultSets=False;Packet Size=4096;",
"COR-W81-100": "Data Source=DATASOURCE;Initial Catalog=Post_PS;User Id=USERID;Password=PASSWORD;Persist Security Info=False;MultipleActiveResultSets=False;Packet Size=4096;",
"MSEDGEWIN10": "Data Source=DATASOURCE; Initial Catalog=COR_Basic; Persist Security Info=False;Integrated Security=true;MultipleActiveResultSets=False;Packet Size=4096;Application Name="COR_Basic"",

"server": "Data Source=DATASOURCE; Initial Catalog=COR_Basic; Persist Security Info=False;User Id=USERID;Password=PASSWORD;MultipleActiveResultSets=False;Packet Size=4096;Application Name="COR_Basic""
,


"conStrings": [

"name": "COR-W81-101",
"connectionString": "Data Source=DATASOURCE; Initial Catalog=COR_Basic; Persist Security Info=False;Integrated Security=true;MultipleActiveResultSets=False;Packet Size=4096;Application Name="COR_Basic"",
"providerName": "System.Data.SqlClient"


,


"name": "server",
"connectionString": "Data Source=DATASOURCE; Initial Catalog=COR_Basic; Persist Security Info=False;Integrated Security=true;MultipleActiveResultSets=False;Packet Size=4096;Application Name="COR_Basic"",
"providerName": "System.Data.SqlClient"

],



"conStringDictionary":
"COR-W81-101":
"connectionString": "Data Source=DATASOURCE; Initial Catalog=COR_Basic; Persist Security Info=False;Integrated Security=true;MultipleActiveResultSets=False;Packet Size=4096;Application Name="COR_Basic"",
"providerName": "System.Data.SqlClient"
,

"server":
"connectionString": "Data Source=DATASOURCE; Initial Catalog=COR_Basic; Persist Security Info=False;Integrated Security=true;MultipleActiveResultSets=False;Packet Size=4096;Application Name="COR_Basic"",
"providerName": "System.Data.SqlClient"



}


Now I wanted to read the connectionStrings:



public class ConnectionString

public string name get; set;
public string connectionString get; set;
public string providerName get; set;



like this:



//Microsoft.Extensions.DependencyInjection.OptionsConfigurationServiceCollectionExtensions.Configure<ConnectionString>(services, Configuration.GetSection("conStrings"));

// https://stackoverflow.com/questions/31929482/retrieve-sections-from-config-json-in-asp-net-5
//var objectSections = Configuration.GetSection("conStringDictionary").GetChildren();
//foreach (var x in objectSections)
//
// System.Console.WriteLine(x.Key);
// var cs = new ConnectionString();
// ConfigurationBinder.Bind(x, cs);
// System.Console.WriteLine(cs);
//

// http://andrewlock.net/how-to-use-the-ioptions-pattern-for-configuration-in-asp-net-core-rc2/
Microsoft.Extensions.DependencyInjection.OptionsConfigurationServiceCollectionExtensions.Configure<Dictionary<string, ConnectionString>>(services, Configuration.GetSection("conStrings"));


But I can't get it to read the array or the dictionary. I need the providerName for each connectionString, and I want to have it in the same entry as the connection string, but not as a joined string.







c# asp.net-core asp.net-core-mvc .net-core asp.net-core-1.0






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Nov 28 '16 at 17:11

























asked Nov 28 '16 at 13:30







user6038265



















  • Your Connections.json is invalid. Your "conStrings" array have to much "}" . It should look like jsoneditoronline.org/?id=a00f0105a65d6a651d872ea9688d6147

    – M. Wiśnicki
    Nov 28 '16 at 13:57






  • 5





    Dude, you just posted connection string to your databases to public view. Consider to remove passwords at least!

    – Maris
    Nov 28 '16 at 14:09











  • @Maris: Doesn't matter, changed them before I posted - forgot one, but it was TrippleDES encrypted anyway. The datasource isn't confidential anyway.

    – user6038265
    Nov 28 '16 at 17:12


















  • Your Connections.json is invalid. Your "conStrings" array have to much "}" . It should look like jsoneditoronline.org/?id=a00f0105a65d6a651d872ea9688d6147

    – M. Wiśnicki
    Nov 28 '16 at 13:57






  • 5





    Dude, you just posted connection string to your databases to public view. Consider to remove passwords at least!

    – Maris
    Nov 28 '16 at 14:09











  • @Maris: Doesn't matter, changed them before I posted - forgot one, but it was TrippleDES encrypted anyway. The datasource isn't confidential anyway.

    – user6038265
    Nov 28 '16 at 17:12

















Your Connections.json is invalid. Your "conStrings" array have to much "}" . It should look like jsoneditoronline.org/?id=a00f0105a65d6a651d872ea9688d6147

– M. Wiśnicki
Nov 28 '16 at 13:57





Your Connections.json is invalid. Your "conStrings" array have to much "}" . It should look like jsoneditoronline.org/?id=a00f0105a65d6a651d872ea9688d6147

– M. Wiśnicki
Nov 28 '16 at 13:57




5




5





Dude, you just posted connection string to your databases to public view. Consider to remove passwords at least!

– Maris
Nov 28 '16 at 14:09





Dude, you just posted connection string to your databases to public view. Consider to remove passwords at least!

– Maris
Nov 28 '16 at 14:09













@Maris: Doesn't matter, changed them before I posted - forgot one, but it was TrippleDES encrypted anyway. The datasource isn't confidential anyway.

– user6038265
Nov 28 '16 at 17:12






@Maris: Doesn't matter, changed them before I posted - forgot one, but it was TrippleDES encrypted anyway. The datasource isn't confidential anyway.

– user6038265
Nov 28 '16 at 17:12













3 Answers
3






active

oldest

votes


















7














You were basically there, all you have to do is make a few strongly typed classes to match the old ConnectionStringSettings and utilize some collection serialization logic.



Here's how I would suggest to format them in json. Rather similar to how you would specify a connection string the old XML app/web.config way. The name of the connection string being the key.




"ConnectionStrings":
"Test1":
"ConnectionString": "server=localhost;database=db;username=user;password=pass;",
"ProviderName": "MySql.Data.MySqlClient"
,
"Test2":
"ConnectionString": "server=localhost;database=db2;username=user2;password=pass2;",
"ProviderName": "MySql.Data.MySqlClient"





Now for the classes to bind to. First is the simple ConnectionStringSettings class itself, implements your basic equality/hashing methods (will be necessary as we intend to stick this in a Dictionary).



public class ConnectionStringSettings

public String Name get; set;
public String ConnectionString get; set;
public String ProviderName get; set;

public ConnectionStringSettings()



public ConnectionStringSettings(String name, String connectionString)
: this(name, connectionString, null)



public ConnectionStringSettings(String name, String connectionString, String providerName)

this.Name = name;
this.ConnectionString = connectionString;
this.ProviderName = providerName;


protected bool Equals(ConnectionStringSettings other)

return String.Equals(Name, other.Name) && String.Equals(ConnectionString, other.ConnectionString) && String.Equals(ProviderName, other.ProviderName);


public override bool Equals(Object obj)

if (ReferenceEquals(null, obj)) return false;
if (ReferenceEquals(this, obj)) return true;
if (obj.GetType() != this.GetType()) return false;
return Equals((ConnectionStringSettings) obj);


public override int GetHashCode()

unchecked

int hashCode = (Name != null ? Name.GetHashCode() : 0);
hashCode = (hashCode * 397) ^ (ConnectionString != null ? ConnectionString.GetHashCode() : 0);
hashCode = (hashCode * 397) ^ (ProviderName != null ? ProviderName.GetHashCode() : 0);
return hashCode;



public static bool operator ==(ConnectionStringSettings left, ConnectionStringSettings right)

return Equals(left, right);


public static bool operator !=(ConnectionStringSettings left, ConnectionStringSettings right)

return !Equals(left, right);




Next is the collection of ConnectionStringSettings. This is only necessary because the Name of the connection string is the key in the JSON notation. In order to keep that name consistently attached we need to override Dictionary's Add method (but you can't do that because its not virtual). So all we are REALLY doing is just wrapping a Dictionary internally with that extra bit in our own Add implementation. Again this looks like a lot of code, but you'll see it's very monotonous boring stuff.



public class ConnectionStringSettingsCollection : IDictionary<String, ConnectionStringSettings>

private readonly Dictionary<String, ConnectionStringSettings> m_ConnectionStrings;

public ConnectionStringSettingsCollection()

m_ConnectionStrings = new Dictionary<String, ConnectionStringSettings>();


public ConnectionStringSettingsCollection(int capacity)

m_ConnectionStrings = new Dictionary<String, ConnectionStringSettings>(capacity);


#region IEnumerable methods
IEnumerator IEnumerable.GetEnumerator()

return ((IEnumerable)m_ConnectionStrings).GetEnumerator();

#endregion

#region IEnumerable<> methods
IEnumerator<KeyValuePair<String, ConnectionStringSettings>> IEnumerable<KeyValuePair<String, ConnectionStringSettings>>.GetEnumerator()

return ((IEnumerable<KeyValuePair<String, ConnectionStringSettings>>)m_ConnectionStrings).GetEnumerator();

#endregion

#region ICollection<> methods
void ICollection<KeyValuePair<String, ConnectionStringSettings>>.Add(KeyValuePair<String, ConnectionStringSettings> item)

((ICollection<KeyValuePair<String, ConnectionStringSettings>>)m_ConnectionStrings).Add(item);


void ICollection<KeyValuePair<String, ConnectionStringSettings>>.Clear()

((ICollection<KeyValuePair<String, ConnectionStringSettings>>)m_ConnectionStrings).Clear();


Boolean ICollection<KeyValuePair<String, ConnectionStringSettings>>.Contains(KeyValuePair<String, ConnectionStringSettings> item)

return ((ICollection<KeyValuePair<String, ConnectionStringSettings>>)m_ConnectionStrings).Contains(item);


void ICollection<KeyValuePair<String, ConnectionStringSettings>>.CopyTo(KeyValuePair<String, ConnectionStringSettings> array, Int32 arrayIndex)

((ICollection<KeyValuePair<String, ConnectionStringSettings>>)m_ConnectionStrings).CopyTo(array, arrayIndex);


Boolean ICollection<KeyValuePair<String, ConnectionStringSettings>>.Remove(KeyValuePair<String, ConnectionStringSettings> item)

return ((ICollection<KeyValuePair<String, ConnectionStringSettings>>)m_ConnectionStrings).Remove(item);


public Int32 Count => ((ICollection<KeyValuePair<String, ConnectionStringSettings>>)m_ConnectionStrings).Count;
public Boolean IsReadOnly => ((ICollection<KeyValuePair<String, ConnectionStringSettings>>)m_ConnectionStrings).IsReadOnly;
#endregion

#region IDictionary<> methods
public void Add(String key, ConnectionStringSettings value)

// NOTE only slight modification, we add back in the Name of connectionString here (since it is the key)
value.Name = key;
m_ConnectionStrings.Add(key, value);


public Boolean ContainsKey(String key)

return m_ConnectionStrings.ContainsKey(key);


public Boolean Remove(String key)

return m_ConnectionStrings.Remove(key);


public Boolean TryGetValue(String key, out ConnectionStringSettings value)

return m_ConnectionStrings.TryGetValue(key, out value);


public ConnectionStringSettings this[String key]

get => m_ConnectionStrings[key];
set => Add(key, value);


public ICollection<String> Keys => m_ConnectionStrings.Keys;
public ICollection<ConnectionStringSettings> Values => m_ConnectionStrings.Values;
#endregion



A few simple extension methods to make things simpler.



public static class ConnectionStringSettingsExtensions

public static ConnectionStringSettingsCollection ConnectionStrings(this IConfigurationRoot configuration, String section = "ConnectionStrings")

var connectionStringCollection = configuration.GetSection(section).Get<ConnectionStringSettingsCollection>();
if (connectionStringCollection == null)

return new ConnectionStringSettingsCollection();


return connectionStringCollection;


public static ConnectionStringSettings ConnectionString(this IConfigurationRoot configuration, String name, String section = "ConnectionStrings")

ConnectionStringSettings connectionStringSettings;

var connectionStringCollection = configuration.GetSection(section).Get<ConnectionStringSettingsCollection>();
if (connectionStringCollection == null



Finally the usage.



var configuration = new ConfigurationBuilder()
.AddJsonFile("config.json")
.Build();

var connectionStrings = configuration.ConnectionStrings();

foreach (var connectionString in connectionStrings.Values)

Console.WriteLine(connectionString.Name);
Console.WriteLine(connectionString.ConnectionString);
Console.WriteLine(connectionString.ProviderName);


var specificConnStr1 = connectionStrings["Test1"];
Console.WriteLine(specificConnStr1.Name);
Console.WriteLine(specificConnStr1.ConnectionString);
Console.WriteLine(specificConnStr1.ProviderName);

var specificConnStr2 = configuration.ConnectionString("Test2");
Console.WriteLine(specificConnStr2.Name);
Console.WriteLine(specificConnStr2.ConnectionString);
Console.WriteLine(specificConnStr2.ProviderName);





share|improve this answer

























  • Upvote for the inspiration!

    – granadaCoder
    Nov 15 '18 at 20:25


















1














First off, Nicholi's answer inspired me! Thanks Nicholi.



Second, I have a "List" solution rather than a IDictionary solution. It's not as smooth as the IDictionary solution.



This can also be dubbed "how to create a collection list for dot net core configuration"



Here we go:



first a shameless theft!



public class ConnectionStringEntry

public String Name get; set;
public String ConnectionString get; set;
public String ProviderName get; set;

public ConnectionStringEntry()



public ConnectionStringEntry(String name, String connectionString)
: this(name, connectionString, null)



public ConnectionStringEntry(String name, String connectionString, String providerName)

this.Name = name;
this.ConnectionString = connectionString;
this.ProviderName = providerName;




second, a "wrapper". I wanted to track a DefaultConnectionStringName...along side my List (collection) of Entries.



public class ConnectionStringWrapper

public string DefaultConnectionStringName get; set; = "";
public List<ConnectionStringEntry> ConnectionStringEntries get; set; = new List<ConnectionStringEntry>();
//public Dictionary<string, ConnectionStringEntry> ConnectionStringEntries get; set; = new Dictionary<string, ConnectionStringEntry>();

public ConnectionStringEntry GetDefaultConnectionStringEntry()

ConnectionStringEntry returnItem = this.GetConnectionStringEntry(this.DefaultConnectionStringName);
return returnItem;


public ConnectionStringEntry GetConnectionStringEntry(string name)

ConnectionStringEntry returnItem = null;
if (null != this.ConnectionStringEntries && this.ConnectionStringEntries.Any())

returnItem = this.ConnectionStringEntries.FirstOrDefault(ce => ce.Name.Equals(name, StringComparison.OrdinalIgnoreCase));


if (null == returnItem)

throw new ArgumentOutOfRangeException(string.Format("No default ConnectionStringEntry found. (ConnectionStringEntries.Names='0', Search.Name='1')", this.ConnectionStringEntries == null ? string.Empty : string.Join(",", this.ConnectionStringEntries.Select(ce => ce.Name)), name));


return returnItem;




Now, my reading the json and mapping to a concrete settings object code:



 IConfiguration config = new ConfigurationBuilder()
.SetBasePath(System.IO.Directory.GetCurrentDirectory())
.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
.Build();


ConnectionStringWrapper settings = new ConnectionStringWrapper();
config.Bind("ConnectionStringWrapperSettings", settings);
Console.WriteLine("0, 1", settings.DefaultConnectionStringName, settings.ConnectionStringEntries.Count);
ConnectionStringEntry cse = settings.GetDefaultConnectionStringEntry();


My nuget packages:



.nugetpackagesmicrosoft.extensions.configuration2.1.1
.nugetpackagesmicrosoft.extensions.configuration.binder2.1.1
.nugetpackagesmicrosoft.extensions.configuration.json2.1.1


BONUS MATERIAL BELOW:



One of the things I am (trying) to so support a code base that can be deployed as DotNet 4.x ("classic" ?? as the term now??) and dotnet core.



To that end, I've written the above to provide an abstraction from the way DotNet(Classic) handles connection strings (xml, our old long time friend) and now the new cool kid on the block : DotNetCore with json.



To that end, I've written an interface:



public interface IConnectionStringWrapperRetriever

ConnectionStringWrapper RetrieveConnectionStringWrapper();



and I have an implementation for dotnetcore:



public class ConnectionStringWrapperDotNetCoreRetriever : IConnectionStringWrapperRetriever

public const string ConnectionStringWrapperSettingsJsonElementName = "ConnectionStringWrapperSettings";

private readonly IConfiguration config;

public ConnectionStringWrapperDotNetCoreRetriever(IConfiguration cnfg)

this.config = cnfg;


public ConnectionStringWrapper RetrieveConnectionStringWrapper()

ConnectionStringWrapper settings = new ConnectionStringWrapper();
this.config.Bind(ConnectionStringWrapperSettingsJsonElementName, settings);
return settings;




Oh yeah, the all important JSON setup:




"ConnectionStringWrapperSettings":
"DefaultConnectionStringName": "abc",
"ConnectionStringEntries": [

"Name": "abc",
"ConnectionString": "Server=myserver;Database=mydatabase;Trusted_Connection=True;MultipleActiveResultSets=true",
"ProviderName": "SomeProvider"
,

"Name": "def",
"ConnectionString": "server=localhost;database=db2;username=user2;password=pass2;",
"ProviderName": "SomeProvider"

]




.............



For DotNet(classic), all you need to do is implement a second concrete for IConnectionStringWrapperRetriever, and do the magic.



Remember the below xml? (ha ha, its not that old yet!)



<?xml version="1.0" encoding="utf-8"?> 
<configuration>
<connectionStrings>
<add name="ConnStr1" connectionString="LocalSqlServer: data source=127.0.0.1;Integrated Security=SSPI;Initial Catalog=aspnetdb"
providerName="System.Data.SqlClient" />
</connectionStrings>
</configuration>


(from https://docs.microsoft.com/en-us/dotnet/api/system.configuration.connectionstringsettingscollection?view=netframework-4.7.2)



Remember this stuff from EnterpriseLibrary?



<configSections>
<section name="dataConfiguration" type="Microsoft.Practices.EnterpriseLibrary.Data.Configuration.DatabaseSettings, Microsoft.Practices.EnterpriseLibrary.Data, Version=2.0.0.0, Culture=neutral, PublicKeyToken=null"/>
</configSections>

<dataConfiguration defaultDatabase="ConnStr1"/>


I'll leave the DotNet(Classic) implementation to the reader.



But now I inject IConnectionStringWrapperRetriever into my DataLayer classes.

I'm using Dapper, so I can fish a connection string using IConnectionStringWrapperRetriever.



If my project is "house" DotNet(Classic), I inject one version of IConnectionStringWrapperRetriever (not seen here, left to the reader). If my project is "housed" in DotNetCore I inject a second (shown above) version of IConnectionStringWrapperRetriever.



Outside the scope of this post, but by "housed", I mean I have 2 csproj's sitting side by side.



MyApp.DataLayer.classic.csproj
and
MyApp.DataLayer.csproj



I find it easier to leave the default csproj to house the DotNetCore stuff. And I use the "classic.csproj" file to house the DotNet(classic). My assembly name and default namespace remain "MyApp.Datalayer"......the .classic is ONLY for the csrproj filename to distinquish.



I create two solution sln files too. MySolution.classic.sln and MySolution.sln.



It seems to be working.....with this ConnectionString abstraction I wrote above.



The ONLY conditional I have is on the (classic) AssemblyInfo.cs files.



#if(!NETCOREAPP2_1)

using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;

/* all the other stuff removed here */

// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

#endif


APPEND:



Ok, here is the DotNet(Classic) version:



public class ConnectionStringWrapperDotNetClassicRetriever : IConnectionStringWrapperRetriever

public ConnectionStringWrapper RetrieveConnectionStringWrapper()

ConnectionStringWrapper returnItem = new ConnectionStringWrapper();

foreach(ConnectionStringSettings css in System.Configuration.ConfigurationManager.ConnectionStrings)

ConnectionStringEntry cse = new ConnectionStringEntry(css.Name, css.ConnectionString, css.ProviderName);
returnItem.ConnectionStringEntries.Add(cse);


if(returnItem.ConnectionStringEntries.Count == 1)

/* if there is only one, set the default name to that one */
returnItem.DefaultConnectionStringName = returnItem.ConnectionStringEntries.First().Name;

else

/*
<packages>
<package id="EnterpriseLibrary.Common" version="6.0.1304.0" targetFramework="net45" />
<package id="EnterpriseLibrary.Data" version="6.0.1304.0" targetFramework="net45" />
</packages>
*/

/* using Microsoft.Practices.EnterpriseLibrary.Data.Configuration; */
/* You can write you own way to handle a default database, or piggyback off of EnterpriseLibrary. You don't necessarily have to use EnterpriseLibrary.Data, you are simply piggybacking on their xml/configuration setup */
DatabaseSettings dbSettings = (DatabaseSettings)ConfigurationManager.GetSection("dataConfiguration");
returnItem.DefaultConnectionStringName = dbSettings.DefaultDatabase;


return returnItem;




And the app.config xml:



<?xml version="1.0" encoding="utf-8" ?>
<configuration>

<configSections>
<section name="dataConfiguration" type="Microsoft.Practices.EnterpriseLibrary.Data.Configuration.DatabaseSettings, Microsoft.Practices.EnterpriseLibrary.Data"/>
</configSections>

<connectionStrings>
<clear/>
<add name="MyFirstConnectionStringName" connectionString="Server=.MyServerOne;Database=OneDB;Trusted_Connection=True;MultipleActiveResultSets=true"
providerName="System.Data.SqlClient" />

<add name="MySecondConnectionStringName" connectionString="Server=.MyServerTwo;Database=TwoDB;Trusted_Connection=True;MultipleActiveResultSets=true"
providerName="System.Data.SqlClient" />
</connectionStrings>


<dataConfiguration defaultDatabase="MyFirstConnectionStringName" />

<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
</startup>
</configuration>


Key words:



DotNet DotNet .Net Core Classic Json Configuration ICollection scalar and collection support both dotnet and dotnetcore






share|improve this answer
































    0














    Something like:



     var configurationRoot = new ConfigurationBuilder()
    .SetBasePath(Directory.GetCurrentDirectory())
    .AddJsonFile("appsettings.json", false)
    .Build();

    var conString = configurationRoot["ConnectionStrings:MyConnection"]);





    share|improve this answer























      Your Answer






      StackExchange.ifUsing("editor", function ()
      StackExchange.using("externalEditor", function ()
      StackExchange.using("snippets", function ()
      StackExchange.snippets.init();
      );
      );
      , "code-snippets");

      StackExchange.ready(function()
      var channelOptions =
      tags: "".split(" "),
      id: "1"
      ;
      initTagRenderer("".split(" "), "".split(" "), channelOptions);

      StackExchange.using("externalEditor", function()
      // Have to fire editor after snippets, if snippets enabled
      if (StackExchange.settings.snippets.snippetsEnabled)
      StackExchange.using("snippets", function()
      createEditor();
      );

      else
      createEditor();

      );

      function createEditor()
      StackExchange.prepareEditor(
      heartbeatType: 'answer',
      autoActivateHeartbeat: false,
      convertImagesToLinks: true,
      noModals: true,
      showLowRepImageUploadWarning: true,
      reputationToPostImages: 10,
      bindNavPrevention: true,
      postfix: "",
      imageUploader:
      brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
      contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
      allowUrls: true
      ,
      onDemand: true,
      discardSelector: ".discard-answer"
      ,immediatelyShowMarkdownHelp:true
      );



      );













      draft saved

      draft discarded


















      StackExchange.ready(
      function ()
      StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f40845542%2fhow-to-read-a-connectionstring-with-provider-in-net-core%23new-answer', 'question_page');

      );

      Post as a guest















      Required, but never shown
























      3 Answers
      3






      active

      oldest

      votes








      3 Answers
      3






      active

      oldest

      votes









      active

      oldest

      votes






      active

      oldest

      votes









      7














      You were basically there, all you have to do is make a few strongly typed classes to match the old ConnectionStringSettings and utilize some collection serialization logic.



      Here's how I would suggest to format them in json. Rather similar to how you would specify a connection string the old XML app/web.config way. The name of the connection string being the key.




      "ConnectionStrings":
      "Test1":
      "ConnectionString": "server=localhost;database=db;username=user;password=pass;",
      "ProviderName": "MySql.Data.MySqlClient"
      ,
      "Test2":
      "ConnectionString": "server=localhost;database=db2;username=user2;password=pass2;",
      "ProviderName": "MySql.Data.MySqlClient"





      Now for the classes to bind to. First is the simple ConnectionStringSettings class itself, implements your basic equality/hashing methods (will be necessary as we intend to stick this in a Dictionary).



      public class ConnectionStringSettings

      public String Name get; set;
      public String ConnectionString get; set;
      public String ProviderName get; set;

      public ConnectionStringSettings()



      public ConnectionStringSettings(String name, String connectionString)
      : this(name, connectionString, null)



      public ConnectionStringSettings(String name, String connectionString, String providerName)

      this.Name = name;
      this.ConnectionString = connectionString;
      this.ProviderName = providerName;


      protected bool Equals(ConnectionStringSettings other)

      return String.Equals(Name, other.Name) && String.Equals(ConnectionString, other.ConnectionString) && String.Equals(ProviderName, other.ProviderName);


      public override bool Equals(Object obj)

      if (ReferenceEquals(null, obj)) return false;
      if (ReferenceEquals(this, obj)) return true;
      if (obj.GetType() != this.GetType()) return false;
      return Equals((ConnectionStringSettings) obj);


      public override int GetHashCode()

      unchecked

      int hashCode = (Name != null ? Name.GetHashCode() : 0);
      hashCode = (hashCode * 397) ^ (ConnectionString != null ? ConnectionString.GetHashCode() : 0);
      hashCode = (hashCode * 397) ^ (ProviderName != null ? ProviderName.GetHashCode() : 0);
      return hashCode;



      public static bool operator ==(ConnectionStringSettings left, ConnectionStringSettings right)

      return Equals(left, right);


      public static bool operator !=(ConnectionStringSettings left, ConnectionStringSettings right)

      return !Equals(left, right);




      Next is the collection of ConnectionStringSettings. This is only necessary because the Name of the connection string is the key in the JSON notation. In order to keep that name consistently attached we need to override Dictionary's Add method (but you can't do that because its not virtual). So all we are REALLY doing is just wrapping a Dictionary internally with that extra bit in our own Add implementation. Again this looks like a lot of code, but you'll see it's very monotonous boring stuff.



      public class ConnectionStringSettingsCollection : IDictionary<String, ConnectionStringSettings>

      private readonly Dictionary<String, ConnectionStringSettings> m_ConnectionStrings;

      public ConnectionStringSettingsCollection()

      m_ConnectionStrings = new Dictionary<String, ConnectionStringSettings>();


      public ConnectionStringSettingsCollection(int capacity)

      m_ConnectionStrings = new Dictionary<String, ConnectionStringSettings>(capacity);


      #region IEnumerable methods
      IEnumerator IEnumerable.GetEnumerator()

      return ((IEnumerable)m_ConnectionStrings).GetEnumerator();

      #endregion

      #region IEnumerable<> methods
      IEnumerator<KeyValuePair<String, ConnectionStringSettings>> IEnumerable<KeyValuePair<String, ConnectionStringSettings>>.GetEnumerator()

      return ((IEnumerable<KeyValuePair<String, ConnectionStringSettings>>)m_ConnectionStrings).GetEnumerator();

      #endregion

      #region ICollection<> methods
      void ICollection<KeyValuePair<String, ConnectionStringSettings>>.Add(KeyValuePair<String, ConnectionStringSettings> item)

      ((ICollection<KeyValuePair<String, ConnectionStringSettings>>)m_ConnectionStrings).Add(item);


      void ICollection<KeyValuePair<String, ConnectionStringSettings>>.Clear()

      ((ICollection<KeyValuePair<String, ConnectionStringSettings>>)m_ConnectionStrings).Clear();


      Boolean ICollection<KeyValuePair<String, ConnectionStringSettings>>.Contains(KeyValuePair<String, ConnectionStringSettings> item)

      return ((ICollection<KeyValuePair<String, ConnectionStringSettings>>)m_ConnectionStrings).Contains(item);


      void ICollection<KeyValuePair<String, ConnectionStringSettings>>.CopyTo(KeyValuePair<String, ConnectionStringSettings> array, Int32 arrayIndex)

      ((ICollection<KeyValuePair<String, ConnectionStringSettings>>)m_ConnectionStrings).CopyTo(array, arrayIndex);


      Boolean ICollection<KeyValuePair<String, ConnectionStringSettings>>.Remove(KeyValuePair<String, ConnectionStringSettings> item)

      return ((ICollection<KeyValuePair<String, ConnectionStringSettings>>)m_ConnectionStrings).Remove(item);


      public Int32 Count => ((ICollection<KeyValuePair<String, ConnectionStringSettings>>)m_ConnectionStrings).Count;
      public Boolean IsReadOnly => ((ICollection<KeyValuePair<String, ConnectionStringSettings>>)m_ConnectionStrings).IsReadOnly;
      #endregion

      #region IDictionary<> methods
      public void Add(String key, ConnectionStringSettings value)

      // NOTE only slight modification, we add back in the Name of connectionString here (since it is the key)
      value.Name = key;
      m_ConnectionStrings.Add(key, value);


      public Boolean ContainsKey(String key)

      return m_ConnectionStrings.ContainsKey(key);


      public Boolean Remove(String key)

      return m_ConnectionStrings.Remove(key);


      public Boolean TryGetValue(String key, out ConnectionStringSettings value)

      return m_ConnectionStrings.TryGetValue(key, out value);


      public ConnectionStringSettings this[String key]

      get => m_ConnectionStrings[key];
      set => Add(key, value);


      public ICollection<String> Keys => m_ConnectionStrings.Keys;
      public ICollection<ConnectionStringSettings> Values => m_ConnectionStrings.Values;
      #endregion



      A few simple extension methods to make things simpler.



      public static class ConnectionStringSettingsExtensions

      public static ConnectionStringSettingsCollection ConnectionStrings(this IConfigurationRoot configuration, String section = "ConnectionStrings")

      var connectionStringCollection = configuration.GetSection(section).Get<ConnectionStringSettingsCollection>();
      if (connectionStringCollection == null)

      return new ConnectionStringSettingsCollection();


      return connectionStringCollection;


      public static ConnectionStringSettings ConnectionString(this IConfigurationRoot configuration, String name, String section = "ConnectionStrings")

      ConnectionStringSettings connectionStringSettings;

      var connectionStringCollection = configuration.GetSection(section).Get<ConnectionStringSettingsCollection>();
      if (connectionStringCollection == null



      Finally the usage.



      var configuration = new ConfigurationBuilder()
      .AddJsonFile("config.json")
      .Build();

      var connectionStrings = configuration.ConnectionStrings();

      foreach (var connectionString in connectionStrings.Values)

      Console.WriteLine(connectionString.Name);
      Console.WriteLine(connectionString.ConnectionString);
      Console.WriteLine(connectionString.ProviderName);


      var specificConnStr1 = connectionStrings["Test1"];
      Console.WriteLine(specificConnStr1.Name);
      Console.WriteLine(specificConnStr1.ConnectionString);
      Console.WriteLine(specificConnStr1.ProviderName);

      var specificConnStr2 = configuration.ConnectionString("Test2");
      Console.WriteLine(specificConnStr2.Name);
      Console.WriteLine(specificConnStr2.ConnectionString);
      Console.WriteLine(specificConnStr2.ProviderName);





      share|improve this answer

























      • Upvote for the inspiration!

        – granadaCoder
        Nov 15 '18 at 20:25















      7














      You were basically there, all you have to do is make a few strongly typed classes to match the old ConnectionStringSettings and utilize some collection serialization logic.



      Here's how I would suggest to format them in json. Rather similar to how you would specify a connection string the old XML app/web.config way. The name of the connection string being the key.




      "ConnectionStrings":
      "Test1":
      "ConnectionString": "server=localhost;database=db;username=user;password=pass;",
      "ProviderName": "MySql.Data.MySqlClient"
      ,
      "Test2":
      "ConnectionString": "server=localhost;database=db2;username=user2;password=pass2;",
      "ProviderName": "MySql.Data.MySqlClient"





      Now for the classes to bind to. First is the simple ConnectionStringSettings class itself, implements your basic equality/hashing methods (will be necessary as we intend to stick this in a Dictionary).



      public class ConnectionStringSettings

      public String Name get; set;
      public String ConnectionString get; set;
      public String ProviderName get; set;

      public ConnectionStringSettings()



      public ConnectionStringSettings(String name, String connectionString)
      : this(name, connectionString, null)



      public ConnectionStringSettings(String name, String connectionString, String providerName)

      this.Name = name;
      this.ConnectionString = connectionString;
      this.ProviderName = providerName;


      protected bool Equals(ConnectionStringSettings other)

      return String.Equals(Name, other.Name) && String.Equals(ConnectionString, other.ConnectionString) && String.Equals(ProviderName, other.ProviderName);


      public override bool Equals(Object obj)

      if (ReferenceEquals(null, obj)) return false;
      if (ReferenceEquals(this, obj)) return true;
      if (obj.GetType() != this.GetType()) return false;
      return Equals((ConnectionStringSettings) obj);


      public override int GetHashCode()

      unchecked

      int hashCode = (Name != null ? Name.GetHashCode() : 0);
      hashCode = (hashCode * 397) ^ (ConnectionString != null ? ConnectionString.GetHashCode() : 0);
      hashCode = (hashCode * 397) ^ (ProviderName != null ? ProviderName.GetHashCode() : 0);
      return hashCode;



      public static bool operator ==(ConnectionStringSettings left, ConnectionStringSettings right)

      return Equals(left, right);


      public static bool operator !=(ConnectionStringSettings left, ConnectionStringSettings right)

      return !Equals(left, right);




      Next is the collection of ConnectionStringSettings. This is only necessary because the Name of the connection string is the key in the JSON notation. In order to keep that name consistently attached we need to override Dictionary's Add method (but you can't do that because its not virtual). So all we are REALLY doing is just wrapping a Dictionary internally with that extra bit in our own Add implementation. Again this looks like a lot of code, but you'll see it's very monotonous boring stuff.



      public class ConnectionStringSettingsCollection : IDictionary<String, ConnectionStringSettings>

      private readonly Dictionary<String, ConnectionStringSettings> m_ConnectionStrings;

      public ConnectionStringSettingsCollection()

      m_ConnectionStrings = new Dictionary<String, ConnectionStringSettings>();


      public ConnectionStringSettingsCollection(int capacity)

      m_ConnectionStrings = new Dictionary<String, ConnectionStringSettings>(capacity);


      #region IEnumerable methods
      IEnumerator IEnumerable.GetEnumerator()

      return ((IEnumerable)m_ConnectionStrings).GetEnumerator();

      #endregion

      #region IEnumerable<> methods
      IEnumerator<KeyValuePair<String, ConnectionStringSettings>> IEnumerable<KeyValuePair<String, ConnectionStringSettings>>.GetEnumerator()

      return ((IEnumerable<KeyValuePair<String, ConnectionStringSettings>>)m_ConnectionStrings).GetEnumerator();

      #endregion

      #region ICollection<> methods
      void ICollection<KeyValuePair<String, ConnectionStringSettings>>.Add(KeyValuePair<String, ConnectionStringSettings> item)

      ((ICollection<KeyValuePair<String, ConnectionStringSettings>>)m_ConnectionStrings).Add(item);


      void ICollection<KeyValuePair<String, ConnectionStringSettings>>.Clear()

      ((ICollection<KeyValuePair<String, ConnectionStringSettings>>)m_ConnectionStrings).Clear();


      Boolean ICollection<KeyValuePair<String, ConnectionStringSettings>>.Contains(KeyValuePair<String, ConnectionStringSettings> item)

      return ((ICollection<KeyValuePair<String, ConnectionStringSettings>>)m_ConnectionStrings).Contains(item);


      void ICollection<KeyValuePair<String, ConnectionStringSettings>>.CopyTo(KeyValuePair<String, ConnectionStringSettings> array, Int32 arrayIndex)

      ((ICollection<KeyValuePair<String, ConnectionStringSettings>>)m_ConnectionStrings).CopyTo(array, arrayIndex);


      Boolean ICollection<KeyValuePair<String, ConnectionStringSettings>>.Remove(KeyValuePair<String, ConnectionStringSettings> item)

      return ((ICollection<KeyValuePair<String, ConnectionStringSettings>>)m_ConnectionStrings).Remove(item);


      public Int32 Count => ((ICollection<KeyValuePair<String, ConnectionStringSettings>>)m_ConnectionStrings).Count;
      public Boolean IsReadOnly => ((ICollection<KeyValuePair<String, ConnectionStringSettings>>)m_ConnectionStrings).IsReadOnly;
      #endregion

      #region IDictionary<> methods
      public void Add(String key, ConnectionStringSettings value)

      // NOTE only slight modification, we add back in the Name of connectionString here (since it is the key)
      value.Name = key;
      m_ConnectionStrings.Add(key, value);


      public Boolean ContainsKey(String key)

      return m_ConnectionStrings.ContainsKey(key);


      public Boolean Remove(String key)

      return m_ConnectionStrings.Remove(key);


      public Boolean TryGetValue(String key, out ConnectionStringSettings value)

      return m_ConnectionStrings.TryGetValue(key, out value);


      public ConnectionStringSettings this[String key]

      get => m_ConnectionStrings[key];
      set => Add(key, value);


      public ICollection<String> Keys => m_ConnectionStrings.Keys;
      public ICollection<ConnectionStringSettings> Values => m_ConnectionStrings.Values;
      #endregion



      A few simple extension methods to make things simpler.



      public static class ConnectionStringSettingsExtensions

      public static ConnectionStringSettingsCollection ConnectionStrings(this IConfigurationRoot configuration, String section = "ConnectionStrings")

      var connectionStringCollection = configuration.GetSection(section).Get<ConnectionStringSettingsCollection>();
      if (connectionStringCollection == null)

      return new ConnectionStringSettingsCollection();


      return connectionStringCollection;


      public static ConnectionStringSettings ConnectionString(this IConfigurationRoot configuration, String name, String section = "ConnectionStrings")

      ConnectionStringSettings connectionStringSettings;

      var connectionStringCollection = configuration.GetSection(section).Get<ConnectionStringSettingsCollection>();
      if (connectionStringCollection == null



      Finally the usage.



      var configuration = new ConfigurationBuilder()
      .AddJsonFile("config.json")
      .Build();

      var connectionStrings = configuration.ConnectionStrings();

      foreach (var connectionString in connectionStrings.Values)

      Console.WriteLine(connectionString.Name);
      Console.WriteLine(connectionString.ConnectionString);
      Console.WriteLine(connectionString.ProviderName);


      var specificConnStr1 = connectionStrings["Test1"];
      Console.WriteLine(specificConnStr1.Name);
      Console.WriteLine(specificConnStr1.ConnectionString);
      Console.WriteLine(specificConnStr1.ProviderName);

      var specificConnStr2 = configuration.ConnectionString("Test2");
      Console.WriteLine(specificConnStr2.Name);
      Console.WriteLine(specificConnStr2.ConnectionString);
      Console.WriteLine(specificConnStr2.ProviderName);





      share|improve this answer

























      • Upvote for the inspiration!

        – granadaCoder
        Nov 15 '18 at 20:25













      7












      7








      7







      You were basically there, all you have to do is make a few strongly typed classes to match the old ConnectionStringSettings and utilize some collection serialization logic.



      Here's how I would suggest to format them in json. Rather similar to how you would specify a connection string the old XML app/web.config way. The name of the connection string being the key.




      "ConnectionStrings":
      "Test1":
      "ConnectionString": "server=localhost;database=db;username=user;password=pass;",
      "ProviderName": "MySql.Data.MySqlClient"
      ,
      "Test2":
      "ConnectionString": "server=localhost;database=db2;username=user2;password=pass2;",
      "ProviderName": "MySql.Data.MySqlClient"





      Now for the classes to bind to. First is the simple ConnectionStringSettings class itself, implements your basic equality/hashing methods (will be necessary as we intend to stick this in a Dictionary).



      public class ConnectionStringSettings

      public String Name get; set;
      public String ConnectionString get; set;
      public String ProviderName get; set;

      public ConnectionStringSettings()



      public ConnectionStringSettings(String name, String connectionString)
      : this(name, connectionString, null)



      public ConnectionStringSettings(String name, String connectionString, String providerName)

      this.Name = name;
      this.ConnectionString = connectionString;
      this.ProviderName = providerName;


      protected bool Equals(ConnectionStringSettings other)

      return String.Equals(Name, other.Name) && String.Equals(ConnectionString, other.ConnectionString) && String.Equals(ProviderName, other.ProviderName);


      public override bool Equals(Object obj)

      if (ReferenceEquals(null, obj)) return false;
      if (ReferenceEquals(this, obj)) return true;
      if (obj.GetType() != this.GetType()) return false;
      return Equals((ConnectionStringSettings) obj);


      public override int GetHashCode()

      unchecked

      int hashCode = (Name != null ? Name.GetHashCode() : 0);
      hashCode = (hashCode * 397) ^ (ConnectionString != null ? ConnectionString.GetHashCode() : 0);
      hashCode = (hashCode * 397) ^ (ProviderName != null ? ProviderName.GetHashCode() : 0);
      return hashCode;



      public static bool operator ==(ConnectionStringSettings left, ConnectionStringSettings right)

      return Equals(left, right);


      public static bool operator !=(ConnectionStringSettings left, ConnectionStringSettings right)

      return !Equals(left, right);




      Next is the collection of ConnectionStringSettings. This is only necessary because the Name of the connection string is the key in the JSON notation. In order to keep that name consistently attached we need to override Dictionary's Add method (but you can't do that because its not virtual). So all we are REALLY doing is just wrapping a Dictionary internally with that extra bit in our own Add implementation. Again this looks like a lot of code, but you'll see it's very monotonous boring stuff.



      public class ConnectionStringSettingsCollection : IDictionary<String, ConnectionStringSettings>

      private readonly Dictionary<String, ConnectionStringSettings> m_ConnectionStrings;

      public ConnectionStringSettingsCollection()

      m_ConnectionStrings = new Dictionary<String, ConnectionStringSettings>();


      public ConnectionStringSettingsCollection(int capacity)

      m_ConnectionStrings = new Dictionary<String, ConnectionStringSettings>(capacity);


      #region IEnumerable methods
      IEnumerator IEnumerable.GetEnumerator()

      return ((IEnumerable)m_ConnectionStrings).GetEnumerator();

      #endregion

      #region IEnumerable<> methods
      IEnumerator<KeyValuePair<String, ConnectionStringSettings>> IEnumerable<KeyValuePair<String, ConnectionStringSettings>>.GetEnumerator()

      return ((IEnumerable<KeyValuePair<String, ConnectionStringSettings>>)m_ConnectionStrings).GetEnumerator();

      #endregion

      #region ICollection<> methods
      void ICollection<KeyValuePair<String, ConnectionStringSettings>>.Add(KeyValuePair<String, ConnectionStringSettings> item)

      ((ICollection<KeyValuePair<String, ConnectionStringSettings>>)m_ConnectionStrings).Add(item);


      void ICollection<KeyValuePair<String, ConnectionStringSettings>>.Clear()

      ((ICollection<KeyValuePair<String, ConnectionStringSettings>>)m_ConnectionStrings).Clear();


      Boolean ICollection<KeyValuePair<String, ConnectionStringSettings>>.Contains(KeyValuePair<String, ConnectionStringSettings> item)

      return ((ICollection<KeyValuePair<String, ConnectionStringSettings>>)m_ConnectionStrings).Contains(item);


      void ICollection<KeyValuePair<String, ConnectionStringSettings>>.CopyTo(KeyValuePair<String, ConnectionStringSettings> array, Int32 arrayIndex)

      ((ICollection<KeyValuePair<String, ConnectionStringSettings>>)m_ConnectionStrings).CopyTo(array, arrayIndex);


      Boolean ICollection<KeyValuePair<String, ConnectionStringSettings>>.Remove(KeyValuePair<String, ConnectionStringSettings> item)

      return ((ICollection<KeyValuePair<String, ConnectionStringSettings>>)m_ConnectionStrings).Remove(item);


      public Int32 Count => ((ICollection<KeyValuePair<String, ConnectionStringSettings>>)m_ConnectionStrings).Count;
      public Boolean IsReadOnly => ((ICollection<KeyValuePair<String, ConnectionStringSettings>>)m_ConnectionStrings).IsReadOnly;
      #endregion

      #region IDictionary<> methods
      public void Add(String key, ConnectionStringSettings value)

      // NOTE only slight modification, we add back in the Name of connectionString here (since it is the key)
      value.Name = key;
      m_ConnectionStrings.Add(key, value);


      public Boolean ContainsKey(String key)

      return m_ConnectionStrings.ContainsKey(key);


      public Boolean Remove(String key)

      return m_ConnectionStrings.Remove(key);


      public Boolean TryGetValue(String key, out ConnectionStringSettings value)

      return m_ConnectionStrings.TryGetValue(key, out value);


      public ConnectionStringSettings this[String key]

      get => m_ConnectionStrings[key];
      set => Add(key, value);


      public ICollection<String> Keys => m_ConnectionStrings.Keys;
      public ICollection<ConnectionStringSettings> Values => m_ConnectionStrings.Values;
      #endregion



      A few simple extension methods to make things simpler.



      public static class ConnectionStringSettingsExtensions

      public static ConnectionStringSettingsCollection ConnectionStrings(this IConfigurationRoot configuration, String section = "ConnectionStrings")

      var connectionStringCollection = configuration.GetSection(section).Get<ConnectionStringSettingsCollection>();
      if (connectionStringCollection == null)

      return new ConnectionStringSettingsCollection();


      return connectionStringCollection;


      public static ConnectionStringSettings ConnectionString(this IConfigurationRoot configuration, String name, String section = "ConnectionStrings")

      ConnectionStringSettings connectionStringSettings;

      var connectionStringCollection = configuration.GetSection(section).Get<ConnectionStringSettingsCollection>();
      if (connectionStringCollection == null



      Finally the usage.



      var configuration = new ConfigurationBuilder()
      .AddJsonFile("config.json")
      .Build();

      var connectionStrings = configuration.ConnectionStrings();

      foreach (var connectionString in connectionStrings.Values)

      Console.WriteLine(connectionString.Name);
      Console.WriteLine(connectionString.ConnectionString);
      Console.WriteLine(connectionString.ProviderName);


      var specificConnStr1 = connectionStrings["Test1"];
      Console.WriteLine(specificConnStr1.Name);
      Console.WriteLine(specificConnStr1.ConnectionString);
      Console.WriteLine(specificConnStr1.ProviderName);

      var specificConnStr2 = configuration.ConnectionString("Test2");
      Console.WriteLine(specificConnStr2.Name);
      Console.WriteLine(specificConnStr2.ConnectionString);
      Console.WriteLine(specificConnStr2.ProviderName);





      share|improve this answer















      You were basically there, all you have to do is make a few strongly typed classes to match the old ConnectionStringSettings and utilize some collection serialization logic.



      Here's how I would suggest to format them in json. Rather similar to how you would specify a connection string the old XML app/web.config way. The name of the connection string being the key.




      "ConnectionStrings":
      "Test1":
      "ConnectionString": "server=localhost;database=db;username=user;password=pass;",
      "ProviderName": "MySql.Data.MySqlClient"
      ,
      "Test2":
      "ConnectionString": "server=localhost;database=db2;username=user2;password=pass2;",
      "ProviderName": "MySql.Data.MySqlClient"





      Now for the classes to bind to. First is the simple ConnectionStringSettings class itself, implements your basic equality/hashing methods (will be necessary as we intend to stick this in a Dictionary).



      public class ConnectionStringSettings

      public String Name get; set;
      public String ConnectionString get; set;
      public String ProviderName get; set;

      public ConnectionStringSettings()



      public ConnectionStringSettings(String name, String connectionString)
      : this(name, connectionString, null)



      public ConnectionStringSettings(String name, String connectionString, String providerName)

      this.Name = name;
      this.ConnectionString = connectionString;
      this.ProviderName = providerName;


      protected bool Equals(ConnectionStringSettings other)

      return String.Equals(Name, other.Name) && String.Equals(ConnectionString, other.ConnectionString) && String.Equals(ProviderName, other.ProviderName);


      public override bool Equals(Object obj)

      if (ReferenceEquals(null, obj)) return false;
      if (ReferenceEquals(this, obj)) return true;
      if (obj.GetType() != this.GetType()) return false;
      return Equals((ConnectionStringSettings) obj);


      public override int GetHashCode()

      unchecked

      int hashCode = (Name != null ? Name.GetHashCode() : 0);
      hashCode = (hashCode * 397) ^ (ConnectionString != null ? ConnectionString.GetHashCode() : 0);
      hashCode = (hashCode * 397) ^ (ProviderName != null ? ProviderName.GetHashCode() : 0);
      return hashCode;



      public static bool operator ==(ConnectionStringSettings left, ConnectionStringSettings right)

      return Equals(left, right);


      public static bool operator !=(ConnectionStringSettings left, ConnectionStringSettings right)

      return !Equals(left, right);




      Next is the collection of ConnectionStringSettings. This is only necessary because the Name of the connection string is the key in the JSON notation. In order to keep that name consistently attached we need to override Dictionary's Add method (but you can't do that because its not virtual). So all we are REALLY doing is just wrapping a Dictionary internally with that extra bit in our own Add implementation. Again this looks like a lot of code, but you'll see it's very monotonous boring stuff.



      public class ConnectionStringSettingsCollection : IDictionary<String, ConnectionStringSettings>

      private readonly Dictionary<String, ConnectionStringSettings> m_ConnectionStrings;

      public ConnectionStringSettingsCollection()

      m_ConnectionStrings = new Dictionary<String, ConnectionStringSettings>();


      public ConnectionStringSettingsCollection(int capacity)

      m_ConnectionStrings = new Dictionary<String, ConnectionStringSettings>(capacity);


      #region IEnumerable methods
      IEnumerator IEnumerable.GetEnumerator()

      return ((IEnumerable)m_ConnectionStrings).GetEnumerator();

      #endregion

      #region IEnumerable<> methods
      IEnumerator<KeyValuePair<String, ConnectionStringSettings>> IEnumerable<KeyValuePair<String, ConnectionStringSettings>>.GetEnumerator()

      return ((IEnumerable<KeyValuePair<String, ConnectionStringSettings>>)m_ConnectionStrings).GetEnumerator();

      #endregion

      #region ICollection<> methods
      void ICollection<KeyValuePair<String, ConnectionStringSettings>>.Add(KeyValuePair<String, ConnectionStringSettings> item)

      ((ICollection<KeyValuePair<String, ConnectionStringSettings>>)m_ConnectionStrings).Add(item);


      void ICollection<KeyValuePair<String, ConnectionStringSettings>>.Clear()

      ((ICollection<KeyValuePair<String, ConnectionStringSettings>>)m_ConnectionStrings).Clear();


      Boolean ICollection<KeyValuePair<String, ConnectionStringSettings>>.Contains(KeyValuePair<String, ConnectionStringSettings> item)

      return ((ICollection<KeyValuePair<String, ConnectionStringSettings>>)m_ConnectionStrings).Contains(item);


      void ICollection<KeyValuePair<String, ConnectionStringSettings>>.CopyTo(KeyValuePair<String, ConnectionStringSettings> array, Int32 arrayIndex)

      ((ICollection<KeyValuePair<String, ConnectionStringSettings>>)m_ConnectionStrings).CopyTo(array, arrayIndex);


      Boolean ICollection<KeyValuePair<String, ConnectionStringSettings>>.Remove(KeyValuePair<String, ConnectionStringSettings> item)

      return ((ICollection<KeyValuePair<String, ConnectionStringSettings>>)m_ConnectionStrings).Remove(item);


      public Int32 Count => ((ICollection<KeyValuePair<String, ConnectionStringSettings>>)m_ConnectionStrings).Count;
      public Boolean IsReadOnly => ((ICollection<KeyValuePair<String, ConnectionStringSettings>>)m_ConnectionStrings).IsReadOnly;
      #endregion

      #region IDictionary<> methods
      public void Add(String key, ConnectionStringSettings value)

      // NOTE only slight modification, we add back in the Name of connectionString here (since it is the key)
      value.Name = key;
      m_ConnectionStrings.Add(key, value);


      public Boolean ContainsKey(String key)

      return m_ConnectionStrings.ContainsKey(key);


      public Boolean Remove(String key)

      return m_ConnectionStrings.Remove(key);


      public Boolean TryGetValue(String key, out ConnectionStringSettings value)

      return m_ConnectionStrings.TryGetValue(key, out value);


      public ConnectionStringSettings this[String key]

      get => m_ConnectionStrings[key];
      set => Add(key, value);


      public ICollection<String> Keys => m_ConnectionStrings.Keys;
      public ICollection<ConnectionStringSettings> Values => m_ConnectionStrings.Values;
      #endregion



      A few simple extension methods to make things simpler.



      public static class ConnectionStringSettingsExtensions

      public static ConnectionStringSettingsCollection ConnectionStrings(this IConfigurationRoot configuration, String section = "ConnectionStrings")

      var connectionStringCollection = configuration.GetSection(section).Get<ConnectionStringSettingsCollection>();
      if (connectionStringCollection == null)

      return new ConnectionStringSettingsCollection();


      return connectionStringCollection;


      public static ConnectionStringSettings ConnectionString(this IConfigurationRoot configuration, String name, String section = "ConnectionStrings")

      ConnectionStringSettings connectionStringSettings;

      var connectionStringCollection = configuration.GetSection(section).Get<ConnectionStringSettingsCollection>();
      if (connectionStringCollection == null



      Finally the usage.



      var configuration = new ConfigurationBuilder()
      .AddJsonFile("config.json")
      .Build();

      var connectionStrings = configuration.ConnectionStrings();

      foreach (var connectionString in connectionStrings.Values)

      Console.WriteLine(connectionString.Name);
      Console.WriteLine(connectionString.ConnectionString);
      Console.WriteLine(connectionString.ProviderName);


      var specificConnStr1 = connectionStrings["Test1"];
      Console.WriteLine(specificConnStr1.Name);
      Console.WriteLine(specificConnStr1.ConnectionString);
      Console.WriteLine(specificConnStr1.ProviderName);

      var specificConnStr2 = configuration.ConnectionString("Test2");
      Console.WriteLine(specificConnStr2.Name);
      Console.WriteLine(specificConnStr2.ConnectionString);
      Console.WriteLine(specificConnStr2.ProviderName);






      share|improve this answer














      share|improve this answer



      share|improve this answer








      edited May 2 '17 at 2:21

























      answered Apr 27 '17 at 2:46









      NicholiNicholi

      8331630




      8331630












      • Upvote for the inspiration!

        – granadaCoder
        Nov 15 '18 at 20:25

















      • Upvote for the inspiration!

        – granadaCoder
        Nov 15 '18 at 20:25
















      Upvote for the inspiration!

      – granadaCoder
      Nov 15 '18 at 20:25





      Upvote for the inspiration!

      – granadaCoder
      Nov 15 '18 at 20:25













      1














      First off, Nicholi's answer inspired me! Thanks Nicholi.



      Second, I have a "List" solution rather than a IDictionary solution. It's not as smooth as the IDictionary solution.



      This can also be dubbed "how to create a collection list for dot net core configuration"



      Here we go:



      first a shameless theft!



      public class ConnectionStringEntry

      public String Name get; set;
      public String ConnectionString get; set;
      public String ProviderName get; set;

      public ConnectionStringEntry()



      public ConnectionStringEntry(String name, String connectionString)
      : this(name, connectionString, null)



      public ConnectionStringEntry(String name, String connectionString, String providerName)

      this.Name = name;
      this.ConnectionString = connectionString;
      this.ProviderName = providerName;




      second, a "wrapper". I wanted to track a DefaultConnectionStringName...along side my List (collection) of Entries.



      public class ConnectionStringWrapper

      public string DefaultConnectionStringName get; set; = "";
      public List<ConnectionStringEntry> ConnectionStringEntries get; set; = new List<ConnectionStringEntry>();
      //public Dictionary<string, ConnectionStringEntry> ConnectionStringEntries get; set; = new Dictionary<string, ConnectionStringEntry>();

      public ConnectionStringEntry GetDefaultConnectionStringEntry()

      ConnectionStringEntry returnItem = this.GetConnectionStringEntry(this.DefaultConnectionStringName);
      return returnItem;


      public ConnectionStringEntry GetConnectionStringEntry(string name)

      ConnectionStringEntry returnItem = null;
      if (null != this.ConnectionStringEntries && this.ConnectionStringEntries.Any())

      returnItem = this.ConnectionStringEntries.FirstOrDefault(ce => ce.Name.Equals(name, StringComparison.OrdinalIgnoreCase));


      if (null == returnItem)

      throw new ArgumentOutOfRangeException(string.Format("No default ConnectionStringEntry found. (ConnectionStringEntries.Names='0', Search.Name='1')", this.ConnectionStringEntries == null ? string.Empty : string.Join(",", this.ConnectionStringEntries.Select(ce => ce.Name)), name));


      return returnItem;




      Now, my reading the json and mapping to a concrete settings object code:



       IConfiguration config = new ConfigurationBuilder()
      .SetBasePath(System.IO.Directory.GetCurrentDirectory())
      .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
      .Build();


      ConnectionStringWrapper settings = new ConnectionStringWrapper();
      config.Bind("ConnectionStringWrapperSettings", settings);
      Console.WriteLine("0, 1", settings.DefaultConnectionStringName, settings.ConnectionStringEntries.Count);
      ConnectionStringEntry cse = settings.GetDefaultConnectionStringEntry();


      My nuget packages:



      .nugetpackagesmicrosoft.extensions.configuration2.1.1
      .nugetpackagesmicrosoft.extensions.configuration.binder2.1.1
      .nugetpackagesmicrosoft.extensions.configuration.json2.1.1


      BONUS MATERIAL BELOW:



      One of the things I am (trying) to so support a code base that can be deployed as DotNet 4.x ("classic" ?? as the term now??) and dotnet core.



      To that end, I've written the above to provide an abstraction from the way DotNet(Classic) handles connection strings (xml, our old long time friend) and now the new cool kid on the block : DotNetCore with json.



      To that end, I've written an interface:



      public interface IConnectionStringWrapperRetriever

      ConnectionStringWrapper RetrieveConnectionStringWrapper();



      and I have an implementation for dotnetcore:



      public class ConnectionStringWrapperDotNetCoreRetriever : IConnectionStringWrapperRetriever

      public const string ConnectionStringWrapperSettingsJsonElementName = "ConnectionStringWrapperSettings";

      private readonly IConfiguration config;

      public ConnectionStringWrapperDotNetCoreRetriever(IConfiguration cnfg)

      this.config = cnfg;


      public ConnectionStringWrapper RetrieveConnectionStringWrapper()

      ConnectionStringWrapper settings = new ConnectionStringWrapper();
      this.config.Bind(ConnectionStringWrapperSettingsJsonElementName, settings);
      return settings;




      Oh yeah, the all important JSON setup:




      "ConnectionStringWrapperSettings":
      "DefaultConnectionStringName": "abc",
      "ConnectionStringEntries": [

      "Name": "abc",
      "ConnectionString": "Server=myserver;Database=mydatabase;Trusted_Connection=True;MultipleActiveResultSets=true",
      "ProviderName": "SomeProvider"
      ,

      "Name": "def",
      "ConnectionString": "server=localhost;database=db2;username=user2;password=pass2;",
      "ProviderName": "SomeProvider"

      ]




      .............



      For DotNet(classic), all you need to do is implement a second concrete for IConnectionStringWrapperRetriever, and do the magic.



      Remember the below xml? (ha ha, its not that old yet!)



      <?xml version="1.0" encoding="utf-8"?> 
      <configuration>
      <connectionStrings>
      <add name="ConnStr1" connectionString="LocalSqlServer: data source=127.0.0.1;Integrated Security=SSPI;Initial Catalog=aspnetdb"
      providerName="System.Data.SqlClient" />
      </connectionStrings>
      </configuration>


      (from https://docs.microsoft.com/en-us/dotnet/api/system.configuration.connectionstringsettingscollection?view=netframework-4.7.2)



      Remember this stuff from EnterpriseLibrary?



      <configSections>
      <section name="dataConfiguration" type="Microsoft.Practices.EnterpriseLibrary.Data.Configuration.DatabaseSettings, Microsoft.Practices.EnterpriseLibrary.Data, Version=2.0.0.0, Culture=neutral, PublicKeyToken=null"/>
      </configSections>

      <dataConfiguration defaultDatabase="ConnStr1"/>


      I'll leave the DotNet(Classic) implementation to the reader.



      But now I inject IConnectionStringWrapperRetriever into my DataLayer classes.

      I'm using Dapper, so I can fish a connection string using IConnectionStringWrapperRetriever.



      If my project is "house" DotNet(Classic), I inject one version of IConnectionStringWrapperRetriever (not seen here, left to the reader). If my project is "housed" in DotNetCore I inject a second (shown above) version of IConnectionStringWrapperRetriever.



      Outside the scope of this post, but by "housed", I mean I have 2 csproj's sitting side by side.



      MyApp.DataLayer.classic.csproj
      and
      MyApp.DataLayer.csproj



      I find it easier to leave the default csproj to house the DotNetCore stuff. And I use the "classic.csproj" file to house the DotNet(classic). My assembly name and default namespace remain "MyApp.Datalayer"......the .classic is ONLY for the csrproj filename to distinquish.



      I create two solution sln files too. MySolution.classic.sln and MySolution.sln.



      It seems to be working.....with this ConnectionString abstraction I wrote above.



      The ONLY conditional I have is on the (classic) AssemblyInfo.cs files.



      #if(!NETCOREAPP2_1)

      using System.Reflection;
      using System.Runtime.CompilerServices;
      using System.Runtime.InteropServices;

      /* all the other stuff removed here */

      // Version information for an assembly consists of the following four values:
      //
      // Major Version
      // Minor Version
      // Build Number
      // Revision
      //
      // You can specify all the values or you can default the Build and Revision Numbers
      // by using the '*' as shown below:
      // [assembly: AssemblyVersion("1.0.*")]
      [assembly: AssemblyVersion("1.0.0.0")]
      [assembly: AssemblyFileVersion("1.0.0.0")]

      #endif


      APPEND:



      Ok, here is the DotNet(Classic) version:



      public class ConnectionStringWrapperDotNetClassicRetriever : IConnectionStringWrapperRetriever

      public ConnectionStringWrapper RetrieveConnectionStringWrapper()

      ConnectionStringWrapper returnItem = new ConnectionStringWrapper();

      foreach(ConnectionStringSettings css in System.Configuration.ConfigurationManager.ConnectionStrings)

      ConnectionStringEntry cse = new ConnectionStringEntry(css.Name, css.ConnectionString, css.ProviderName);
      returnItem.ConnectionStringEntries.Add(cse);


      if(returnItem.ConnectionStringEntries.Count == 1)

      /* if there is only one, set the default name to that one */
      returnItem.DefaultConnectionStringName = returnItem.ConnectionStringEntries.First().Name;

      else

      /*
      <packages>
      <package id="EnterpriseLibrary.Common" version="6.0.1304.0" targetFramework="net45" />
      <package id="EnterpriseLibrary.Data" version="6.0.1304.0" targetFramework="net45" />
      </packages>
      */

      /* using Microsoft.Practices.EnterpriseLibrary.Data.Configuration; */
      /* You can write you own way to handle a default database, or piggyback off of EnterpriseLibrary. You don't necessarily have to use EnterpriseLibrary.Data, you are simply piggybacking on their xml/configuration setup */
      DatabaseSettings dbSettings = (DatabaseSettings)ConfigurationManager.GetSection("dataConfiguration");
      returnItem.DefaultConnectionStringName = dbSettings.DefaultDatabase;


      return returnItem;




      And the app.config xml:



      <?xml version="1.0" encoding="utf-8" ?>
      <configuration>

      <configSections>
      <section name="dataConfiguration" type="Microsoft.Practices.EnterpriseLibrary.Data.Configuration.DatabaseSettings, Microsoft.Practices.EnterpriseLibrary.Data"/>
      </configSections>

      <connectionStrings>
      <clear/>
      <add name="MyFirstConnectionStringName" connectionString="Server=.MyServerOne;Database=OneDB;Trusted_Connection=True;MultipleActiveResultSets=true"
      providerName="System.Data.SqlClient" />

      <add name="MySecondConnectionStringName" connectionString="Server=.MyServerTwo;Database=TwoDB;Trusted_Connection=True;MultipleActiveResultSets=true"
      providerName="System.Data.SqlClient" />
      </connectionStrings>


      <dataConfiguration defaultDatabase="MyFirstConnectionStringName" />

      <startup>
      <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
      </startup>
      </configuration>


      Key words:



      DotNet DotNet .Net Core Classic Json Configuration ICollection scalar and collection support both dotnet and dotnetcore






      share|improve this answer





























        1














        First off, Nicholi's answer inspired me! Thanks Nicholi.



        Second, I have a "List" solution rather than a IDictionary solution. It's not as smooth as the IDictionary solution.



        This can also be dubbed "how to create a collection list for dot net core configuration"



        Here we go:



        first a shameless theft!



        public class ConnectionStringEntry

        public String Name get; set;
        public String ConnectionString get; set;
        public String ProviderName get; set;

        public ConnectionStringEntry()



        public ConnectionStringEntry(String name, String connectionString)
        : this(name, connectionString, null)



        public ConnectionStringEntry(String name, String connectionString, String providerName)

        this.Name = name;
        this.ConnectionString = connectionString;
        this.ProviderName = providerName;




        second, a "wrapper". I wanted to track a DefaultConnectionStringName...along side my List (collection) of Entries.



        public class ConnectionStringWrapper

        public string DefaultConnectionStringName get; set; = "";
        public List<ConnectionStringEntry> ConnectionStringEntries get; set; = new List<ConnectionStringEntry>();
        //public Dictionary<string, ConnectionStringEntry> ConnectionStringEntries get; set; = new Dictionary<string, ConnectionStringEntry>();

        public ConnectionStringEntry GetDefaultConnectionStringEntry()

        ConnectionStringEntry returnItem = this.GetConnectionStringEntry(this.DefaultConnectionStringName);
        return returnItem;


        public ConnectionStringEntry GetConnectionStringEntry(string name)

        ConnectionStringEntry returnItem = null;
        if (null != this.ConnectionStringEntries && this.ConnectionStringEntries.Any())

        returnItem = this.ConnectionStringEntries.FirstOrDefault(ce => ce.Name.Equals(name, StringComparison.OrdinalIgnoreCase));


        if (null == returnItem)

        throw new ArgumentOutOfRangeException(string.Format("No default ConnectionStringEntry found. (ConnectionStringEntries.Names='0', Search.Name='1')", this.ConnectionStringEntries == null ? string.Empty : string.Join(",", this.ConnectionStringEntries.Select(ce => ce.Name)), name));


        return returnItem;




        Now, my reading the json and mapping to a concrete settings object code:



         IConfiguration config = new ConfigurationBuilder()
        .SetBasePath(System.IO.Directory.GetCurrentDirectory())
        .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
        .Build();


        ConnectionStringWrapper settings = new ConnectionStringWrapper();
        config.Bind("ConnectionStringWrapperSettings", settings);
        Console.WriteLine("0, 1", settings.DefaultConnectionStringName, settings.ConnectionStringEntries.Count);
        ConnectionStringEntry cse = settings.GetDefaultConnectionStringEntry();


        My nuget packages:



        .nugetpackagesmicrosoft.extensions.configuration2.1.1
        .nugetpackagesmicrosoft.extensions.configuration.binder2.1.1
        .nugetpackagesmicrosoft.extensions.configuration.json2.1.1


        BONUS MATERIAL BELOW:



        One of the things I am (trying) to so support a code base that can be deployed as DotNet 4.x ("classic" ?? as the term now??) and dotnet core.



        To that end, I've written the above to provide an abstraction from the way DotNet(Classic) handles connection strings (xml, our old long time friend) and now the new cool kid on the block : DotNetCore with json.



        To that end, I've written an interface:



        public interface IConnectionStringWrapperRetriever

        ConnectionStringWrapper RetrieveConnectionStringWrapper();



        and I have an implementation for dotnetcore:



        public class ConnectionStringWrapperDotNetCoreRetriever : IConnectionStringWrapperRetriever

        public const string ConnectionStringWrapperSettingsJsonElementName = "ConnectionStringWrapperSettings";

        private readonly IConfiguration config;

        public ConnectionStringWrapperDotNetCoreRetriever(IConfiguration cnfg)

        this.config = cnfg;


        public ConnectionStringWrapper RetrieveConnectionStringWrapper()

        ConnectionStringWrapper settings = new ConnectionStringWrapper();
        this.config.Bind(ConnectionStringWrapperSettingsJsonElementName, settings);
        return settings;




        Oh yeah, the all important JSON setup:




        "ConnectionStringWrapperSettings":
        "DefaultConnectionStringName": "abc",
        "ConnectionStringEntries": [

        "Name": "abc",
        "ConnectionString": "Server=myserver;Database=mydatabase;Trusted_Connection=True;MultipleActiveResultSets=true",
        "ProviderName": "SomeProvider"
        ,

        "Name": "def",
        "ConnectionString": "server=localhost;database=db2;username=user2;password=pass2;",
        "ProviderName": "SomeProvider"

        ]




        .............



        For DotNet(classic), all you need to do is implement a second concrete for IConnectionStringWrapperRetriever, and do the magic.



        Remember the below xml? (ha ha, its not that old yet!)



        <?xml version="1.0" encoding="utf-8"?> 
        <configuration>
        <connectionStrings>
        <add name="ConnStr1" connectionString="LocalSqlServer: data source=127.0.0.1;Integrated Security=SSPI;Initial Catalog=aspnetdb"
        providerName="System.Data.SqlClient" />
        </connectionStrings>
        </configuration>


        (from https://docs.microsoft.com/en-us/dotnet/api/system.configuration.connectionstringsettingscollection?view=netframework-4.7.2)



        Remember this stuff from EnterpriseLibrary?



        <configSections>
        <section name="dataConfiguration" type="Microsoft.Practices.EnterpriseLibrary.Data.Configuration.DatabaseSettings, Microsoft.Practices.EnterpriseLibrary.Data, Version=2.0.0.0, Culture=neutral, PublicKeyToken=null"/>
        </configSections>

        <dataConfiguration defaultDatabase="ConnStr1"/>


        I'll leave the DotNet(Classic) implementation to the reader.



        But now I inject IConnectionStringWrapperRetriever into my DataLayer classes.

        I'm using Dapper, so I can fish a connection string using IConnectionStringWrapperRetriever.



        If my project is "house" DotNet(Classic), I inject one version of IConnectionStringWrapperRetriever (not seen here, left to the reader). If my project is "housed" in DotNetCore I inject a second (shown above) version of IConnectionStringWrapperRetriever.



        Outside the scope of this post, but by "housed", I mean I have 2 csproj's sitting side by side.



        MyApp.DataLayer.classic.csproj
        and
        MyApp.DataLayer.csproj



        I find it easier to leave the default csproj to house the DotNetCore stuff. And I use the "classic.csproj" file to house the DotNet(classic). My assembly name and default namespace remain "MyApp.Datalayer"......the .classic is ONLY for the csrproj filename to distinquish.



        I create two solution sln files too. MySolution.classic.sln and MySolution.sln.



        It seems to be working.....with this ConnectionString abstraction I wrote above.



        The ONLY conditional I have is on the (classic) AssemblyInfo.cs files.



        #if(!NETCOREAPP2_1)

        using System.Reflection;
        using System.Runtime.CompilerServices;
        using System.Runtime.InteropServices;

        /* all the other stuff removed here */

        // Version information for an assembly consists of the following four values:
        //
        // Major Version
        // Minor Version
        // Build Number
        // Revision
        //
        // You can specify all the values or you can default the Build and Revision Numbers
        // by using the '*' as shown below:
        // [assembly: AssemblyVersion("1.0.*")]
        [assembly: AssemblyVersion("1.0.0.0")]
        [assembly: AssemblyFileVersion("1.0.0.0")]

        #endif


        APPEND:



        Ok, here is the DotNet(Classic) version:



        public class ConnectionStringWrapperDotNetClassicRetriever : IConnectionStringWrapperRetriever

        public ConnectionStringWrapper RetrieveConnectionStringWrapper()

        ConnectionStringWrapper returnItem = new ConnectionStringWrapper();

        foreach(ConnectionStringSettings css in System.Configuration.ConfigurationManager.ConnectionStrings)

        ConnectionStringEntry cse = new ConnectionStringEntry(css.Name, css.ConnectionString, css.ProviderName);
        returnItem.ConnectionStringEntries.Add(cse);


        if(returnItem.ConnectionStringEntries.Count == 1)

        /* if there is only one, set the default name to that one */
        returnItem.DefaultConnectionStringName = returnItem.ConnectionStringEntries.First().Name;

        else

        /*
        <packages>
        <package id="EnterpriseLibrary.Common" version="6.0.1304.0" targetFramework="net45" />
        <package id="EnterpriseLibrary.Data" version="6.0.1304.0" targetFramework="net45" />
        </packages>
        */

        /* using Microsoft.Practices.EnterpriseLibrary.Data.Configuration; */
        /* You can write you own way to handle a default database, or piggyback off of EnterpriseLibrary. You don't necessarily have to use EnterpriseLibrary.Data, you are simply piggybacking on their xml/configuration setup */
        DatabaseSettings dbSettings = (DatabaseSettings)ConfigurationManager.GetSection("dataConfiguration");
        returnItem.DefaultConnectionStringName = dbSettings.DefaultDatabase;


        return returnItem;




        And the app.config xml:



        <?xml version="1.0" encoding="utf-8" ?>
        <configuration>

        <configSections>
        <section name="dataConfiguration" type="Microsoft.Practices.EnterpriseLibrary.Data.Configuration.DatabaseSettings, Microsoft.Practices.EnterpriseLibrary.Data"/>
        </configSections>

        <connectionStrings>
        <clear/>
        <add name="MyFirstConnectionStringName" connectionString="Server=.MyServerOne;Database=OneDB;Trusted_Connection=True;MultipleActiveResultSets=true"
        providerName="System.Data.SqlClient" />

        <add name="MySecondConnectionStringName" connectionString="Server=.MyServerTwo;Database=TwoDB;Trusted_Connection=True;MultipleActiveResultSets=true"
        providerName="System.Data.SqlClient" />
        </connectionStrings>


        <dataConfiguration defaultDatabase="MyFirstConnectionStringName" />

        <startup>
        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
        </startup>
        </configuration>


        Key words:



        DotNet DotNet .Net Core Classic Json Configuration ICollection scalar and collection support both dotnet and dotnetcore






        share|improve this answer



























          1












          1








          1







          First off, Nicholi's answer inspired me! Thanks Nicholi.



          Second, I have a "List" solution rather than a IDictionary solution. It's not as smooth as the IDictionary solution.



          This can also be dubbed "how to create a collection list for dot net core configuration"



          Here we go:



          first a shameless theft!



          public class ConnectionStringEntry

          public String Name get; set;
          public String ConnectionString get; set;
          public String ProviderName get; set;

          public ConnectionStringEntry()



          public ConnectionStringEntry(String name, String connectionString)
          : this(name, connectionString, null)



          public ConnectionStringEntry(String name, String connectionString, String providerName)

          this.Name = name;
          this.ConnectionString = connectionString;
          this.ProviderName = providerName;




          second, a "wrapper". I wanted to track a DefaultConnectionStringName...along side my List (collection) of Entries.



          public class ConnectionStringWrapper

          public string DefaultConnectionStringName get; set; = "";
          public List<ConnectionStringEntry> ConnectionStringEntries get; set; = new List<ConnectionStringEntry>();
          //public Dictionary<string, ConnectionStringEntry> ConnectionStringEntries get; set; = new Dictionary<string, ConnectionStringEntry>();

          public ConnectionStringEntry GetDefaultConnectionStringEntry()

          ConnectionStringEntry returnItem = this.GetConnectionStringEntry(this.DefaultConnectionStringName);
          return returnItem;


          public ConnectionStringEntry GetConnectionStringEntry(string name)

          ConnectionStringEntry returnItem = null;
          if (null != this.ConnectionStringEntries && this.ConnectionStringEntries.Any())

          returnItem = this.ConnectionStringEntries.FirstOrDefault(ce => ce.Name.Equals(name, StringComparison.OrdinalIgnoreCase));


          if (null == returnItem)

          throw new ArgumentOutOfRangeException(string.Format("No default ConnectionStringEntry found. (ConnectionStringEntries.Names='0', Search.Name='1')", this.ConnectionStringEntries == null ? string.Empty : string.Join(",", this.ConnectionStringEntries.Select(ce => ce.Name)), name));


          return returnItem;




          Now, my reading the json and mapping to a concrete settings object code:



           IConfiguration config = new ConfigurationBuilder()
          .SetBasePath(System.IO.Directory.GetCurrentDirectory())
          .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
          .Build();


          ConnectionStringWrapper settings = new ConnectionStringWrapper();
          config.Bind("ConnectionStringWrapperSettings", settings);
          Console.WriteLine("0, 1", settings.DefaultConnectionStringName, settings.ConnectionStringEntries.Count);
          ConnectionStringEntry cse = settings.GetDefaultConnectionStringEntry();


          My nuget packages:



          .nugetpackagesmicrosoft.extensions.configuration2.1.1
          .nugetpackagesmicrosoft.extensions.configuration.binder2.1.1
          .nugetpackagesmicrosoft.extensions.configuration.json2.1.1


          BONUS MATERIAL BELOW:



          One of the things I am (trying) to so support a code base that can be deployed as DotNet 4.x ("classic" ?? as the term now??) and dotnet core.



          To that end, I've written the above to provide an abstraction from the way DotNet(Classic) handles connection strings (xml, our old long time friend) and now the new cool kid on the block : DotNetCore with json.



          To that end, I've written an interface:



          public interface IConnectionStringWrapperRetriever

          ConnectionStringWrapper RetrieveConnectionStringWrapper();



          and I have an implementation for dotnetcore:



          public class ConnectionStringWrapperDotNetCoreRetriever : IConnectionStringWrapperRetriever

          public const string ConnectionStringWrapperSettingsJsonElementName = "ConnectionStringWrapperSettings";

          private readonly IConfiguration config;

          public ConnectionStringWrapperDotNetCoreRetriever(IConfiguration cnfg)

          this.config = cnfg;


          public ConnectionStringWrapper RetrieveConnectionStringWrapper()

          ConnectionStringWrapper settings = new ConnectionStringWrapper();
          this.config.Bind(ConnectionStringWrapperSettingsJsonElementName, settings);
          return settings;




          Oh yeah, the all important JSON setup:




          "ConnectionStringWrapperSettings":
          "DefaultConnectionStringName": "abc",
          "ConnectionStringEntries": [

          "Name": "abc",
          "ConnectionString": "Server=myserver;Database=mydatabase;Trusted_Connection=True;MultipleActiveResultSets=true",
          "ProviderName": "SomeProvider"
          ,

          "Name": "def",
          "ConnectionString": "server=localhost;database=db2;username=user2;password=pass2;",
          "ProviderName": "SomeProvider"

          ]




          .............



          For DotNet(classic), all you need to do is implement a second concrete for IConnectionStringWrapperRetriever, and do the magic.



          Remember the below xml? (ha ha, its not that old yet!)



          <?xml version="1.0" encoding="utf-8"?> 
          <configuration>
          <connectionStrings>
          <add name="ConnStr1" connectionString="LocalSqlServer: data source=127.0.0.1;Integrated Security=SSPI;Initial Catalog=aspnetdb"
          providerName="System.Data.SqlClient" />
          </connectionStrings>
          </configuration>


          (from https://docs.microsoft.com/en-us/dotnet/api/system.configuration.connectionstringsettingscollection?view=netframework-4.7.2)



          Remember this stuff from EnterpriseLibrary?



          <configSections>
          <section name="dataConfiguration" type="Microsoft.Practices.EnterpriseLibrary.Data.Configuration.DatabaseSettings, Microsoft.Practices.EnterpriseLibrary.Data, Version=2.0.0.0, Culture=neutral, PublicKeyToken=null"/>
          </configSections>

          <dataConfiguration defaultDatabase="ConnStr1"/>


          I'll leave the DotNet(Classic) implementation to the reader.



          But now I inject IConnectionStringWrapperRetriever into my DataLayer classes.

          I'm using Dapper, so I can fish a connection string using IConnectionStringWrapperRetriever.



          If my project is "house" DotNet(Classic), I inject one version of IConnectionStringWrapperRetriever (not seen here, left to the reader). If my project is "housed" in DotNetCore I inject a second (shown above) version of IConnectionStringWrapperRetriever.



          Outside the scope of this post, but by "housed", I mean I have 2 csproj's sitting side by side.



          MyApp.DataLayer.classic.csproj
          and
          MyApp.DataLayer.csproj



          I find it easier to leave the default csproj to house the DotNetCore stuff. And I use the "classic.csproj" file to house the DotNet(classic). My assembly name and default namespace remain "MyApp.Datalayer"......the .classic is ONLY for the csrproj filename to distinquish.



          I create two solution sln files too. MySolution.classic.sln and MySolution.sln.



          It seems to be working.....with this ConnectionString abstraction I wrote above.



          The ONLY conditional I have is on the (classic) AssemblyInfo.cs files.



          #if(!NETCOREAPP2_1)

          using System.Reflection;
          using System.Runtime.CompilerServices;
          using System.Runtime.InteropServices;

          /* all the other stuff removed here */

          // Version information for an assembly consists of the following four values:
          //
          // Major Version
          // Minor Version
          // Build Number
          // Revision
          //
          // You can specify all the values or you can default the Build and Revision Numbers
          // by using the '*' as shown below:
          // [assembly: AssemblyVersion("1.0.*")]
          [assembly: AssemblyVersion("1.0.0.0")]
          [assembly: AssemblyFileVersion("1.0.0.0")]

          #endif


          APPEND:



          Ok, here is the DotNet(Classic) version:



          public class ConnectionStringWrapperDotNetClassicRetriever : IConnectionStringWrapperRetriever

          public ConnectionStringWrapper RetrieveConnectionStringWrapper()

          ConnectionStringWrapper returnItem = new ConnectionStringWrapper();

          foreach(ConnectionStringSettings css in System.Configuration.ConfigurationManager.ConnectionStrings)

          ConnectionStringEntry cse = new ConnectionStringEntry(css.Name, css.ConnectionString, css.ProviderName);
          returnItem.ConnectionStringEntries.Add(cse);


          if(returnItem.ConnectionStringEntries.Count == 1)

          /* if there is only one, set the default name to that one */
          returnItem.DefaultConnectionStringName = returnItem.ConnectionStringEntries.First().Name;

          else

          /*
          <packages>
          <package id="EnterpriseLibrary.Common" version="6.0.1304.0" targetFramework="net45" />
          <package id="EnterpriseLibrary.Data" version="6.0.1304.0" targetFramework="net45" />
          </packages>
          */

          /* using Microsoft.Practices.EnterpriseLibrary.Data.Configuration; */
          /* You can write you own way to handle a default database, or piggyback off of EnterpriseLibrary. You don't necessarily have to use EnterpriseLibrary.Data, you are simply piggybacking on their xml/configuration setup */
          DatabaseSettings dbSettings = (DatabaseSettings)ConfigurationManager.GetSection("dataConfiguration");
          returnItem.DefaultConnectionStringName = dbSettings.DefaultDatabase;


          return returnItem;




          And the app.config xml:



          <?xml version="1.0" encoding="utf-8" ?>
          <configuration>

          <configSections>
          <section name="dataConfiguration" type="Microsoft.Practices.EnterpriseLibrary.Data.Configuration.DatabaseSettings, Microsoft.Practices.EnterpriseLibrary.Data"/>
          </configSections>

          <connectionStrings>
          <clear/>
          <add name="MyFirstConnectionStringName" connectionString="Server=.MyServerOne;Database=OneDB;Trusted_Connection=True;MultipleActiveResultSets=true"
          providerName="System.Data.SqlClient" />

          <add name="MySecondConnectionStringName" connectionString="Server=.MyServerTwo;Database=TwoDB;Trusted_Connection=True;MultipleActiveResultSets=true"
          providerName="System.Data.SqlClient" />
          </connectionStrings>


          <dataConfiguration defaultDatabase="MyFirstConnectionStringName" />

          <startup>
          <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
          </startup>
          </configuration>


          Key words:



          DotNet DotNet .Net Core Classic Json Configuration ICollection scalar and collection support both dotnet and dotnetcore






          share|improve this answer















          First off, Nicholi's answer inspired me! Thanks Nicholi.



          Second, I have a "List" solution rather than a IDictionary solution. It's not as smooth as the IDictionary solution.



          This can also be dubbed "how to create a collection list for dot net core configuration"



          Here we go:



          first a shameless theft!



          public class ConnectionStringEntry

          public String Name get; set;
          public String ConnectionString get; set;
          public String ProviderName get; set;

          public ConnectionStringEntry()



          public ConnectionStringEntry(String name, String connectionString)
          : this(name, connectionString, null)



          public ConnectionStringEntry(String name, String connectionString, String providerName)

          this.Name = name;
          this.ConnectionString = connectionString;
          this.ProviderName = providerName;




          second, a "wrapper". I wanted to track a DefaultConnectionStringName...along side my List (collection) of Entries.



          public class ConnectionStringWrapper

          public string DefaultConnectionStringName get; set; = "";
          public List<ConnectionStringEntry> ConnectionStringEntries get; set; = new List<ConnectionStringEntry>();
          //public Dictionary<string, ConnectionStringEntry> ConnectionStringEntries get; set; = new Dictionary<string, ConnectionStringEntry>();

          public ConnectionStringEntry GetDefaultConnectionStringEntry()

          ConnectionStringEntry returnItem = this.GetConnectionStringEntry(this.DefaultConnectionStringName);
          return returnItem;


          public ConnectionStringEntry GetConnectionStringEntry(string name)

          ConnectionStringEntry returnItem = null;
          if (null != this.ConnectionStringEntries && this.ConnectionStringEntries.Any())

          returnItem = this.ConnectionStringEntries.FirstOrDefault(ce => ce.Name.Equals(name, StringComparison.OrdinalIgnoreCase));


          if (null == returnItem)

          throw new ArgumentOutOfRangeException(string.Format("No default ConnectionStringEntry found. (ConnectionStringEntries.Names='0', Search.Name='1')", this.ConnectionStringEntries == null ? string.Empty : string.Join(",", this.ConnectionStringEntries.Select(ce => ce.Name)), name));


          return returnItem;




          Now, my reading the json and mapping to a concrete settings object code:



           IConfiguration config = new ConfigurationBuilder()
          .SetBasePath(System.IO.Directory.GetCurrentDirectory())
          .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
          .Build();


          ConnectionStringWrapper settings = new ConnectionStringWrapper();
          config.Bind("ConnectionStringWrapperSettings", settings);
          Console.WriteLine("0, 1", settings.DefaultConnectionStringName, settings.ConnectionStringEntries.Count);
          ConnectionStringEntry cse = settings.GetDefaultConnectionStringEntry();


          My nuget packages:



          .nugetpackagesmicrosoft.extensions.configuration2.1.1
          .nugetpackagesmicrosoft.extensions.configuration.binder2.1.1
          .nugetpackagesmicrosoft.extensions.configuration.json2.1.1


          BONUS MATERIAL BELOW:



          One of the things I am (trying) to so support a code base that can be deployed as DotNet 4.x ("classic" ?? as the term now??) and dotnet core.



          To that end, I've written the above to provide an abstraction from the way DotNet(Classic) handles connection strings (xml, our old long time friend) and now the new cool kid on the block : DotNetCore with json.



          To that end, I've written an interface:



          public interface IConnectionStringWrapperRetriever

          ConnectionStringWrapper RetrieveConnectionStringWrapper();



          and I have an implementation for dotnetcore:



          public class ConnectionStringWrapperDotNetCoreRetriever : IConnectionStringWrapperRetriever

          public const string ConnectionStringWrapperSettingsJsonElementName = "ConnectionStringWrapperSettings";

          private readonly IConfiguration config;

          public ConnectionStringWrapperDotNetCoreRetriever(IConfiguration cnfg)

          this.config = cnfg;


          public ConnectionStringWrapper RetrieveConnectionStringWrapper()

          ConnectionStringWrapper settings = new ConnectionStringWrapper();
          this.config.Bind(ConnectionStringWrapperSettingsJsonElementName, settings);
          return settings;




          Oh yeah, the all important JSON setup:




          "ConnectionStringWrapperSettings":
          "DefaultConnectionStringName": "abc",
          "ConnectionStringEntries": [

          "Name": "abc",
          "ConnectionString": "Server=myserver;Database=mydatabase;Trusted_Connection=True;MultipleActiveResultSets=true",
          "ProviderName": "SomeProvider"
          ,

          "Name": "def",
          "ConnectionString": "server=localhost;database=db2;username=user2;password=pass2;",
          "ProviderName": "SomeProvider"

          ]




          .............



          For DotNet(classic), all you need to do is implement a second concrete for IConnectionStringWrapperRetriever, and do the magic.



          Remember the below xml? (ha ha, its not that old yet!)



          <?xml version="1.0" encoding="utf-8"?> 
          <configuration>
          <connectionStrings>
          <add name="ConnStr1" connectionString="LocalSqlServer: data source=127.0.0.1;Integrated Security=SSPI;Initial Catalog=aspnetdb"
          providerName="System.Data.SqlClient" />
          </connectionStrings>
          </configuration>


          (from https://docs.microsoft.com/en-us/dotnet/api/system.configuration.connectionstringsettingscollection?view=netframework-4.7.2)



          Remember this stuff from EnterpriseLibrary?



          <configSections>
          <section name="dataConfiguration" type="Microsoft.Practices.EnterpriseLibrary.Data.Configuration.DatabaseSettings, Microsoft.Practices.EnterpriseLibrary.Data, Version=2.0.0.0, Culture=neutral, PublicKeyToken=null"/>
          </configSections>

          <dataConfiguration defaultDatabase="ConnStr1"/>


          I'll leave the DotNet(Classic) implementation to the reader.



          But now I inject IConnectionStringWrapperRetriever into my DataLayer classes.

          I'm using Dapper, so I can fish a connection string using IConnectionStringWrapperRetriever.



          If my project is "house" DotNet(Classic), I inject one version of IConnectionStringWrapperRetriever (not seen here, left to the reader). If my project is "housed" in DotNetCore I inject a second (shown above) version of IConnectionStringWrapperRetriever.



          Outside the scope of this post, but by "housed", I mean I have 2 csproj's sitting side by side.



          MyApp.DataLayer.classic.csproj
          and
          MyApp.DataLayer.csproj



          I find it easier to leave the default csproj to house the DotNetCore stuff. And I use the "classic.csproj" file to house the DotNet(classic). My assembly name and default namespace remain "MyApp.Datalayer"......the .classic is ONLY for the csrproj filename to distinquish.



          I create two solution sln files too. MySolution.classic.sln and MySolution.sln.



          It seems to be working.....with this ConnectionString abstraction I wrote above.



          The ONLY conditional I have is on the (classic) AssemblyInfo.cs files.



          #if(!NETCOREAPP2_1)

          using System.Reflection;
          using System.Runtime.CompilerServices;
          using System.Runtime.InteropServices;

          /* all the other stuff removed here */

          // Version information for an assembly consists of the following four values:
          //
          // Major Version
          // Minor Version
          // Build Number
          // Revision
          //
          // You can specify all the values or you can default the Build and Revision Numbers
          // by using the '*' as shown below:
          // [assembly: AssemblyVersion("1.0.*")]
          [assembly: AssemblyVersion("1.0.0.0")]
          [assembly: AssemblyFileVersion("1.0.0.0")]

          #endif


          APPEND:



          Ok, here is the DotNet(Classic) version:



          public class ConnectionStringWrapperDotNetClassicRetriever : IConnectionStringWrapperRetriever

          public ConnectionStringWrapper RetrieveConnectionStringWrapper()

          ConnectionStringWrapper returnItem = new ConnectionStringWrapper();

          foreach(ConnectionStringSettings css in System.Configuration.ConfigurationManager.ConnectionStrings)

          ConnectionStringEntry cse = new ConnectionStringEntry(css.Name, css.ConnectionString, css.ProviderName);
          returnItem.ConnectionStringEntries.Add(cse);


          if(returnItem.ConnectionStringEntries.Count == 1)

          /* if there is only one, set the default name to that one */
          returnItem.DefaultConnectionStringName = returnItem.ConnectionStringEntries.First().Name;

          else

          /*
          <packages>
          <package id="EnterpriseLibrary.Common" version="6.0.1304.0" targetFramework="net45" />
          <package id="EnterpriseLibrary.Data" version="6.0.1304.0" targetFramework="net45" />
          </packages>
          */

          /* using Microsoft.Practices.EnterpriseLibrary.Data.Configuration; */
          /* You can write you own way to handle a default database, or piggyback off of EnterpriseLibrary. You don't necessarily have to use EnterpriseLibrary.Data, you are simply piggybacking on their xml/configuration setup */
          DatabaseSettings dbSettings = (DatabaseSettings)ConfigurationManager.GetSection("dataConfiguration");
          returnItem.DefaultConnectionStringName = dbSettings.DefaultDatabase;


          return returnItem;




          And the app.config xml:



          <?xml version="1.0" encoding="utf-8" ?>
          <configuration>

          <configSections>
          <section name="dataConfiguration" type="Microsoft.Practices.EnterpriseLibrary.Data.Configuration.DatabaseSettings, Microsoft.Practices.EnterpriseLibrary.Data"/>
          </configSections>

          <connectionStrings>
          <clear/>
          <add name="MyFirstConnectionStringName" connectionString="Server=.MyServerOne;Database=OneDB;Trusted_Connection=True;MultipleActiveResultSets=true"
          providerName="System.Data.SqlClient" />

          <add name="MySecondConnectionStringName" connectionString="Server=.MyServerTwo;Database=TwoDB;Trusted_Connection=True;MultipleActiveResultSets=true"
          providerName="System.Data.SqlClient" />
          </connectionStrings>


          <dataConfiguration defaultDatabase="MyFirstConnectionStringName" />

          <startup>
          <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
          </startup>
          </configuration>


          Key words:



          DotNet DotNet .Net Core Classic Json Configuration ICollection scalar and collection support both dotnet and dotnetcore







          share|improve this answer














          share|improve this answer



          share|improve this answer








          edited Nov 16 '18 at 13:45

























          answered Nov 15 '18 at 19:22









          granadaCodergranadaCoder

          15.2k55581




          15.2k55581





















              0














              Something like:



               var configurationRoot = new ConfigurationBuilder()
              .SetBasePath(Directory.GetCurrentDirectory())
              .AddJsonFile("appsettings.json", false)
              .Build();

              var conString = configurationRoot["ConnectionStrings:MyConnection"]);





              share|improve this answer



























                0














                Something like:



                 var configurationRoot = new ConfigurationBuilder()
                .SetBasePath(Directory.GetCurrentDirectory())
                .AddJsonFile("appsettings.json", false)
                .Build();

                var conString = configurationRoot["ConnectionStrings:MyConnection"]);





                share|improve this answer

























                  0












                  0








                  0







                  Something like:



                   var configurationRoot = new ConfigurationBuilder()
                  .SetBasePath(Directory.GetCurrentDirectory())
                  .AddJsonFile("appsettings.json", false)
                  .Build();

                  var conString = configurationRoot["ConnectionStrings:MyConnection"]);





                  share|improve this answer













                  Something like:



                   var configurationRoot = new ConfigurationBuilder()
                  .SetBasePath(Directory.GetCurrentDirectory())
                  .AddJsonFile("appsettings.json", false)
                  .Build();

                  var conString = configurationRoot["ConnectionStrings:MyConnection"]);






                  share|improve this answer












                  share|improve this answer



                  share|improve this answer










                  answered Nov 28 '16 at 14:55









                  Derek BeattieDerek Beattie

                  8,35732543




                  8,35732543



























                      draft saved

                      draft discarded
















































                      Thanks for contributing an answer to Stack Overflow!


                      • Please be sure to answer the question. Provide details and share your research!

                      But avoid


                      • Asking for help, clarification, or responding to other answers.

                      • Making statements based on opinion; back them up with references or personal experience.

                      To learn more, see our tips on writing great answers.




                      draft saved


                      draft discarded














                      StackExchange.ready(
                      function ()
                      StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f40845542%2fhow-to-read-a-connectionstring-with-provider-in-net-core%23new-answer', 'question_page');

                      );

                      Post as a guest















                      Required, but never shown





















































                      Required, but never shown














                      Required, but never shown












                      Required, but never shown







                      Required, but never shown

































                      Required, but never shown














                      Required, but never shown












                      Required, but never shown







                      Required, but never shown







                      這個網誌中的熱門文章

                      Barbados

                      Node.js Script on GitHub Pages or Amazon S3