Configuration in .NET

Configuration in .NET is performed using one or more configuration providers. Configuration providers read configuration data from key-value pairs using a variety of configuration sources:

  • Settings files, such as appsettings.json
  • Environment variables
  • Azure Key Vault
  • Azure App Configuration
  • Command-line arguments
  • Custom providers, installed or created
  • Directory files
  • In-memory .NET objects
  • Third-party providers

Note

For information about configuring the .NET runtime itself, see .NET Runtime configuration settings.

Concepts and abstractions

Given one or more configuration sources, the IConfiguration type provides a unified view of the configuration data. Configuration is read-only, and the configuration pattern is not designed to be programmatically writable. The IConfiguration interface is a single representation of all the configuration sources, as shown in the following diagram:

The `IConfiguration` interface is a single representation of all the configuration sources.

Configure console apps

.NET console applications created using the dotnet new command template or Visual Studio by default do not expose configuration capabilities. To add configuration in a new .NET console application, add a package reference to Microsoft.Extensions.Hosting. Modify the Program.cs file to match the following code:

using Microsoft.Extensions.Hosting;

using IHost host = Host.CreateDefaultBuilder(args).Build();

// Application code should start here.

await host.RunAsync();

The Host.CreateDefaultBuilder(String[]) method provides default configuration for the app in the following order:

  1. ChainedConfigurationProvider : Adds an existing IConfiguration as a source.
  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.

Configuration providers that are added later override previous key settings. For example, if SomeKey is set in both appsettings.json and the environment, the environment value is used. Using the default configuration providers, the Command-line configuration provider overrides all other providers.

Binding

One of the key advantages of using the .NET configuration abstractions is the ability to bind configuration values to instances of .NET objects. For example, the JSON configuration provider can be used to map appsettings.json files to .NET objects and is used with dependency injection. This enables the options pattern, which uses classes to provide strongly typed access to groups of related settings. .NET configuration provides various abstractions. Consider the following interfaces:

These abstractions are agnostic to their underlying configuration provider (IConfigurationProvider). In other words, you can use an IConfiguration instance to access any configuration value from multiple providers.

The binder can use different approaches to process configuration values:​

  • Direct deserialization (using built-in converters) for primitive types​.
  • The TypeConverter for a complex type when the type has one​.
  • Reflection for a complex type that has properties.

Note

The binder has a few limitations:

  • Properties are ignored if they have private setters or their type can't be converted.
  • Properties without corresponding configuration keys are ignored.

Binding hierarchies

Configuration values can contain hierarchical data. Hierarchical objects are represented with the use of the : delimiter in the configuration keys. To access a configuration value, use the : character to delimit a hierarchy. For example, consider the following configuration values:

{
  "Parent": {
    "FavoriteNumber": 7,
    "Child": {
      "Name": "Example",
      "GrandChild": {
        "Age": 3
      }
    }
  }
}

The following table represents example keys and their corresponding values for the preceding example JSON:

Key Value
"Parent:FavoriteNumber" 7
"Parent:Child:Name" "Example"
"Parent:Child:GrandChild:Age" 3

Basic example

To access configuration values in their basic form, without the assistance of the generic host approach, use the ConfigurationBuilder type directly.

Tip

The System.Configuration.ConfigurationBuilder type is different to the Microsoft.Extensions.Configuration.ConfigurationBuilder type. All of this content is specific to the Microsoft.Extensions.* NuGet packages and namespaces.

Consider the following C# project:

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net6.0</TargetFramework>
    <Nullable>enable</Nullable>
    <ImplicitUsings>true</ImplicitUsings>
  </PropertyGroup>

  <ItemGroup>
    <Content Include="appsettings.json">
      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
    </Content>
  </ItemGroup>

  <ItemGroup>
    <PackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="6.0.0" />
    <PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="6.0.0" />
    <PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="6.0.0" />
  </ItemGroup>

</Project>

The preceding project file references several configuration NuGet packages:

Consider an example appsettings.json file:

{
    "Settings": {
        "KeyOne": 1,
        "KeyTwo": true,
        "KeyThree": {
            "Message": "Oh, that's nice...",
            "SupportedVersions": {
                "v1": "1.0.0",
                "v3": "3.0.7"
            }
        },
        "IPAddressRange": [
            "46.36.198.121",
            "46.36.198.122",
            "46.36.198.123",
            "46.36.198.124",
            "46.36.198.125"
        ]
    }
}

Now, given this JSON file here is an example consumption pattern using the configuration builder directly:

using Microsoft.Extensions.Configuration;

// Build a config object, using env vars and JSON providers.
IConfiguration config = new ConfigurationBuilder()
    .AddJsonFile("appsettings.json")
    .AddEnvironmentVariables()
    .Build();

// Get values from the config given their key and their target type.
Settings settings = config.GetRequiredSection("Settings").Get<Settings>();

// Write the values to the console.
Console.WriteLine($"KeyOne = {settings.KeyOne}");
Console.WriteLine($"KeyTwo = {settings.KeyTwo}");
Console.WriteLine($"KeyThree:Message = {settings.KeyThree.Message}");

// Application code which might rely on the config could start here.

// This will output the following:
//   KeyOne = 1
//   KeyTwo = True
//   KeyThree:Message = Oh, that's nice...

The preceding C# code:

  • Instantiates a ConfigurationBuilder.
  • Adds the "appsettings.json" file to be recognized by the JSON configuration provider.
  • Adds environment variables as being recognized by the Environment Variable configuration provider.
  • Gets the required "Settings" section and the corresponding Settings instance by using the config instance.

The Settings object is shaped as follows:

public sealed class Settings
{
    public int KeyOne { get; set; }
    public bool KeyTwo { get; set; }
    public NestedSettings KeyThree { get; set; } = null!;
}
public sealed class NestedSettings
{
    public string Message { get; set; } = null!;
}

Basic example with hosting

To access the IConfiguration value, you can rely again on the Microsoft.Extensions.Hosting NuGet package. Create a new console application, and paste the following project file contents into it:

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net6.0</TargetFramework>
    <Nullable>enable</Nullable>
    <ImplicitUsings>true</ImplicitUsings>
  </PropertyGroup>

  <ItemGroup>
    <Content Include="appsettings.json">
      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
    </Content>
  </ItemGroup>

  <ItemGroup>
    <PackageReference Include="Microsoft.Extensions.Hosting" Version="6.0.0" />
  </ItemGroup>

</Project>

The preceding project file defines:

  • That the application is an executable.
  • That an appsettings.json file is to be copied to the output directory when the project is compiled.
  • That the Microsoft.Extensions.Hosting NuGet package reference is added.

Add the appsettings.json file at the root of the project with the following contents:

{
    "KeyOne": 1,
    "KeyTwo": true,
    "KeyThree": {
        "Message": "Thanks for checking this out!"
    }
}

Replace the contents of the Program.cs file with the following C# code:

using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;

using IHost host = Host.CreateDefaultBuilder(args).Build();

// Ask the service provider for the configuration abstraction.
IConfiguration config = host.Services.GetRequiredService<IConfiguration>();

// Get values from the config given their key and their target type.
int keyOneValue = config.GetValue<int>("KeyOne");
bool keyTwoValue = config.GetValue<bool>("KeyTwo");
string keyThreeNestedValue = config.GetValue<string>("KeyThree:Message");

// Write the values to the console.
Console.WriteLine($"KeyOne = {keyOneValue}");
Console.WriteLine($"KeyTwo = {keyTwoValue}");
Console.WriteLine($"KeyThree:Message = {keyThreeNestedValue}");

// Application code which might rely on the config could start here.

await host.RunAsync();

// This will output the following:
//   KeyOne = 1
//   KeyTwo = True
//   KeyThree:Message = Thanks for checking this out!

When you run this application, the Host.CreateDefaultBuilder defines the behavior to discover the JSON configuration and expose it through the IConfiguration instance. From the host instance, you can ask the service provider for the IConfiguration instance and then ask it for values.

Tip

Using the raw IConfiguration instance in this way, while convenient, doesn't scale very well. When applications grow in complexity, and their corresponding configurations become more complex, we recommend that you use the options pattern as an alternative.

Basic example with hosting and using the indexer API

Consider the same appsettings.json file contents from the previous example:

{
    "SupportedVersions": {
        "v1": "1.0.0",
        "v3": "3.0.7"
    },
    "IPAddressRange": [
        "46.36.198.123",
        "46.36.198.124",
        "46.36.198.125"
    ]
}

Replace the contents of the Program.cs file with the following C# code:

using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;

using IHost host = Host.CreateDefaultBuilder(args).Build();

// Ask the service provider for the configuration abstraction.
IConfiguration config = host.Services.GetRequiredService<IConfiguration>();

// Get values from the config given their key and their target type.
string ipOne = config["IPAddressRange:0"];
string ipTwo = config["IPAddressRange:1"];
string ipThree = config["IPAddressRange:2"];
string versionOne = config["SupportedVersions:v1"];
string versionThree = config["SupportedVersions:v3"];

// Write the values to the console.
Console.WriteLine($"IPAddressRange:0 = {ipOne}");
Console.WriteLine($"IPAddressRange:1 = {ipTwo}");
Console.WriteLine($"IPAddressRange:2 = {ipThree}");
Console.WriteLine($"SupportedVersions:v1 = {versionOne}");
Console.WriteLine($"SupportedVersions:v3 = {versionThree}");

// Application code which might rely on the config could start here.

await host.RunAsync();

// This will output the following:
//     IPAddressRange:0 = 46.36.198.123
//     IPAddressRange:1 = 46.36.198.124
//     IPAddressRange:2 = 46.36.198.125
//     SupportedVersions:v1 = 1.0.0
//     SupportedVersions:v3 = 3.0.7

The values are accessed using the indexer API where each key is a string, and the value is a string. Configuration supports properties, objects, arrays, and dictionaries.

Configuration providers

The following table shows the configuration providers available to .NET Core apps.

Provider Provides configuration from
Azure App configuration provider Azure App Configuration
Azure Key Vault configuration provider Azure Key Vault
Command-line configuration provider Command-line parameters
Custom configuration provider Custom source
Environment Variables configuration provider Environment variables
File configuration provider JSON, XML, and INI files
Key-per-file configuration provider Directory files
Memory configuration provider In-memory collections
App secrets (Secret Manager) File in the user profile directory

Tip

The order in which configuration providers are added matters. When multiple configuration providers are used and more than one provided specifies the same key, the last one added is used.

For more information on various configuration providers, see Configuration providers in .NET.

See also