Chapter 2: Customizing App Configuration
This second chapter is about application configuration, how to use it, and how to customize the ASP.NET configuration to employ different ways to configure your app. Perhaps you already have an existing Extensible Markup Language (XML) configuration or want to share a YAML Ain't Markup Language (YAML) configuration file over different kinds of applications. Sometimes, it also makes sense to read configuration values out of a database.
In this chapter, we will be covering the following topics:
- Configuring the configuration
- Using typed configurations
- Configuration using Initialization (INI) files
- Configuration providers
The topics in this chapter refer to the hosting layer of the ASP.NET Core architecture:

Figure 2.1 – ASP.NET Core architecture
Technical requirements
To follow the descriptions in this chapter, you will need to create an ASP.NET Core Model-View-Controller (MVC) application. Open your console, shell, or Bash terminal, and change to your working directory. Use the following command to create a new MVC application:
dotnet new mvc -n ConfigureSample -o ConfigureSample
Now, open the project in Visual Studio by double-clicking the project file or, in Visual Studio Code (VS Code), by typing the following command in the already open console:
cd ConfigureSample code .
All of the code samples in this chapter can be found in the GitHub repository for this book at https://github.com/PacktPublishing/Customizing-ASP.NET-Core-6.0-Second-Edition/tree/main/Chapter02.
Configuring the configuration
Let's start by looking at how to configure your various configuration options.
Since ASP.NET Core 2.0, the configuration is hidden in the default configuration of WebHostBuilder
and is no longer part of Startup.cs
. This helps to keep the startup clean and simple.
In ASP.NET Core 3.1 up to ASP.NET Core 5.0, the code looks like this:
// ASP.NET Core 3.0 and later public class Program { public static void Main(string[] args) { CreateWebHostBuilder(args).Build().Run(); } public static IHostBuilder CreateHostBuilder(string[] args) => Host.CreateDefaultBuilder(args) .ConfigureWebHostDefaults(webBuilder => { webBuilder.UseStartup<Startup>(); } }
In ASP.NET Core 6.0, Microsoft introduced the minimal application programming interface (API) approach that simplifies the configuration a lot. This doesn't use Startup
and adds all the configuration in the Program.cs
file. Let's see how it looks here:
Var builder = WebApplication.CreateBuilder(args); // Add services to the container. builder.Services.AddControllersWithViews(); var app = builder.Build(); // The rest of the file isn't relevant for this chapter
Fortunately, in both versions, you are also able to override the default settings to customize the configuration in the way you need it. In both versions, we extend IWebHostBuilder
with the ConfigureAppConfiguration()
method where the magic will happen.
This is what the configuration looks like in ASP.NET Core 3.1 and ASP.NET Core 5.0:
Host.CreateDefaultBuilder(args) .ConfigureWebHostDefaults(webBuilder => { webBuilder .ConfigureAppConfiguration((builderContext, config) => { // configure configuration here }) .UseStartup<Startup>(); });
This is what the code looks like when using the minimal API approach. You also can use ConfigureAppConfiguration
to configure the app configuration:
builder.WebHost.ConfigureAppConfiguration((builderContext, config) => { // configure configuration here });
But there is a much simpler approach, by accessing the Configuration
property of the builder:
builder.Configuration.AddJsonFile( "appsettings.json", optional: false, reloadOnChange: true);
When you create a new ASP.NET Core project, you will already have appsettings.json
and appsettings.Development.json
configured. You can, and should, use these configuration files to configure your app; this is the preconfigured way, and most ASP.NET Core developers will look for an appsettings.json
file to configure the application. This is absolutely fine and works pretty well.
The following code snippet shows the encapsulated default configuration to read the appsettings.json
files:
var env = builder.Environment; builder.Configuration.SetBasePath(env.ContentRootPath); builder.Configuration.AddJsonFile( "appsettings.json", optional: false, reloadOnChange: true); builder.Configuration.AddJsonFile( $"appsettings.{env.EnvironmentName}.json", optional: true, reloadOnChange: true); builder.Configuration.AddEnvironmentVariables();
This configuration also sets the base path of the application and adds the configuration via environment variables.
Whenever you customize the application configuration, you should add the configuration via environment variables as a final step, using the AddEnvironmentVariables()
method. The order of the configuration matters and the configuration providers that you add later on will override the configurations added previously. Be sure that the environment variables always override the configurations that are set via a file. This way, you also ensure that the configuration of your application on an Azure App Service will be passed to the application as environment variables.
IConfigurationBuilder
has a lot of extension methods to add more configurations, such as XML or INI configuration files and in-memory configurations. You can find additional configuration providers built by the community to read in YAML files, database values, and a lot more. In an upcoming section, we will see how to read INI files. First, we will look at using typed configurations.
Using typed configurations
Before trying to read INI files, it makes sense for you to see how to use typed configurations instead of reading the configuration via IConfiguration
, key by key.
To read a typed configuration, you need to define the type to configure. I usually create a class called AppSettings
, as follows:
namespace ConfigureSample; public class AppSettings { public int Foo { get; set; } public string Bar { get; set; } }
This is a simple Plain Old CLR Object (POCO) class that will only contain the application setting values, as illustrated in the following code snippet. These classes can then be filled with specific configuration sections inside the ConfigureServices
method in Startup.cs
until ASP.NET Core 5.0:
services.Configure<AppSettings> (Configuration.GetSection("AppSettings"));
Using the minimal API approach, you need to configure the AppSettings
class, like this:
builder.Services.Configure<AppSettings>( builder.Configuration.GetSection("AppSettings"));
This way, the typed configuration also gets registered as a service in the dependency injection (DI) container and can be used everywhere in the application. You are able to create different configuration types for each configuration section. In most cases, one section should be fine, but sometimes it makes sense to divide the settings into different sections. The next snippet shows how to use the configuration in an MVC controller:
using Microsoft.Extensions.Options; // ... public class HomeController : Controller { private readonly AppSettings _options; public HomeController(IOptions<AppSettings> options) { _options = options.Value; } public IActionResult Index() { ViewData["Message"] = _options.Bar; return View(); }
IOptions<AppSettings>
is a wrapper around our AppSettings
type, and the Value
property contains the actual instance of AppSettings
, including the values from the configuration file.
To try reading the settings in, the appsettings.json
file needs to have the AppSettings
section configured, otherwise the values are null or not set. Let's now add the section to the appsettings.json
file, as follows:
{ "Logging": { "LogLevel": { "Default": "Warning" } }, "AllowedHosts": "*", "AppSettings": { "Foo": 123, "Bar": "Bar" } }
Next, we'll examine how INI files can be used for configuration.
Configuration using INI files
To also use INI files to configure the application, you will need to add the INI configuration inside the ConfigureAppConfiguration()
method in Program.cs
, as follows:
builder.Configuration.AddIniFile( "appsettings.ini", optional: false, reloadOnChange: true); builder.Configuration.AddJsonFile( $"appsettings.{env.EnvironmentName}.ini", optional: true, reloadOnChange: true);
This code loads the INI files the same way as the JavaScript Object Notation (JSON) configuration files. The first line is a required configuration, and the second line is an optional configuration depending on the current runtime environment.
The INI file could look like this:
[AppSettings] Bar="FooBar"
As you can see, this file contains a section called AppSettings
and a property called Bar
.
Earlier, we said that the order of the configuration matters. If you add the two lines to configure via INI files after the configuration via JSON files, the INI files will override the settings from the JSON files. The Bar
property gets overridden with "FooBar"
and the Foo
property stays the same because it will not be overridden. Also, the values out of the INI file will be available via the typed configuration created previously.
Every other configuration provider will work the same way. Let's now see how a configuration provider will look.
Configuration providers
A configuration provider is an implementation of IConfigurationProvider
that is created by a configuration source, which is an implementation of IConfigurationSource
. The configuration provider then reads the data from somewhere and provides it via Dictionary
.
To add a custom or third-party configuration provider to ASP.NET Core, you will need to call the Add
method on ConfigurationBuilder
and insert the configuration source. This is just an example:
// add new configuration source builder.Configuration.Add(new MyCustomConfigurationSource { SourceConfig = //configure whatever source Optional = false, ReloadOnChange = true });
Usually, you would create an extension method to add the configuration source more easily, as illustrated here:
builder.Configuration.AddMyCustomSource("source", optional: false, reloadOnChange: true);
A really detailed concrete example about how to create a custom configuration provider has been written by Andrew Lock. You can find this in the Further reading section of this chapter.
Summary
In most cases, you will not need to add a different configuration provider or create your own configuration provider, but it's good to know how to change it, just in case. Also, using a typed configuration is a nice way to read and provide the settings. In classic ASP.NET, we used a manually created façade to read the application settings in a typed manner. Now, this is automatically done by just providing a type. This type will be automatically instantiated, filled, and provided, via DI.
To learn more about customizing DI in ASP.NET Core 6.0, let's have a look at the next chapter.
Further reading
You can refer to the following source for more information:
- Creating a custom ConfigurationProvider in ASP.NET Core to parse YAML, Andrew Lock: https://andrewlock.net/creating-a-custom-iconfigurationprovider-in-asp-net-core-to-parse-yaml/