The Problem
Managing the configuration data have always been troublsome. Although Microsoft did provided and also updated/upgraded a lot of options from time to time, yet it remains a challenge most of time. Things get more critical when the configuration data we are concerned is the confidential data like connection string, smtp passwords, API keys etc becase at some point of time, they do get checked in source code or shared across other developers. In one of my prev project faced a similar issue when private key and the Code Signing certificate was accidentally checked in by a developer. The customer had to revoke the certificate which invalidated all the production builds which were deployed to end users as well.
The Solution: ConfigurationBuilder()
With ASP.net there are some pretty cool enhancements that Microsoft added especially with the Configuration Builder. Earlier whole of .net relied on System.Configuration Namespace to get the configuration data. With the current version it has been greatly re-architeced which now provides a simple key value pair from multiple sources prebuild or even custom providers (like azure or mongoDb) which we shall try out in next post.
Following is the standard startup file from empty Asp.net 4 project. I have just added support to use MVC and use of static file.
public class Startup { public void ConfigureServices(IServiceCollection services) { services.AddMvc(); } // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. public void Configure(IApplicationBuilder app) { app.UseStaticFiles(); app.UseMvcWithDefaultRoute(); } // Entry point for the application. public static void Main(string[] args) => WebApplication.Run<Startup>(args); }
Exposing the Configuration
The configurationBuilder provides IConfigurationRoot type when .Build is called on it. This can be easily made available across the codebase using a simple static property which can be them invoked from anywhere.
/// <summary> /// The configuration Object /// Static property as same instance is needed to be returned across the project. The instance will be generated when constructor is called. /// </summary> public static IConfiguration configurationProvider; /// <summary> /// Default Ctor /// </summary> public Startup() { //Create the configuratonBuilder object var configurationBuilder = new ConfigurationBuilder(); //call the .Build and set the configurationRoot object configurationProvider = configurationBuilder.Build(); }
Consuming the Configurations Built
The IConfigurationRoot object created in is a simple key value provider. We can pass in the name of the key and get the value in return. Sample usage is showin in the following MVC Controller.
public class AppController : Controller { public IActionResult Index() { ViewBag.Key1Val = Startup.ConfigurationProvider["Key1"]; return View(); } }
The Options
The Configurationbuilder can be created in the in the constructor of the startup class. There are pretty much options provided by default. Also note that the configurationBuilder provides fluent api which means you can chain different options together in single call.

Options provided by default with configuration builder.
Environment Variables
These are the most basic configuration data store that can be easily created by a single line call of .AddEnvironmentVariables() on the configuration object. The environment variables could also be used to store developer only confidential data.
InMemoryCollection
Although not much useful, but the configuration data can be filled with In Memory collection that takes IEnumerable<KeyValuePair<string,string>> for which dictionary is best candidate. This is not much of use since the data is already hardcoded in code, and can not be updated at runtime.
Following code highlights the use of environment variables and In Memory collection.
public Startup() { //Sample Dictionary object to use in in memory collection. This could be computed or fetched dynamically Dictionary<string, string> someConfigDictionary = new Dictionary<string, string>(); someConfigDictionary.Add("key1", "value1"); someConfigDictionary.Add("key2", "value2"); someConfigDictionary.Add("key3", "value3"); //Create the configuratonBuilder object var configurationBuilder = new ConfigurationBuilder() .AddEnvironmentVariables() .AddInMemoryCollection(someConfigDictionary); //call the .Build and set the configurationRoot object configurationRoot = configurationBuilder.Build(); }
JsonProvider
Microsoft lately had taken Json a lot more seriously. This can be seen in project.json or bower.json. Json Configuration Provider is one of the most useful thing I find for providing the configuration data. The beauty lies in the simplicity of use and configuration. No need to cripple the app.config (or web.config) if you want to configure your application or change the configuration.
First step is of course we need the JSON file that we want to use.
{ "AppSetting": { "MailSettings": { "AdminMailId": "[email protected]", "InfoMailId": "[email protected]", "SmtpServer": "smtp.vineetyadav.com", "SmtpKey": "nvf32f42csafce3-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" }, "ServiceEndpoints": { "AzureAuthEndpoint": "vineetyadav023.cloudservices.net", "AuthServiceEndpotin": "http://local.vineetyadav.com/oauth2", "TokenProvider": "http://local.vineetyadav.com/token" } } }
As in the above config file, i have define multiple keys in 2 level of hierarchies. This file shall remain a simple json file. Once the application is build/deployed, this can be changed either manually or build transforms. To load the json file, first we need to set the base path where it is deployed. This can be done using the SetBasePath method on the builder object. It takes in a string for the base path which can be fetched from IApplicationEnvironment object which is injected by the framework. Following Code shows the same.
public Startup(IApplicationEnvironment appEnv) { //Sample Dictionary object to use in in memory collection. This could be computed or fetched dynamically Dictionary<string, string> someConfigDictionary = new Dictionary<string, string>(); someConfigDictionary.Add("key1", "value1"); someConfigDictionary.Add("key2", "value2"); someConfigDictionary.Add("key3", "value3"); //Create the configuratonBuilder object var configurationBuilder = new ConfigurationBuilder() .SetBasePath(appEnv.ApplicationBasePath) .AddJsonFile("config.json") .AddEnvironmentVariables() .AddInMemoryCollection(someConfigDictionary); //call the .Build and set the ConfigurationRoot object ConfigurationProvider = configurationBuilder.Build(); }
However there is a little twist as regard to accessing these values set by the Json. To access any value, it is needed to pass the key name along with complete hierarchy seperated with ‘:’ (colon). For instance to access the “InfoMailId” from the above json config, the getter should be used as follows:
public class AppController : Controller { public IActionResult Index() { ViewBag.Key1Val = Startup.ConfigurationProvider["Key1"]; ViewBag.InfoMailId= Startup.ConfigurationProvider["AppSetting:MailSettings:InfoMailId"]; return View(); } }
User Secrets
User Secret is a new concept introduced, to store user confidential data like connection string or db credentials in users AppData folder so that it is never added to source code. This will be covered in next post. Keep following.
Custom Configuration Provider (Azure Storage)
ConfigurationBuilder provides extensiblity support to add custom Providers as well. I shall try to demonstrate the same by build a custom provider that uses azure table as a custom data source. This will be covered in next to next post. Keep following. 🙂
Custom Configuration Provider (MongoDb Storage – persumably)
Source Code: https://github.com/yadavvineet/SampleApplications/tree/master/AspConfiguraitonProviderSample/HelloMars
Hi
Thank you for the post, it shed quite a bit of light on this topic. Would you be able to do a basic sample with a MongoDb custom config provider?
Thanks,
Lee
Hi Lee,
Sorry for delayed reply. Was engaged in some work. i already had tried it. Will clean code an share a code sample & tutorial in next few days.
Thanks
Vineet