.NET Core Configuration: Appsettings vs. Environment Variables

Typical .NET Core application uses the commaon configuration system defined in the package Microsoft.Extensions.Configuration.

My intension in this post is not to describe how that works. IN this post I rather assume you are familiar with .NET Core configuration.

Assume there is already a configuration in the appsettings like this one:

 "MongoMessageProviderConfig": {
    "PollingIntervalSec": 10,
    "CatalogDbConnectionString": "mongodb://..."
  },

To make it working you will do something like this:

...
ConfigurationBuilder builder = new ConfigurationBuilder();
            builder.AddJsonFile(Path.Combine(AppContext.BaseDirectory, "appsettings.json"), false, true);
...
var sec = configRoot.GetSection("MongoMessageProviderConfig");
MongoMessageProviderConfig cfg = new MongoMessageProviderConfig();
                msgProvCfgSection.Bind(cfg);

It means, appsettings.json will be used for configuration, and variable sec is bound to JSON section with the name "MongoMessageProviderConfig".
Now, assume there is a requirement to run the same code in the docker container. In this case your code might change the host. If it was previously hosted in AppService (an example) and now it should me hosted as docker container in Azure Container Registry you will figure out that appsettings support in Azure portal for the AppService is great. But you will also figure out that ACI has not such kind of support. ACI rather provides a great configuration support for environment variables.
In that case you will probably switch from appsettings to environment variables. The question is how to do this without the need to change the code?

First of all you need to add Environment configuration provider.

...
ConfigurationBuilder builder = new ConfigurationBuilder();
builder.AddJsonFile(Path.Combine(AppContext.BaseDirectory, "appsettings.json"), false, true);
builder.AddEnvironmentVariables();
var configRoot = builder.Build();
...

Then you need to add required environment variables in a slightly inconvenient way. For example:

 "Section1": {
    {
     "Section2": {
         "VariableName" : "VariableValue"
     }
    }
  },

will be represented as a single environment variable in the following format:

Section1__Section2__VariableName = VariableValue

Please use double underscores '__' to separate section levels.
Of course you can read this value in .NET as usual:

Environment.GetEnvironmentVariable("MongoMessageProviderConfig__CatalogDbConnectionString")

But it is more interesting, you can use the same code to read value from environment variable.

var sec = configRoot.GetSection("MongoMessageProviderConfig");
MongoMessageProviderConfig cfg = new MongoMessageProviderConfig();
                                 msgProvCfgSection.Bind(cfg);

If the value is also specified in the appsettings.json, environment variable will override it.If you want to change override priority, change the sequence of registration like 'AddEnv'

builder.AddEnvironmentVariables();
builder.AddJsonFile(Path.Combine(AppContext.BaseDirectory, "appsettings.json"), false, true);

Hope this helps.


comments powered by Disqus