Photo by Alexey Ruban on Unsplash

Configuration in ASP.NET Core Explained

A common consideration for working with an ASP.NET Core application is how to store and retrieve values in configuration settings, as well as how to change and update them as the application moves to higher environments. It’s common to need sensitive values like passwords, API keys, and database connection strings in order to call out to other services, and these settings must be stored separately from the application’s source code. To help manage this process, ASP.NET Core contains a set of configuration providers for retrieving and storing values, as well as a class to make complex settings available in the application as strongly-typed objects.

Prerequisites

I’ll assume you have some familiarity with ASP.NET Core applications, but this article will still stay at a beginner level. To build a copy of the example application and follow along, you will need:

  1. Docker Desktop running on your local machine. The version I’m using as of this writing is 19.03.12.
  2. Postman, or an API tool of your choice, is recommended for making calls to the API and inspecting the results.
  3. Lastly, to follow along with the examples, I’ve created a Github repo with a before and after branch. The following command will clone the repo:
$ git clone https://github.com/jsheridanwells/aspnetcore-config-example.git
$ git fetch origin before:before 
$ git fetch origin after:after

The boilerplate

Here are the important files we’ll be working with in this project:

  • Program.cs is the main file that scaffolds an ASP.NET Core application and creates both the application and the host environment for the application. In this project, you'll notice a method called .ConfigureAppConfiguration that is commented out. Later in this tutorial, we'll uncomment the method and play around with the directives in there.
  • Startup.cs defines all the top-level settings for the application including configuration, dependency in injection, and the middlewares used by the application. In this class, we'll define the entry point for the app's configuration.
  • Controllers/ConfigController.cs is the single controller in the project with a single method called GetConfig that will be modified to return the values in our settings so that we can inspect the configuration values that are available in the application.
  • Lastly, Dockerfile will be used to build the application in a container and experiment with passing in configuration values that way. Note that we won't discuss containerizing applications in this tutorial, but you won't need to know much Docker for this demo.
$ dotnet run

Loading configuration in Startup.cs

Best practice for loading configuration settings is to create a simple class to map the configuration values, then adding them in the Startup class.

using System;namespace AspNetCoreConfigExample
{
public class MyConfig
{
public Guid Id { get; set; }
public string Location { get; set; }
}
}
"MyConfig": {
"Id": "4c3c066c-928f-4de4-86b8-09365aed6a7c",
"Location": "from appSettings.json"
}
// Add configuration section here
var configs = Configuration.GetSection("MyConfig");
services.Configure<MyConfig>(configs);
private MyConfig _configs;
public ConfigController(IOptions<MyConfig> opts)
{
_configs = opts.Value;
}
[HttpGet]
public IActionResult GetConfig()
{
// 3. return the config to inspect it
var configs = _configs;
return Ok(new { Result = "config values: ", configs });
}
$ dotnet run
{
"id": "4c3c066c-928f-4de4-86b8-09365aed6a7c",
"location": "from appSettings.json"
}

The provider hierarchy

The default configuration setup for an ASP.NET Core app is hidden away in the Program class, in a method called .ConfigureWebHostDefaults. By default, the method checks for settings in a hierarchy of locations and if a matching configuration is found after a preceding one, settings from the latter are used.

  1. Any appsettings.{ ENVIRONMENT_NAME }.json files
  2. User secrets from the .NET User Secrets Manager
  3. Environment variables
  4. Command line arguments

appsettings.json

When we ran the application in the last step, the configuration values that were returned came from the ./appsettings.json file. This can be overridden with an appsettings.{ ENVIRONMENT NAME }.json file. Add a file at the root of the project called appsettings.Development.json and paste in the following:

{
"MyConfig": {
"Id": "6e20863b-ae31-4e6c-8711-00177586bec0",
"Location": "from appSettings.development.json"
}
}
{
"MyConfig": {
"Id": "bd304170-b899-42a9-9f9f-048e6e67a5dd",
"Location": "from appSettings.Staging.json"
}
}
$ export ASPNETCORE_ENVIRONMENT="Staging"
$ dotnet run --launch-profile "Staging"
> set ASPNETCORE_ENVIRONMENT="Staging"

User Secrets Manager

appsettings.json is okay for generic settings, but some other settings for development need to be stored separately from the source code. These could be API keys, passwords, settings for cloud infrastructure, or connections strings for remote databases. The .NET CLI provides a utility called the User Secrets Manager that can store and load values from a local development filesystem.

  1. The project will need a user secrets ID which can be any string. This is added to the .csproj file. For this project, there is already a GUID added:
<!--AspNetCoreConfigExample.csproj-->
<PropertyGroup>
<!-- ...-->
<UserSecretsId>fa9be5ec-53e4-4275-8941-99cf83d8c344</UserSecretsId>
</PropertyGroup>
$ dotnet user-secrets set MyConfig:Id fa3e83d5-27e2-4a02-ae75-ad3763985290
$ dotnet user-secrets set MyConfig:Location 'User Secrets Store'

Environment variables, command line arguments, and container commands

We can also set MyConfig:Id and MyConfig:Location as environment variables and they will take precedent over the user secrets settings.

$ export MyConfig__Id=52a8f62b-43fa-4da6-8a7e-7b788402aeed
$ export MyConfig__Location="Environment Variable"
> set MyConfig:Id=52a8f62b-43fa-4da6-8a7e-7b788402aeed
> set MyConfig:Location="Environment Variable"
$ dotnet run MyConfig:Id=be4209bc-8162-4c77-9064-8dd912b2a413 MyConfig:Location='command line'
ENV MyConfig__Id='73ce1157-c1b4-4d90-8669-2b33c86d7801'
ENV MyConfig__Location='from Dockerfile'
$ docker build -t config-app .
$ docker run -it -p 5000:5000 config-app
$ docker run -it -p 5000:5000 \
-e MyConfig__Id='2021b838-6876-44b9-b123-1f760dc98aaa' \
-e MyConfig__Location='from Docker CLI' \
config-app

Setting the configuration provider hierarchy

The default order of configuration providers that get called is logical for most situations, but ASP.NET Core also contains a scaffolding method for overriding the default order.

.ConfigureAppConfiguration((hostContext, config) =>
{
config.AddUserSecrets<MyConfig>();
config.AddJsonFile("appsettings.json");
})

Conclusion

In this project, we saw some of the configuration providers that are available in an ASP.NET Core application and how those settings can be moved around and concealed as the application is deployed to higher environments. This gives several convenient strategies for setting up the application for a variety of deployment types.

Further reading

I am a second-career software engineer currently working in the public sector.

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store