You are currently viewing Applying Config Transformations In .NET Web Applications

Applying Config Transformations In .NET Web Applications

In .NET, the application configuration is stored in appsettings.json file. This article explains how can config transformations be applied to configurations in appsettings.json in .NET applications.

Why Config Transformations?

The configuration files contain settings which are required for your code to execute, and some of them might have different values on different environments.

For ex. let’s say, your application interacts with a SQL Server database. So, your application would need to know the connection string for connecting to it. This connection string would have some value for dev environment and another value for test environment and some third value for the production environment.

The config transformations help to transform the values – automatically during the build. So, once you setup the config transformations, your build pipelines will automatically update the config file with environment specific values, saving you from the tedious job of writing any code to update the config files (or even worst, modifying configs manually after deployment).

.NET Framework – Web.Config Transformations

Traditionally, .NET Framework uses web.config (or app.config) XML configuration files. You might already be aware of a nuget package – SlowCheetah. If not, you can read about it here on GitHub. The readme file explains how the build time transformations work.

How does .NET loads configurations ?

The .NET uses appsettings.json as the default configuration file, instead of web.config. The configurations are in the JSON format. The .NET uses configuration providers to load configuration settings from various sources.

So, let’s quickly have look at what are configuration providers. Later we will also quickly have a look at how those providers are called via CreateDefaultBuilder method. That will ultimately help us to know more about how the transformations work with appsettings.json.

What are Configuration Providers ?

There are different types of configuration providers, which are used for loading configurations from various sources.

When the framework builds IHostBuilder instance using CreateDefaultBuilder method, it loads the configurations using some of these providers.

Documentation Says…

CreateDefaultBuilder provides default configuration for the app in the following order:

  1. ChainedConfigurationProvider : Adds an existing IConfiguration as a source. In the default configuration case, adds the host configuration and setting it as the first source for the app configuration.
  2. appsettings.json using the JSON configuration provider.
  3. appsettings.Environment.json using the JSON configuration provider. For example, appsettings.Production.json and appsettings.Development.json.
  4. App secrets when the app runs in the Development environment.
  5. Environment variables using the Environment Variables configuration provider.
  6. Command-line arguments using the Command-line configuration provider.

Summary of how it works…

So, first, the appsettings.json is loaded. Then the values from appsettings.environment-name.json are loaded. It also does other things like loading values from app secrets, or applying command line inputs, but for the sake of simplicity, I have tried to keep focus on appsettings.json configurations.

I already have discussed in the previous blog post that .NET uses ASPNETCORE_ENVIRONMENT variable to identify the logical environment. So, if you have multiple appsettings.environment-name.json files, the actual file which overrides appsettings.json settings would be decided by the environment variable.

Let’s setup transformation

We now have enough information to get started on this task. Let’s create a .NET Core MVC web application in Visual Studio.

In appsettings.json file, add a new json property, Mode, which is set to “default“. Also add an array of JSON objects, MailFeature, a hypothetical mail feature which uses this configuration to set the email from addresses and subjects based on type of emails.

The file appsettings.json should have contents as shown below.

Then, let’s modify Index action from HomeController.cs to populate the view data as shown below.

Next, let’s modify Index.cshtml file to show the Mode value from the ViewData collection on the header, as shown in below code snippet.

Now, if you exapand the appsettings.json, it should already show you an environment specific JSON file with name appsettings.Development.json. Let’s add two more JSON files:

  • appsettings.Test.json
  • appsettings.Staging.json
  • appsettings.Production.json

NOTE: The CreateDefaultBuilder method performs case insensitive matching for finding environment specific configuration file. So, if the value of ASPNETCORE_ENVIRONMENT is test, it would still be correctly able to apply transformations from appsettings.Test.json.

Override a setting from JSON object

For overriding the default Mode from appsettings.json, add the Mode property to environment specific appsettings file and set it to the respective environment name, as shown in below snippet.

As you can see, you can create the JSON structure of the object and specify only those properties which you want to override in the environment specific files.

The disadvantage that one may say is – if a configuration property is nested at third level, then those levels need to be present in the environment specific JSON file.

Override a setting from JSON array

The obvious question that was bothering me was – how to handle JSON object arrays from appsettings.json ?

For example, we have a JSON array MailFeature. Let’s say we want to put environment name in subject if the environment is Development or Test, but obviously environment name should not be present in subject on Production.

Would I need to retype everything from the array ? If not, then how will it identify which subject belongs to which json object from the array?

So, just out of curiosity, I modified the appsettings.Development.json as shown in below snippet to understand how it works.

As I expected, the code transformed the subjects appropriately. This might have happend because the provider reads the values from array in the sequence in which it appears in the file.

So, yeah, like JSON objects, you can transform JSON arrays too. The only thing to take care is the item to be transformed should be present at the same array index in both the files.

Everything is (Key, Value) Pair

I tried to dig this further to see how the configuration is internally handled by .NET.

So, I put a breakpoint in Index action. When execution flow reached there, I used immediate window to execute configuration.AsEnumerable().ToList(). This returned below result:

So, internally everything is IEnumerable<KeyValuePair<string string>>. The key is formed by appending all previous JSON keys separated by colon (:) characther.

IConfiguration in .NET – Everything is key value pair internally

Efficient Transformation

If everything is key value pair, then the transformation files can also be written as shown below. It might not provide any advantage for JSON objects which are at topmost level.

For transforming only a few properties from either JSON arrays or deep nested objects, it might save some key strokes for you.

Verifying

For verifying, you can quickly run the sample from Visual Studio. Every time you run, change the ASPNETCORE_ENVIRONMENT value from launchSetting.json to any value from “Development”, “Test”, “Staging”, and “Production”. The home page should show the header text from the environment specific JSON file.

Transforming configurations from appsettings.json

So, we have seen how easy it is to setup the config transformations in .NET. You do not need any third party packages for setting it up. Further more, there are many possibilities.

For example, only if you wish, you can write your own code to create the IHostBuilder instance, and that code can decide how the transformation works. That custom code can use something else like secrets or key vault or any other configuration store to override the values from appsettings.json.

I hope you found this information useful. Let me know your thoughts.

Leave a Reply

This Post Has 2 Comments