A Step by Step Guide for ASP.NET Core Configuration
Tags: aspnetcore, configuration, guide, aspnet
Published: 2021-08-19 09:37:33

If you are new to ASP.NET Core development, one of the first few things you will notice is that the old web.config or app.config files are no longer available in ASP.NET Core projects. Configuration in ASP.NET Core is performed using one or more Configuration Providers. There are configuration providers for reading configurations from almost anywhere such as files e.g. JSON, INI or XML, environment variables, Azure key vault, command-line arguments, etc. and many more sources. This tutorial is a step by step guide to show you how can you configure your application settings in various files such as JSON, INI or XML and how can you read those settings from your application code. I will also demonstrate how can you read application settings as custom .NET types (classes) and how can you use the built-in ASP.NET Core dependency injection to read your configuration settings in multiple classes, services or even projects available in your solution.

## Getting Started

Create an ASP.NET Core Web Application using Visual Studio 2019 Professional or Community edition. Provide project name and location and choose MVC Web Application from one of the available templates

![Create an ASP.NET Core MVC Web Application using Visual Studio 2019](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/smsxb0okm04c5x9s3z5z.png)

Build your project and press F4 to make sure the project is running in browser without any problem.

## Default Configuration

When we create ASP.NET Core web applications using the command line or Visual Studio, we will see a few files automatically generated for us and one of those files is the Program.cs file.
 
![Visual Studio 2019 Solution Explorer](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mejv7f70qlswgdq5hok5.png)

This file creates the host builder for us and you will also see a method [CreateDefaultBuilder](https://docs.microsoft.com/en-us/dotnet/api/microsoft.extensions.hosting.host.createdefaultbuilder) in this file as shown below.
```
public class Program
{
	public static void Main(string[] args)
	{
		CreateHostBuilder(args).Build().Run();
	}

	public static IHostBuilder CreateHostBuilder(string[] args) =>
		Host.CreateDefaultBuilder(args)
			.ConfigureWebHostDefaults(webBuilder =>
			{
				webBuilder.UseStartup<Startup>();
			});
}
```
The [CreateDefaultBuilder](https://docs.microsoft.com/en-us/dotnet/api/microsoft.extensions.hosting.host.createdefaultbuilder) method configures the default configurations for our application in the following order:

1. If there are any host configurations and settings, they will be added first using [ChainedConfigurationProvider](https://docs.microsoft.com/en-us/dotnet/api/microsoft.extensions.configuration.chainedconfigurationsource).
2. Next, it will configure our project settings defined in our project appsettings.json file using the [JSON configuration provider](https://docs.microsoft.com/en-us/aspnet/core/fundamentals/configuration/?view=aspnetcore-3.1#file-configuration-provider).
3. If we have environment specific application settings in appsettings.Development.json or appsettings.Production.json files then they will be configured.
4. If we have any development related [application secrets](https://docs.microsoft.com/en-us/aspnet/core/security/app-secrets?view=aspnetcore-3.1) configured, they will be loaded next.
5. Environment variables will be loaded next using [Environment variables configuration provider](https://docs.microsoft.com/en-us/aspnet/core/fundamentals/configuration/?view=aspnetcore-3.1#evcp).
6. In the end, Command line arguments will load using the [Command line configuration provider](https://docs.microsoft.com/en-us/aspnet/core/fundamentals/configuration/?view=aspnetcore-3.1#command-line).

Please keep in mind that the Configuration providers added later in the above list will override previous key settings loaded by any previous configuration provider. For example, if you have configured a setting in both appsettings.json and the environment, the environment value will be used. Using the default configuration providers, the [Command-line configuration provider](https://docs.microsoft.com/en-us/aspnet/core/fundamentals/configuration/?view=aspnetcore-3.1#clcp) overrides all other providers as they are added at the end of the above list.

For more information on CreateDefaultBuilder, see [Default builder settings](https://docs.microsoft.com/en-us/aspnet/core/fundamentals/host/generic-host?view=aspnetcore-3.1#default-builder-settings).

As this tutorial is all about saving and reading settings from the configuration files, so I will not discuss other non-file related configuration providers such as environment, command line, etc.

## Custom Application Configurations

Now we need to decide what application settings we want to configure and for this tutorial, I am saving the following configuration settings in my project appsettings.json file.
```
{
  "MyApplication": {
    "Name": "Demo Configuration Application",
    "Version": "1.0",
    "DefaultUrl": "http://www.exampledemoapp.com",
    "Support": {
      "Email": "support@demoapp.com",
      "Phone": "123456789"
    }    
  },
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft": "Warning",
      "Microsoft.Hosting.Lifetime": "Information"
    }
  },
  "AllowedHosts": "\*"
}
```
I am adding similar settings in the appsettings.Development.json file with some different values related to the development environment.
```
{
  "MyApplication": {
    "Name": "Demo Configuration Application (Development)",
    "Version": "1.1",
    "DefaultUrl": "http://localhost:3030",
    "Support": {
      "Email": "support@demoapp.com",
      "Phone": "123456789"
    }
  },
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft": "Warning",
      "Microsoft.Hosting.Lifetime": "Information"
    }
  }
}
```
We need to read these settings in our application code so open the HomeController.cs file and declare a private field of type IConfiguration. Inject the IConfiguration parameter in the constructor of HomeController and make sure the private field Configuration is initialized within the constructor.
```
using Microsoft.Extensions.Configuration;

private readonly IConfiguration Configuration;

public HomeController(IConfiguration configuration)
{
    Configuration = configuration;
}
```
ASP.NET Core will automatically inject and initialize our field at runtime and will provide us access to all configuration settings available within our application. To read configuration settings in the code, we need to use the above Configuration variable and need to pass the application setting key name to the indexer. If we have a nested setting then we can separate the parent setting and child setting using a colon operator as we did in the case of **“MyApplication:Support:Email”** below.
```
public IActionResult Index()
{
	var appName = Configuration["MyApplication:Name"];
	var appVersion = Configuration["MyApplication:Version"];
	var appUrl = Configuration["MyApplication:DefaultUrl"];
	var supportEmail = Configuration["MyApplication:Support:Email"];
	var supportPhone = Configuration["MyApplication:Support:Phone"];

	ViewBag.ApplicationName = appName;
	ViewBag.ApplicationVersion = appVersion;
	ViewBag.ApplicationUrl = appUrl;
	ViewBag.SupportEmail = supportEmail;
	ViewBag.SupportPhone = supportPhone;

	return View();
}
```
I have passed the settings to view using the ViewBag and then displaying the settings in the view using the same ViewBag properties.
```
<div>
	<h4>
		@ViewBag.ApplicationName
	</h4>
	<h5>
		Version: @ViewBag.ApplicationVersion
	</h5>
	<br />
	<table class="table table-bordered table-striped" style="width:90%;">
		<tr>
			<td><b>Default URL</b></td>
			<td>@ViewBag.ApplicationUrl</td>
		</tr>
		<tr>
			<td><b>Support Email</b></td>
			<td>@ViewBag.SupportEmail</td>
		</tr>
		<tr>
			<td><b>Support Phone</b></td>
			<td>@ViewBag.SupportPhone</td>
		</tr>
	</table>
</div>
```
If you will run the project now, you will see the following output in the browser:

![Read ASP.NET Core Settings](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/x8d3trgb6nqhhocej5yt.png)

One thing you may have noticed above that the application is reading the settings from the appsettings.Development.json file and this is because by default the current environment of your application is set as Development.

![Current Environment in ASP.NET Core Apps](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ciy1m5as4pwemkryt932.png)

The default [JsonConfigurationProvider](https://docs.microsoft.com/en-us/dotnet/api/microsoft.extensions.configuration.json.jsonconfigurationprovider) loads _appsettings.json first and then appsettings.**Environment**.json will be loaded and will override the settings defined in appsetttings.json file. For example, by default:_

![Read ASP.NET Core Settings](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/x8d3trgb6nqhhocej5yt.png)

- In development, _appsettings_.**_Development_**._json_ configuration overwrites values found in _appsettings.json_.
- In production, _appsettings_.**_Production_**._json_ configuration overwrites values found in _appsettings.json_. For example, when deploying the app to Azure.

If you will change, your environment from “Development” to “Production” above and will run your application you will see that application will stop reading settings from the appsettings.Development.json file and as we don’t have appsettings.Production.json file in our project so everything defined in appsettings.json file is read and displayed.

![Reading Production Environment settings in ASP.NET Core](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/b507fogairpjuzwr8ej3.png)

## Reading Application Settings using Options pattern

If you are building a large application with a lot of configurations or you have many hierarchical settings to read then reading all settings one by one is not the recommended approach. There are also chances of misspelling a setting key in the code, which could lead you to a difficult to track bug. The preferred way to read configuration values is by using the [options pattern](https://docs.microsoft.com/en-us/aspnet/core/fundamentals/configuration/options?view=aspnetcore-3.1). The options pattern uses classes to provide strongly typed access to groups of related settings. To read the above configuration values in a strongly typed manner, we need to create strongly-typed C# classes as shown below:
```
public class ApplicationOptions
{
	public const string MyApplication = "MyApplication";

	public string Name { get; set; }
	public decimal Version { get; set; }
	public string DefaultUrl { get; set; }

	public SupportOptions Support { get; set; }
}

public class SupportOptions
{
	public const string Support = "Support";

	public string Email { get; set; }
	public string Phone { get; set; }
}
```
We need to keep the following points in mind when we are creating strongly typed classes to read configurations using options pattern.

- A class must be **non-abstract** with a public parameterless constructor.
- All **public** read-write properties of the type are bound.
- Fields are **not** bound e.g., **MyApplication** and **Support** const fields will not be bound

To bind our settings we need to call [**ConfigurationBinder.Bind**](https://docs.microsoft.com/en-us/dotnet/api/microsoft.extensions.configuration.configurationbinder.bind) method and need to bind **ApplicationOptions** class object with the **MyApplication** section as follows:
```
public IActionResult Index()
{
	var applicationOptions = new ApplicationOptions();
	Configuration.GetSection(ApplicationOptions.MyApplication).Bind(applicationOptions);

	ViewBag.ApplicationName = applicationOptions.Name;
	ViewBag.ApplicationVersion = applicationOptions.Version;
	ViewBag.ApplicationUrl = applicationOptions.DefaultUrl;

	ViewBag.SupportEmail = applicationOptions.Support.Email;
	ViewBag.SupportPhone = applicationOptions.Support.Phone;

	return View();
}
```
In the preceding code, we have called the **Bind** method to bind the configuration section. There is another convenient method **Get<T>** which can be used to read the configuration section as a specified Type. Here is how you can use the Get<T> method to read and bind configuration with strongly typed classes:
```
public IActionResult Index()
{
	var applicationOptions = Configuration.GetSection(ApplicationOptions.MyApplication).Get<ApplicationOptions>();

	ViewBag.ApplicationName = applicationOptions.Name;
	ViewBag.ApplicationVersion = applicationOptions.Version;
	ViewBag.ApplicationUrl = applicationOptions.DefaultUrl;

	ViewBag.SupportEmail = applicationOptions.Support.Email;
	ViewBag.SupportPhone = applicationOptions.Support.Phone;

	return View();
}
```
In all my examples above, I am reading application settings in a standard MVC controller. If you have a large application, you may want to read the configurations in multiple controllers and classes throughout the application. It is not recommended to bind the configuration section in each one of those classes and write a lot of duplicate code. A better approach is to bind the configuration section inside the **ConfigureServices** method of **Startup.cs** file using the options pattern and then add it to the dependency injection service container.
```
public class Startup
{
	public Startup(IConfiguration configuration)
	{
		Configuration = configuration;
	}

	public IConfiguration Configuration { get; }

	public void ConfigureServices(IServiceCollection services)
	{
		services.Configure<ApplicationOptions>(Configuration.GetSection(ApplicationOptions.MyApplication));

		services.AddControllersWithViews();
	}
}
```
Once our configurations are added to the dependency injection container, we can inject the **ApplicationOptions** object using the **IOptions** interface in any controller or class where we want to read the configuration settings. The following code shows how can we inject ApplicationOptions in HomeController and read our settings from the appsettings.json file.
```
public class HomeController : Controller
{
	private readonly ApplicationOptions _options;

	public HomeController(IOptions<ApplicationOptions> options)
	{
		_options = options.Value;
	}

	public IActionResult Index()
	{
		ViewBag.ApplicationName = _options.Name;
		ViewBag.ApplicationVersion = _options.Version;
		ViewBag.ApplicationUrl = _options.DefaultUrl;

		ViewBag.SupportEmail = _options.Support.Email;
		ViewBag.SupportPhone = _options.Support.Phone;

		return View();
	}
}
```
## Using XML Configuration Provider in ASP.NET Core

So far, in this tutorial, we are using the default [JsonConfigurationProvider](https://docs.microsoft.com/en-us/dotnet/api/microsoft.extensions.configuration.json.jsonconfigurationprovider) which reads settings from the appsettings.json file. If you don’t like JSON and want to store and read settings from an XML file then you have to use the [XmlConfigurationProvider](https://docs.microsoft.com/en-us/dotnet/api/microsoft.extensions.configuration.xml.xmlconfigurationprovider) that loads configuration from XML file key-value pairs at runtime. Let’s create an appsettings.xml file and add the similar settings in the newly created XML file.
```
<?xml version="1.0" encoding="utf-8" ?>
<MyApplication>
  <Name>Demo Configuration Application</Name>
  <Version>1.0</Version>
  <DefaultUrl>http://www.exampledemoapp.com</DefaultUrl>
  <Support>
    <Email>support@demoapp.com</Email>
    <Phone>123456789</Phone>
  </Support>
</MyApplication>
```
The following code clears all the configuration providers and adds several configuration providers. I am using the **AddXmlFile** method to add both appsettings.xml and any environment specific file such as appsettings.Development.xml and appsettings.Production.xml. In the end, I am adding Environment Variables and Command-line configuration providers.
```
public class Program
{
	public static void Main(string[] args)
	{
		CreateHostBuilder(args).Build().Run();
	}

	public static IHostBuilder CreateHostBuilder(string[] args) =>
		Host.CreateDefaultBuilder(args)
			.ConfigureAppConfiguration((hostingContext, config) =>
			{
				config.Sources.Clear();

				var env = hostingContext.HostingEnvironment;

				config.AddXmlFile("appsettings.xml", optional: true, reloadOnChange: true)
					  .AddXmlFile($"appsettings.{env.EnvironmentName}.xml",
									 optional: true, reloadOnChange: true);

				config.AddEnvironmentVariables();

				if (args != null)
				{
					config.AddCommandLine(args);
				}
			})
			.ConfigureWebHostDefaults(webBuilder =>
			{
				webBuilder.UseStartup<Startup>();
			});
}
```
The following code shows how we can read the XML settings in our C# code using the same IConfiguration object we used at the start of this tutorial.
```
public class HomeController : Controller
{
	private readonly IConfiguration Configuration;

	public HomeController(IConfiguration configuration)
	{
		Configuration = configuration;
	}

	public IActionResult Index()
	{
		var appName = Configuration["Name"];
		var appVersion = Configuration["Version"];
		var appUrl = Configuration["DefaultUrl"];
		var supportEmail = Configuration["Support:Email"];
		var supportPhone = Configuration["Support:Phone"];

		ViewBag.ApplicationName = appName;
		ViewBag.ApplicationVersion = appVersion;
		ViewBag.ApplicationUrl = appUrl;
		ViewBag.SupportEmail = supportEmail;
		ViewBag.SupportPhone = supportPhone;

		return View();
	}         
}
```
If you will run the application now, you will see similar output as we saw when we were using JSON configuration files.

![Read ASP.NET Core Settings](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/x8d3trgb6nqhhocej5yt.png)

## Using INI Configuration Provider in ASP.NET Core

If you are integrating with a legacy system, where settings are available in the form of INI files then you have to use [IniConfigurationProvider](https://docs.microsoft.com/en-us/dotnet/api/microsoft.extensions.configuration.ini.iniconfigurationprovider) that loads configuration from INI file key-value pairs at runtime. Let’s create an appsettings.ini file and add similar settings in the newly created INI file.
```
[MyApplication]
Name="Demo Configuration Application"
Version=1.0
DefaultUrl="http://www.exampledemoapp.com"
  
[MyApplication:Support]
Email="support@demoapp.com"
Phone="123456789"
```
The following code is very much similar to the above code where we were reading settings from an XML based configuration file. We need to clear all the configuration providers and adds INI files along with other configuration providers. We need to use the **AddIniFile** method to add both appsettings.ini and any environment specific files such as appsettings.Development.ini and appsettings.Production.ini. In the end, I am adding Environment Variables and Command-line configuration providers.
```
public class Program
{
	public static void Main(string[] args)
	{
		CreateHostBuilder(args).Build().Run();
	}

	public static IHostBuilder CreateHostBuilder(string[] args) =>
		Host.CreateDefaultBuilder(args)
			.ConfigureAppConfiguration((hostingContext, config) =>
			{
				config.Sources.Clear();

				var env = hostingContext.HostingEnvironment;

				config.AddIniFile("appsettings.ini", optional: true, reloadOnChange: true)
				  .AddIniFile($"appsettings.{env.EnvironmentName}.ini",
								 optional: true, reloadOnChange: true);

				config.AddEnvironmentVariables();

				if (args != null)
				{
					config.AddCommandLine(args);
				}
			})
			.ConfigureWebHostDefaults(webBuilder =>
			{
				webBuilder.UseStartup<Startup>();
			});
}
```
The following code shows how we can read the INI settings in our C# code using the same IConfiguration object we used at the start of this tutorial.
```
public class HomeController : Controller
{
	private readonly IConfiguration Configuration;

	public HomeController(IConfiguration configuration)
	{
		Configuration = configuration;
	}

	public IActionResult Index()
	{
		var appName = Configuration["MyApplication:Name"];
		var appVersion = Configuration["MyApplication:Version"];
		var appUrl = Configuration["MyApplication:DefaultUrl"];
		var supportEmail = Configuration["MyApplication:Support:Email"];
		var supportPhone = Configuration["MyApplication:Support:Phone"];

		ViewBag.ApplicationName = appName;
		ViewBag.ApplicationVersion = appVersion;
		ViewBag.ApplicationUrl = appUrl;
		ViewBag.SupportEmail = supportEmail;
		ViewBag.SupportPhone = supportPhone;

		return View();
	}         
}
```
## Summary

ASP.NET Core provides powerful and flexible options that support several different ways to work with configurations such as file-based configurations, in-memory configurations, environment variables, or even command-line arguments. This also supports the options model so that we can strongly inject settings to our application. We can also create a [custom configuration provider](https://docs.microsoft.com/en-us/aspnet/core/fundamentals/configuration/?view=aspnetcore-3.1#custom-configuration-provider) that reads configuration key-value pairs from a database using [Entity Framework (EF)](https://docs.microsoft.com/en-us/ef/core/).