The .NET configuration system provides a standardized way of expressing and reading configuration values.
NuGet Package: Microsoft.Extensions.Configuration
Source Code: https://github.com/dotnet/runtime/tree/main/src/libraries
Hierarchical Configuration Values
Hierarchical configuration values are supported out-of-the-box. For example here the logging configuration:
{
"Logging": {
"Console": {
"FormatterOptions": {
"TimestampFormat": "[HH:mm:ss] "
}
}
}
}
If a configuration provider doesn’t support a hierarchical representation but just flat strings (e.g. the command line, environment variables), hierarchy levels are separated with a :
Logging:Console:FormatterOptions:TimestampFormat
Environment variables don’t support :
as hierarchy separator - they use __
(double underscore) instead:
Logging__Console__FormatterOptions__TimestampFormat
Getting a Value
To get a configuration value, you need an instance of IConfiguration
(for how to get this, see below).
With this, you can call:
IConfiguration config = ...
int value = config.GetValue<int>("Parent:FavoriteNumber");
Note: GetValue<T>()
is an extension method from the Microsoft.Extensions.Configuration.Binder NuGet package.
Alternatively you can bind whole configuration sections (see below) to objects.
For example, with this configuration:
{
"Settings": {
"KeyOne": 1,
"KeyTwo": true,
"KeyThree": {
"Message": "Oh, that's nice..."
}
}
}
And these classes:
public class Settings
{
public int KeyOne { get; set; }
public bool KeyTwo { get; set; }
public NestedSettings KeyThree { get; set; }
}
public class NestedSettings
{
public string Message { get; set; }
}
You can call:
IConfiguration config = ...
Settings settings = config.GetRequiredSection("Settings").Get<Settings>();
Central Interfaces
There are three central interface for the configuration system:
IConfiguration
: Represents a set of key/value configuration properties.IConfigurationRoot
: Represents the root of anIConfiguration
hierarchy.IConfigurationSection
: Represents a section of configuration values.
Both IConfigurationRoot
and IConfigurationSection
inherit from IConfiguration
.
Conceptually both IConfigurationRoot
and IConfigurationSection
represent a configuration hierarchy.
Configuration Sections
Configuration sections allow you to get a whole subtree (sub hierarchy) of the configuration hierarchy.
To obtain a configuration section use this extension method:
IConfigurationSection GetRequiredSection(this IConfiguration configuration, string key)
For example, given this configuration:
{
"Logging": {
"Console": {
"FormatterOptions": {
"TimestampFormat": "[HH:mm:ss] "
}
}
}
}
Calling configurationRoot.GetRequiredSection("Logging")
gives you (conceptually):
{
"Console": {
"FormatterOptions": {
"TimestampFormat": "[HH:mm:ss] "
}
}
}
Accessing the Configurations via Generic Host
If you’re using a Generic Host application, you have several possibilities to get access to the configuration system:
-
In
IHostBuilder
viaHostBuilderContext.Configuration
(HostBuilderContext
can be injected as parameter in the delegates registered inIHostBuilder
) -
Via dependency injection (as
IConfiguration
) -
Via Options. They can be registered in the dependency injection system like so:
hostBuilder.ConfigureServices((context, services) => { services.Configure<MyOptions>(context.Configuration.GetSection("MyOptions")); });
And can then be injected in a constructor like so:
public ExampleService(IOptions<MyOptions> options) { }
Manual Creation
If you don’t use a Generic Host application, you can manually create the configuration system like so:
IConfiguration config = new ConfigurationBuilder()
.AddJsonFile("appsettings.json")
.AddEnvironmentVariables()
.Build();
Configuration Providers
Configuration Providers define where configuration values are read from.
They’re registered in the IConfigurationBuilder
like so:
configurationBuilder.AddJsonFile("appsettings.json");
configurationBuilder.AddEnvironmentVariables();
With IHostBuilder
, providers are registered with these methods:
// host configuration
ConfigureHostConfiguration(Action<IConfigurationBuilder> configureDelegate);
// application configuration
ConfigureAppConfiguration(Action<HostBuilderContext, IConfigurationBuilder> configureDelegate);
Note: The order in which the providers are registers matters! If the same configuration key is provided by multiple providers, the provider that was added last is used.
.NET comes with several configuration providers built-in. Here a few select ones.
In-Memory Provider
configurationBuilder.AddInMemoryCollection(
new Dictionary<string, string>
{
["SecretKey"] = "Dictionary MyKey Value",
["TransientFaultHandlingOptions:Enabled"] = bool.TrueString,
["TransientFaultHandlingOptions:AutoRetryDelay"] = "00:00:07",
["Logging:LogLevel:Default"] = "Warning"
}
);
JSON File Provider
hostBuilder.ConfigureAppConfiguration((hostBuilderContext, configurationBuilder) =>
{
IHostEnvironment env = hostBuilderContext.HostingEnvironment;
configurationBuilder
.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
.AddJsonFile($"appsettings.{env.EnvironmentName}.json", true, true);
});
Command Line Provider
configurationBuilder.AddCommandLine(args);
Configuration values can be set with various patterns - for example like this:
--Parent:FavoriteNumber 42
Environment Variables Provider
Provides configuration values via environment variables.
By default, the variables do not require a prefix. However, you can specify that only variables with a certain prefix are to be used:
configurationBuilder.AddEnvironmentVariables(prefix: "CustomPrefix_");
For example, to set the TimestampFormat
for the console logger via environment variable, use this:
set Logging__Console__FormatterOptions__TimestampFormat="[HH:mm:ss] "