Multiple environments are a very common situation in our process to develop software in the enterprise. NET Core 3.1 abandons the classic Web Config to use a .json file, but it goes beyond and gives the developer a very flexible way to configure the application in multiple environments. This article explores how Core manages this setting and how the developer can get the most out of this.
Introduction
Multiple environments are a very common situation in our process to develop software in the enterprise. NET Core 3.1 abandoning the classic Web Config to use a .json file, but it goes beyond and gives developers a very flexible way to configure the application in multiple environments. This article explores how Core manages this setting and how the developer can make the most out of it.
.NET Core 3.1 admits multiple AppSettings allowing us an easy configuration of the application in different environment. Each AppSetting file is differentiated for the other using the AppSettings.EnvironmentName.json convention.
Download Code demo
Background
Core organizes the AppSettings
in the following form:
- One Appsettings.json
- Several optional AppSettings.environment.json
Core manages these files in the following fashion:
- The AppSettings.json is always taken into account to be used in the application.
- Only one environment file is selected depending on the value of the .NET variable:
ASPNETCORE_ENVIRONMENT
This selected file is merged with the general AppSettings.json. In the merge, the following rules are applied:
- All the values of both files go to the final settings.
- If a value is in both files, the value of the environment setting file takes precedence and it is used in the application settings.
Application Settings Example
Let's see a practical example. We have an AppSettings.json with two entries:
- environment = default
- var1 = default
and a AppSettings.dev.json with the following entries:
- environment = dev-environment
- var2 = dev
as you can see in the below image.
If the ASPNETCORE_ENVIRONMENT
variable has value of dev
, then when we build the application, the AppSettings.dev.json is selected and merged with the AppSetting.json as is shown below:
As result of this operation, the configuration variables are the following:
environment
= dev-environment
: because they are in both files and the value of dev
takes precedence over the AppSettings.json var1
= default: because it exists in Appsettings.json var2
= dev: because it exists in AppSettings.dev.json
Using the Code
Download Code demo
To test this, you can use the project attached to this article. Let me briefly explain it.
The project is the simple API template for NET Core 3.1 APIs that you can find in Visual Studio(TM) 2019 that we modified to show best how the AppSettings
works.
We added to the project three extra AppSettings files to be used in three different environment. This is a normal situation in a software developer company.
Now we configure the environments with the following variables:
AppSettings.json
{
"environment": "default",
"var1": "default"
}
AppSettings.dev.json
{
"environment": "dev-environment",
"var2": "dev"
}
AppSettings.Development.json
{
"environment": "Development",
"var3": "development"
}
AppSettings.prod.json
{
"environment": "Production",
"var4": "production"
}
ApplSettings.qa.json
{
"environment": "QA",
"var5": "qa"
}
Note that we have the variable environment in each settings file and var1
to var5
only in one of the rest of the files.
We create a service in this application to read the configuration that the application uses when running. This allows us to know what is really used when the application is in operation.
[HttpGet]
[ProducesResponseType(typeof(string), StatusCodes.Status200OK)]
public IActionResult Get()
{
string env = config["environment"];
string var1 = config["var1"];
string var2 = config["var2"];
string var3 = config["var3"];
string var4 = config["var4"];
string var5 = config["var5"];
string ret = Environment.NewLine;
return Ok($"Environment: {env}{ret}var1:
{var1}{ret}var2: {var2}{ret}var3: {var3}{ret}var4: {var4}{ret}var5: {var5}");
}
Also, we create different profiles that allow us to launch the application using different values of ASPNETCORE_ENVIRONMENT
:
"API Prod": {
"commandName": "IISExpress",
"launchBrowser": true,
"launchUrl": "api/Configuration",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Prod"
}
},
"API Dev": {
"commandName": "IISExpress",
"launchBrowser": true,
"launchUrl": "api/Configuration",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Dev"
}
},
"API QA": {
"commandName": "IISExpress",
"launchBrowser": true,
"launchUrl": "api/Configuration",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "QA"
}
},
Build the application and see what happens when we launch the application using the profile Dev:
You should get this:
Environment: dev-environment
var1: default
var2: dev
var3:
var4:
var5:
Observe that as we explain the variable Environment
, that exists in AppSettings.json and in AppSettings.dev.json take the value of AppSettings.dev.json overriding the value present in AppsSettings.json. The var1
only exists in AppSettings.json and takes the value from there, and var2
only is present in AppSettings.dev.json and takes the value that is in there. Observe that var3
, var4
, and var5
have no value, because they are not present in any of the selected Appsettings.
If we run QA, the result will be different:
Environment: QA
var1: default
var2:
var3:
var4:
var5: qa
You can continue to test, but it demonstrates how the final settings are built by the Core in the build process.
Points of Interest
As we see, all variables that you put in AppSettings.json should be used in all environment, except that the variable exists also in a AppSettings.environment.json.
One alternative of organizing our config is to put all values per defect in the AppSettings.json and to repeat in the other config those that change per environment. This organization appears attractive, but in my opinion leads to problems in real life.
My recommendation is to put in the AppSettings.json those values that are the same in all configurations. and put in AppSettings.environment.json, those values that change in every environment.
This allows you to get errors more easily, because you forgot to put a value, there is no default, and the service fails, given you have the chance to correct it.
If you take the value by defect, the program may still work, but with a false value creating confusing error when you deploy in the test environment that is used for several developers.
For example, you can point to a URL in production and other in QA, if you put the URL of QA in AppSettings.json and forgot to put in production, the program silently takes the QA values and you have no way to know if the configuration is correct.
If there are no values per defect, you can prevent that the program works with a defective configuration, for example, during the health check process, you can detect that the URL is not correct.
You can see more information about this in Video format at : https://youtu.be/cHgRF3bDKXU
History
- 14th March, 2021: Initial version
- Adding reference to Video