In the old days of .NET applications we had a simple xml configuration file that would ship with each environment. This was tried and tested and was well understood. Then came Docker. The promise was that I could build a container on my machine and then ship that exact container to production. This is great except for my trusty configuration file. You don't really want to update the file system of the container for each environment it goes through. There must be a better way!
Luckily containerized applications was a big consideration when ASP.NET core was built and so they cleverly solved the problem with layers of configuration providers. Each layer will override the configuration of the layer below. The default providers in order of precedence are:
- appsettings.json
- appsettings.{environment}.json
- User secrets (development only)
- Environment variables
- Command line arguments
So if I have the following appsettings in my container:
"SystemSettings": {
"Url" : "http://dev-env.com"
}
I could also have a appsettings.uat.json that could override it. This isn't something that I have used very much because then it still requires all your production configuration to be shipped in the same container.
A better way would be to setting the Environment variables for each environment specific value when running the container. So in this example my UAT container would run with the following Environment variable:
SystemSettings__Url = http://uat-env.com
For environment variables a double underscore traverses the json structure to get to the key you want to override.
What is great about ASP.NET Core is that this isn't set in stone. If it doesn't suit your needs, you can change the precedence and even add another configuration provider. A good example would be if you want to get configuration from a database table or cloud provider.