Using the configuration Builder in ASP.NET 5

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 (azure for example)

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": "admin@vineetyadav.com",
            "InfoMailId": "info@vineetyadav.com",
            "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.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s