Configuration in ASP.NET Core

By Rick Anderson and Kirk Larkin

Configuration in ASP.NET Core 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

This topic provides information on configuration in ASP.NET Core. For information on using configuration in console apps, see .NET Configuration.

View or download sample code (how to download)

Default configuration

ASP.NET Core web apps created with dotnet new or Visual Studio generate the following code:

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>();
            });
}

CreateDefaultBuilder provides default configuration for the app in the following order:

  1. ChainedConfigurationProvider : Adds an existing IConfiguration as a source. In the default configuration case, adds the host configuration and setting it as the first source for the app configuration.
  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 MyKey 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.

For more information on CreateDefaultBuilder, see Default builder settings.

The following code displays the enabled configuration providers in the order they were added:

public class Index2Model : PageModel
{
    private IConfigurationRoot ConfigRoot;

    public Index2Model(IConfiguration configRoot)
    {
        ConfigRoot = (IConfigurationRoot)configRoot;
    }

    public ContentResult OnGet()
    {           
        string str = "";
        foreach (var provider in ConfigRoot.Providers.ToList())
        {
            str += provider.ToString() + "\n";
        }

        return Content(str);
    }
}

appsettings.json

Consider the following appsettings.json file:

{
  "Position": {
    "Title": "Editor",
    "Name": "Joe Smith"
  },
  "MyKey":  "My appsettings.json Value",
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft": "Warning",
      "Microsoft.Hosting.Lifetime": "Information"
    }
  },
  "AllowedHosts": "*"
}

The following code from the sample download displays several of the preceding configurations settings:

public class TestModel : PageModel
{
    // requires using Microsoft.Extensions.Configuration;
    private readonly IConfiguration Configuration;

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

    public ContentResult OnGet()
    {
        var myKeyValue = Configuration["MyKey"];
        var title = Configuration["Position:Title"];
        var name = Configuration["Position:Name"];
        var defaultLogLevel = Configuration["Logging:LogLevel:Default"];


        return Content($"MyKey value: {myKeyValue} \n" +
                       $"Title: {title} \n" +
                       $"Name: {name} \n" +
                       $"Default Log Level: {defaultLogLevel}");
    }
}

The default JsonConfigurationProvider loads configuration in the following order:

  1. appsettings.json
  2. appsettings.Environment.json : For example, the appsettings.Production.json and appsettings.Development.json files. The environment version of the file is loaded based on the IHostingEnvironment.EnvironmentName. For more information, see Use multiple environments in ASP.NET Core.

appsettings.Environment.json values override keys in appsettings.json. For example, by default:

  • 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.

Bind hierarchical configuration data using the options pattern

The preferred way to read related configuration values is using the options pattern. For example, to read the following configuration values:

  "Position": {
    "Title": "Editor",
    "Name": "Joe Smith"
  }

Create the following PositionOptions class:

public class PositionOptions
{
    public const string Position = "Position";

    public string Title { get; set; }
    public string Name { get; set; }
}

An options class:

  • Must be non-abstract with a public parameterless constructor.
  • All public read-write properties of the type are bound.
  • Fields are not bound. In the preceding code, Position is not bound. The Position property is used so the string "Position" doesn't need to be hard coded in the app when binding the class to a configuration provider.

The following code:

  • Calls ConfigurationBinder.Bind to bind the PositionOptions class to the Position section.
  • Displays the Position configuration data.
public class Test22Model : PageModel
{
    private readonly IConfiguration Configuration;

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

    public ContentResult OnGet()
    {
        var positionOptions = new PositionOptions();
        Configuration.GetSection(PositionOptions.Position).Bind(positionOptions);

        return Content($"Title: {positionOptions.Title} \n" +
                       $"Name: {positionOptions.Name}");
    }
}

In the preceding code, by default, changes to the JSON configuration file after the app has started are read.

ConfigurationBinder.Get<T> binds and returns the specified type. ConfigurationBinder.Get<T> may be more convenient than using ConfigurationBinder.Bind. The following code shows how to use ConfigurationBinder.Get<T> with the PositionOptions class:

public class Test21Model : PageModel
{
    private readonly IConfiguration Configuration;
    public PositionOptions positionOptions { get; private set; }

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

    public ContentResult OnGet()
    {            
        positionOptions = Configuration.GetSection(PositionOptions.Position)
                                                     .Get<PositionOptions>();

        return Content($"Title: {positionOptions.Title} \n" +
                       $"Name: {positionOptions.Name}");
    }
}

In the preceding code, by default, changes to the JSON configuration file after the app has started are read.

An alternative approach when using the options pattern is to bind the Position section and add it to the dependency injection service container. In the following code, PositionOptions is added to the service container with Configure and bound to configuration:

public void ConfigureServices(IServiceCollection services)
{
    services.Configure<PositionOptions>(Configuration.GetSection(
                                        PositionOptions.Position));
    services.AddRazorPages();
}

Using the preceding code, the following code reads the position options:

public class Test2Model : PageModel
{
    private readonly PositionOptions _options;

    public Test2Model(IOptions<PositionOptions> options)
    {
        _options = options.Value;
    }

    public ContentResult OnGet()
    {
        return Content($"Title: {_options.Title} \n" +
                       $"Name: {_options.Name}");
    }
}

In the preceding code, changes to the JSON configuration file after the app has started are not read. To read changes after the app has started, use IOptionsSnapshot.

Using the default configuration, the appsettings.json and appsettings.Environment.json files are enabled with reloadOnChange: true. Changes made to the appsettings.json and appsettings.Environment.json file after the app starts are read by the JSON configuration provider.

See JSON configuration provider in this document for information on adding additional JSON configuration files.

Combining service collection

Consider the following ConfigureServices method, which registers services and configures options:

public void ConfigureServices(IServiceCollection services)
{
    services.Configure<PositionOptions>(
        Configuration.GetSection(PositionOptions.Position));
    services.Configure<ColorOptions>(
        Configuration.GetSection(ColorOptions.Color));

    services.AddScoped<IMyDependency, MyDependency>();
    services.AddScoped<IMyDependency2, MyDependency2>();

    services.AddRazorPages();
}

Related groups of registrations can be moved to an extension method to register services. For example, the configuration services are added to the following class:

using ConfigSample.Options;
using Microsoft.Extensions.Configuration;

namespace Microsoft.Extensions.DependencyInjection
{
    public static class MyConfigServiceCollectionExtensions
    {
        public static IServiceCollection AddConfig(
             this IServiceCollection services, IConfiguration config)
        {
            services.Configure<PositionOptions>(
                config.GetSection(PositionOptions.Position));
            services.Configure<ColorOptions>(
                config.GetSection(ColorOptions.Color));

            return services;
        }
    }
}

The remaining services are registered in a similar class. The following ConfigureServices method uses the new extension methods to register the services:

public void ConfigureServices(IServiceCollection services)
{
    services.AddConfig(Configuration)
            .AddMyDependencyGroup();

    services.AddRazorPages();
}

Note: Each services.Add{GROUP_NAME} extension method adds and potentially configures services. For example, AddControllersWithViews adds the services MVC controllers with views require, and AddRazorPages adds the services Razor Pages requires. We recommended that apps follow this naming convention. Place extension methods in the Microsoft.Extensions.DependencyInjection namespace to encapsulate groups of service registrations.

Security and user secrets

Configuration data guidelines:

  • Never store passwords or other sensitive data in configuration provider code or in plain text configuration files. The Secret Manager tool can be used to store secrets in development.
  • Don't use production secrets in development or test environments.
  • Specify secrets outside of the project so that they can't be accidentally committed to a source code repository.

By default, the user secrets configuration source is registered after the JSON configuration sources. Therefore, user secrets keys take precedence over keys in appsettings.json and appsettings.Environment.json.

For more information on storing passwords or other sensitive data:

Azure Key Vault safely stores app secrets for ASP.NET Core apps. For more information, see Azure Key Vault Configuration Provider in ASP.NET Core.

Environment variables

Using the default configuration, the EnvironmentVariablesConfigurationProvider loads configuration from environment variable key-value pairs after reading appsettings.json, appsettings.Environment.json, and user secrets. Therefore, key values read from the environment override values read from appsettings.json, appsettings.Environment.json, and user secrets.

The : separator doesn't work with environment variable hierarchical keys on all platforms. __, the double underscore, is:

  • Supported by all platforms. For example, the : separator is not supported by Bash, but __ is.
  • Automatically replaced by a :

The following set commands:

  • Set the environment keys and values of the preceding example on Windows.
  • Test the settings when using the sample download. The dotnet run command must be run in the project directory.
set MyKey="My key from Environment"
set Position__Title=Environment_Editor
set Position__Name=Environment_Rick
dotnet run

The preceding environment settings:

  • Are only set in processes launched from the command window they were set in.
  • Won't be read by browsers launched with Visual Studio.

The following setx commands can be used to set the environment keys and values on Windows. Unlike set, setx settings are persisted. /M sets the variable in the system environment. If the /M switch isn't used, a user environment variable is set.

setx MyKey "My key from setx Environment" /M
setx Position__Title Setx_Environment_Editor /M
setx Position__Name Environment_Rick /M

To test that the preceding commands override appsettings.json and appsettings.Environment.json:

  • With Visual Studio: Exit and restart Visual Studio.
  • With the CLI: Start a new command window and enter dotnet run.

Call AddEnvironmentVariables with a string to specify a prefix for environment variables:

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.AddEnvironmentVariables(prefix: "MyCustomPrefix_");
            })
            .ConfigureWebHostDefaults(webBuilder =>
            {
                webBuilder.UseStartup<Startup>();
            });
}

In the preceding code:

The prefix is stripped off when the configuration key-value pairs are read.

The following commands test the custom prefix:

set MyCustomPrefix_MyKey="My key with MyCustomPrefix_ Environment"
set MyCustomPrefix_Position__Title=Editor_with_customPrefix
set MyCustomPrefix_Position__Name=Environment_Rick_cp
dotnet run

The default configuration loads environment variables and command line arguments prefixed with DOTNET_ and ASPNETCORE_. The DOTNET_ and ASPNETCORE_ prefixes are used by ASP.NET Core for host and app configuration, but not for user configuration. For more information on host and app configuration, see .NET Generic Host.

On Azure App Service, select New application setting on the Settings > Configuration page. Azure App Service application settings are:

  • Encrypted at rest and transmitted over an encrypted channel.
  • Exposed as environment variables.

For more information, see Azure Apps: Override app configuration using the Azure Portal.

See Connection string prefixes for information on Azure database connection strings.

Naming of environment variables

Environment variable names reflect the structure of an appsettings.json file. Each element in the hierarchy is separated by a double underscore (preferable) or a colon. When the element structure includes an array, the array index should be treated as an additional element name in this path. Consider the following appsettings.json file and its equivalent values represented as environment variables.

appsettings.json

{
    "SmtpServer": "smtp.example.com",
    "Logging": [
        {
            "Name": "ToEmail",
            "Level": "Critical",
            "Args": {
                "FromAddress": "MySystem@example.com",
                "ToAddress": "SRE@example.com"
            }
        },
        {
            "Name": "ToConsole",
            "Level": "Information"
        }
    ]
}

environment variables

setx SmtpServer=smtp.example.com
setx Logging__0__Name=ToEmail
setx Logging__0__Level=Critical
setx Logging__0__Args__FromAddress=MySystem@example.com
setx Logging__0__Args__ToAddress=SRE@example.com
setx Logging__1__Name=ToConsole
setx Logging__1__Level=Information

Environment variables set in launchSettings.json

Environment variables set in launchSettings.json override those set in the system environment.

Command-line

Using the default configuration, the CommandLineConfigurationProvider loads configuration from command-line argument key-value pairs after the following configuration sources:

  • appsettings.json and appsettings.Environment.json files.
  • App secrets in the Development environment.
  • Environment variables.

By default, configuration values set on the command-line override configuration values set with all the other configuration providers.

Command-line arguments

The following command sets keys and values using =:

dotnet run MyKey="My key from command line" Position:Title=Cmd Position:Name=Cmd_Rick

The following command sets keys and values using /:

dotnet run /MyKey "Using /" /Position:Title=Cmd_ /Position:Name=Cmd_Rick

The following command sets keys and values using --:

dotnet run --MyKey "Using --" --Position:Title=Cmd-- --Position:Name=Cmd--Rick

The key value:

  • Must follow =, or the key must have a prefix of -- or / when the value follows a space.
  • Isn't required if = is used. For example, MySetting=.

Within the same command, don't mix command-line argument key-value pairs that use = with key-value pairs that use a space.

Switch mappings

Switch mappings allow key name replacement logic. Provide a dictionary of switch replacements to the AddCommandLine method.

When the switch mappings dictionary is used, the dictionary is checked for a key that matches the key provided by a command-line argument. If the command-line key is found in the dictionary, the dictionary value is passed back to set the key-value pair into the app's configuration. A switch mapping is required for any command-line key prefixed with a single dash (-).

Switch mappings dictionary key rules:

  • Switches must start with - or --.
  • The switch mappings dictionary must not contain duplicate keys.

To use a switch mappings dictionary, pass it into the call to AddCommandLine:

public class Program
{
    public static void Main(string[] args)
    {
        CreateHostBuilder(args).Build().Run();
    }

    public static IHostBuilder CreateHostBuilder(string[] args)
    {
        var switchMappings = new Dictionary<string, string>()
         {
             { "-k1", "key1" },
             { "-k2", "key2" },
             { "--alt3", "key3" },
             { "--alt4", "key4" },
             { "--alt5", "key5" },
             { "--alt6", "key6" },
         };

        return Host.CreateDefaultBuilder(args)
            .ConfigureAppConfiguration((hostingContext, config) =>
            {
                config.AddCommandLine(args, switchMappings);
            })
            .ConfigureWebHostDefaults(webBuilder =>
            {
                webBuilder.UseStartup<Startup>();
            });
    }
}

The following code shows the key values for the replaced keys:

public class Test3Model : PageModel
{
    private readonly IConfiguration Config;

    public Test3Model(IConfiguration configuration)
    {
        Config = configuration;
    }

    public ContentResult OnGet()
    {
        return Content(
                $"Key1: '{Config["Key1"]}'\n" +
                $"Key2: '{Config["Key2"]}'\n" +
                $"Key3: '{Config["Key3"]}'\n" +
                $"Key4: '{Config["Key4"]}'\n" +
                $"Key5: '{Config["Key5"]}'\n" +
                $"Key6: '{Config["Key6"]}'");
    }
}

The following command works to test key replacement:

dotnet run -k1 value1 -k2 value2 --alt3=value2 /alt4=value3 --alt5 value5 /alt6 value6

For apps that use switch mappings, the call to CreateDefaultBuilder shouldn't pass arguments. The CreateDefaultBuilder method's AddCommandLine call doesn't include mapped switches, and there's no way to pass the switch-mapping dictionary to CreateDefaultBuilder. The solution isn't to pass the arguments to CreateDefaultBuilder but instead to allow the ConfigurationBuilder method's AddCommandLine method to process both the arguments and the switch-mapping dictionary.

Hierarchical configuration data

The Configuration API reads hierarchical configuration data by flattening the hierarchical data with the use of a delimiter in the configuration keys.

The sample download contains the following appsettings.json file:

{
  "Position": {
    "Title": "Editor",
    "Name": "Joe Smith"
  },
  "MyKey":  "My appsettings.json Value",
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft": "Warning",
      "Microsoft.Hosting.Lifetime": "Information"
    }
  },
  "AllowedHosts": "*"
}

The following code from the sample download displays several of the configurations settings:

public class TestModel : PageModel
{
    // requires using Microsoft.Extensions.Configuration;
    private readonly IConfiguration Configuration;

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

    public ContentResult OnGet()
    {
        var myKeyValue = Configuration["MyKey"];
        var title = Configuration["Position:Title"];
        var name = Configuration["Position:Name"];
        var defaultLogLevel = Configuration["Logging:LogLevel:Default"];


        return Content($"MyKey value: {myKeyValue} \n" +
                       $"Title: {title} \n" +
                       $"Name: {name} \n" +
                       $"Default Log Level: {defaultLogLevel}");
    }
}

The preferred way to read hierarchical configuration data is using the options pattern. For more information, see Bind hierarchical configuration data in this document.

GetSection and GetChildren methods are available to isolate sections and children of a section in the configuration data. These methods are described later in GetSection, GetChildren, and Exists.

Configuration keys and values

Configuration keys:

  • Are case-insensitive. For example, ConnectionString and connectionstring are treated as equivalent keys.
  • If a key and value is set in more than one configuration providers, the value from the last provider added is used. For more information, see Default configuration.
  • Hierarchical keys
    • Within the Configuration API, a colon separator (:) works on all platforms.
    • In environment variables, a colon separator may not work on all platforms. A double underscore, __, is supported by all platforms and is automatically converted into a colon :.
    • In Azure Key Vault, hierarchical keys use -- as a separator. The Azure Key Vault configuration provider automatically replaces -- with a : when the secrets are loaded into the app's configuration.
  • The ConfigurationBinder supports binding arrays to objects using array indices in configuration keys. Array binding is described in the Bind an array to a class section.

Configuration values:

  • Are strings.
  • Null values can't be stored in configuration or bound to objects.

Configuration providers

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

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

Configuration sources are read in the order that their configuration providers are specified. Order configuration providers in code to suit the priorities for the underlying configuration sources that the app requires.

A typical sequence of configuration providers is:

  1. appsettings.json
  2. appsettings.Environment.json
  3. User secrets
  4. Environment variables using the Environment Variables configuration provider.
  5. Command-line arguments using the Command-line configuration provider.

A common practice is to add the Command-line configuration provider last in a series of providers to allow command-line arguments to override configuration set by the other providers.

The preceding sequence of providers is used in the default configuration.

Connection string prefixes

The Configuration API has special processing rules for four connection string environment variables. These connection strings are involved in configuring Azure connection strings for the app environment. Environment variables with the prefixes shown in the table are loaded into the app with the default configuration or when no prefix is supplied to AddEnvironmentVariables.

Connection string prefix Provider
CUSTOMCONNSTR_ Custom provider
MYSQLCONNSTR_ MySQL
SQLAZURECONNSTR_ Azure SQL Database
SQLCONNSTR_ SQL Server

When an environment variable is discovered and loaded into configuration with any of the four prefixes shown in the table:

  • The configuration key is created by removing the environment variable prefix and adding a configuration key section (ConnectionStrings).
  • A new configuration key-value pair is created that represents the database connection provider (except for CUSTOMCONNSTR_, which has no stated provider).
Environment variable key Converted configuration key Provider configuration entry
CUSTOMCONNSTR_{KEY} ConnectionStrings:{KEY} Configuration entry not created.
MYSQLCONNSTR_{KEY} ConnectionStrings:{KEY} Key: ConnectionStrings:{KEY}_ProviderName:
Value: MySql.Data.MySqlClient
SQLAZURECONNSTR_{KEY} ConnectionStrings:{KEY} Key: ConnectionStrings:{KEY}_ProviderName:
Value: System.Data.SqlClient
SQLCONNSTR_{KEY} ConnectionStrings:{KEY} Key: ConnectionStrings:{KEY}_ProviderName:
Value: System.Data.SqlClient

File configuration provider

FileConfigurationProvider is the base class for loading configuration from the file system. The following configuration providers derive from FileConfigurationProvider:

INI configuration provider

The IniConfigurationProvider loads configuration from INI file key-value pairs at runtime.

The following code clears all the configuration providers and adds several 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("MyIniConfig.ini", optional: true, reloadOnChange: true)
                      .AddIniFile($"MyIniConfig.{env.EnvironmentName}.ini",
                                     optional: true, reloadOnChange: true);

                config.AddEnvironmentVariables();

                if (args != null)
                {
                    config.AddCommandLine(args);
                }
            })
            .ConfigureWebHostDefaults(webBuilder =>
            {
                webBuilder.UseStartup<Startup>();
            });
}

In the preceding code, settings in the MyIniConfig.ini and MyIniConfig.Environment.ini files are overridden by settings in the:

The sample download contains the following MyIniConfig.ini file:

MyKey="MyIniConfig.ini Value"

[Position]
Title="My INI Config title"
Name="My INI Config name"

[Logging:LogLevel]
Default=Information
Microsoft=Warning

The following code from the sample download displays several of the preceding configurations settings:

public class TestModel : PageModel
{
    // requires using Microsoft.Extensions.Configuration;
    private readonly IConfiguration Configuration;

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

    public ContentResult OnGet()
    {
        var myKeyValue = Configuration["MyKey"];
        var title = Configuration["Position:Title"];
        var name = Configuration["Position:Name"];
        var defaultLogLevel = Configuration["Logging:LogLevel:Default"];


        return Content($"MyKey value: {myKeyValue} \n" +
                       $"Title: {title} \n" +
                       $"Name: {name} \n" +
                       $"Default Log Level: {defaultLogLevel}");
    }
}

JSON configuration provider

The JsonConfigurationProvider loads configuration from JSON file key-value pairs.

Overloads can specify:

  • Whether the file is optional.
  • Whether the configuration is reloaded if the file changes.

Consider the following code:

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.AddJsonFile("MyConfig.json", 
                    optional: true, 
                    reloadOnChange: true);
            })
            .ConfigureWebHostDefaults(webBuilder =>
            {
                webBuilder.UseStartup<Startup>();
            });
}

The preceding code:

You typically don't want a custom JSON file overriding values set in the Environment variables configuration provider and the Command-line configuration provider.

The following code clears all the configuration providers and adds several 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.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
                      .AddJsonFile($"appsettings.{env.EnvironmentName}.json", 
                                     optional: true, reloadOnChange: true);

                config.AddJsonFile("MyConfig.json", optional: true, reloadOnChange: true)
                      .AddJsonFile($"MyConfig.{env.EnvironmentName}.json",
                                     optional: true, reloadOnChange: true);

                config.AddEnvironmentVariables();

                if (args != null)
                {
                    config.AddCommandLine(args);
                }
            })
            .ConfigureWebHostDefaults(webBuilder =>
            {
                webBuilder.UseStartup<Startup>();
            });
}

In the preceding code, settings in the MyConfig.json and MyConfig.Environment.json files:

The sample download contains the following MyConfig.json file:

{
  "Position": {
    "Title": "My Config title",
    "Name": "My Config Smith"
  },
  "MyKey":  "MyConfig.json Value",
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft": "Warning",
      "Microsoft.Hosting.Lifetime": "Information"
    }
  },
  "AllowedHosts": "*"
}

The following code from the sample download displays several of the preceding configurations settings:

public class TestModel : PageModel
{
    // requires using Microsoft.Extensions.Configuration;
    private readonly IConfiguration Configuration;

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

    public ContentResult OnGet()
    {
        var myKeyValue = Configuration["MyKey"];
        var title = Configuration["Position:Title"];
        var name = Configuration["Position:Name"];
        var defaultLogLevel = Configuration["Logging:LogLevel:Default"];


        return Content($"MyKey value: {myKeyValue} \n" +
                       $"Title: {title} \n" +
                       $"Name: {name} \n" +
                       $"Default Log Level: {defaultLogLevel}");
    }
}

XML configuration provider

The XmlConfigurationProvider loads configuration from XML file key-value pairs at runtime.

The following code clears all the configuration providers and adds several 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("MyXMLFile.xml", optional: true, reloadOnChange: true)
                      .AddXmlFile($"MyXMLFile.{env.EnvironmentName}.xml",
                                     optional: true, reloadOnChange: true);

                config.AddEnvironmentVariables();

                if (args != null)
                {
                    config.AddCommandLine(args);
                }
            })
            .ConfigureWebHostDefaults(webBuilder =>
            {
                webBuilder.UseStartup<Startup>();
            });
}

In the preceding code, settings in the MyXMLFile.xml and MyXMLFile.Environment.xml files are overridden by settings in the:

The sample download contains the following MyXMLFile.xml file:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <MyKey>MyXMLFile Value</MyKey>
  <Position>
    <Title>Title from  MyXMLFile</Title>
    <Name>Name from MyXMLFile</Name>
  </Position>
  <Logging>
    <LogLevel>
      <Default>Information</Default>
      <Microsoft>Warning</Microsoft>
    </LogLevel>
  </Logging>
</configuration>

The following code from the sample download displays several of the preceding configurations settings:

public class TestModel : PageModel
{
    // requires using Microsoft.Extensions.Configuration;
    private readonly IConfiguration Configuration;

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

    public ContentResult OnGet()
    {
        var myKeyValue = Configuration["MyKey"];
        var title = Configuration["Position:Title"];
        var name = Configuration["Position:Name"];
        var defaultLogLevel = Configuration["Logging:LogLevel:Default"];


        return Content($"MyKey value: {myKeyValue} \n" +
                       $"Title: {title} \n" +
                       $"Name: {name} \n" +
                       $"Default Log Level: {defaultLogLevel}");
    }
}

Repeating elements that use the same element name work if the name attribute is used to distinguish the elements:

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
  <section name="section0">
    <key name="key0">value 00</key>
    <key name="key1">value 01</key>
  </section>
  <section name="section1">
    <key name="key0">value 10</key>
    <key name="key1">value 11</key>
  </section>
</configuration>

The following code reads the previous configuration file and displays the keys and values:

public class IndexModel : PageModel
{
    private readonly IConfiguration Configuration;

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

    public ContentResult OnGet()
    {
        var key00 = "section:section0:key:key0";
        var key01 = "section:section0:key:key1";
        var key10 = "section:section1:key:key0";
        var key11 = "section:section1:key:key1";

        var val00 = Configuration[key00];
        var val01 = Configuration[key01];
        var val10 = Configuration[key10];
        var val11 = Configuration[key11];

        return Content($"{key00} value: {val00} \n" +
                       $"{key01} value: {val01} \n" +
                       $"{key10} value: {val10} \n" +
                       $"{key10} value: {val11} \n"
                       );
    }
}

Attributes can be used to supply values:

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
  <key attribute="value" />
  <section>
    <key attribute="value" />
  </section>
</configuration>

The previous configuration file loads the following keys with value:

  • key:attribute
  • section:key:attribute

Key-per-file configuration provider

The KeyPerFileConfigurationProvider uses a directory's files as configuration key-value pairs. The key is the file name. The value contains the file's contents. The Key-per-file configuration provider is used in Docker hosting scenarios.

To activate key-per-file configuration, call the AddKeyPerFile extension method on an instance of ConfigurationBuilder. The directoryPath to the files must be an absolute path.

Overloads permit specifying:

  • An Action<KeyPerFileConfigurationSource> delegate that configures the source.
  • Whether the directory is optional and the path to the directory.

The double-underscore (__) is used as a configuration key delimiter in file names. For example, the file name Logging__LogLevel__System produces the configuration key Logging:LogLevel:System.

Call ConfigureAppConfiguration when building the host to specify the app's configuration:

.ConfigureAppConfiguration((hostingContext, config) =>
{
    var path = Path.Combine(
        Directory.GetCurrentDirectory(), "path/to/files");
    config.AddKeyPerFile(directoryPath: path, optional: true);
})

Memory configuration provider

The MemoryConfigurationProvider uses an in-memory collection as configuration key-value pairs.

The following code adds a memory collection to the configuration system:

public class Program
{
    public static void Main(string[] args)
    {
        CreateHostBuilder(args).Build().Run();
    }

    public static IHostBuilder CreateHostBuilder(string[] args)
    {
        var Dict = new Dictionary<string, string>
        {
           {"MyKey", "Dictionary MyKey Value"},
           {"Position:Title", "Dictionary_Title"},
           {"Position:Name", "Dictionary_Name" },
           {"Logging:LogLevel:Default", "Warning"}
        };

        return Host.CreateDefaultBuilder(args)
            .ConfigureAppConfiguration((hostingContext, config) =>
            {
                config.AddInMemoryCollection(Dict);
            })
            .ConfigureWebHostDefaults(webBuilder =>
            {
                webBuilder.UseStartup<Startup>();
            });
    }
}

The following code from the sample download displays the preceding configurations settings:

public class TestModel : PageModel
{
    // requires using Microsoft.Extensions.Configuration;
    private readonly IConfiguration Configuration;

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

    public ContentResult OnGet()
    {
        var myKeyValue = Configuration["MyKey"];
        var title = Configuration["Position:Title"];
        var name = Configuration["Position:Name"];
        var defaultLogLevel = Configuration["Logging:LogLevel:Default"];


        return Content($"MyKey value: {myKeyValue} \n" +
                       $"Title: {title} \n" +
                       $"Name: {name} \n" +
                       $"Default Log Level: {defaultLogLevel}");
    }
}

In the preceding code, config.AddInMemoryCollection(Dict) is added after the default configuration providers. For an example of ordering the configuration providers, see JSON configuration provider.

See Bind an array for another example using MemoryConfigurationProvider.

GetValue

ConfigurationBinder.GetValue<T> extracts a single value from configuration with a specified key and converts it to the specified type:

public class TestNumModel : PageModel
{
    private readonly IConfiguration Configuration;

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

    public ContentResult OnGet()
    {
        var number = Configuration.GetValue<int>("NumberKey", 99);
        return Content($"{number}");
    }
}

In the preceding code, if NumberKey isn't found in the configuration, the default value of 99 is used.

GetSection, GetChildren, and Exists

For the examples that follow, consider the following MySubsection.json file:

{
  "section0": {
    "key0": "value00",
    "key1": "value01"
  },
  "section1": {
    "key0": "value10",
    "key1": "value11"
  },
  "section2": {
    "subsection0": {
      "key0": "value200",
      "key1": "value201"
    },
    "subsection1": {
      "key0": "value210",
      "key1": "value211"
    }
  }
}

The following code adds MySubsection.json to the 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.AddJsonFile("MySubsection.json", 
                    optional: true, 
                    reloadOnChange: true);
            })
            .ConfigureWebHostDefaults(webBuilder =>
            {
                webBuilder.UseStartup<Startup>();
            });
}

GetSection

IConfiguration.GetSection returns a configuration subsection with the specified subsection key.

The following code returns values for section1:

public class TestSectionModel : PageModel
{
    private readonly IConfiguration Config;

    public TestSectionModel(IConfiguration configuration)
    {
        Config = configuration.GetSection("section1");
    }

    public ContentResult OnGet()
    {
        return Content(
                $"section1:key0: '{Config["key0"]}'\n" +
                $"section1:key1: '{Config["key1"]}'");
    }
}

The following code returns values for section2:subsection0:

public class TestSection2Model : PageModel
{
    private readonly IConfiguration Config;

    public TestSection2Model(IConfiguration configuration)
    {
        Config = configuration.GetSection("section2:subsection0");
    }

    public ContentResult OnGet()
    {
        return Content(
                $"section2:subsection0:key0 '{Config["key0"]}'\n" +
                $"section2:subsection0:key1:'{Config["key1"]}'");
    }
}

GetSection never returns null. If a matching section isn't found, an empty IConfigurationSection is returned.

When GetSection returns a matching section, Value isn't populated. A Key and Path are returned when the section exists.

GetChildren and Exists

The following code calls IConfiguration.GetChildren and returns values for section2:subsection0:

public class TestSection4Model : PageModel
{
    private readonly IConfiguration Config;

    public TestSection4Model(IConfiguration configuration)
    {
        Config = configuration;
    }

    public ContentResult OnGet()
    {
        string s = null;
        var selection = Config.GetSection("section2");
        if (!selection.Exists())
        {
            throw new System.Exception("section2 does not exist.");
        }
        var children = selection.GetChildren();

        foreach (var subSection in children)
        {
            int i = 0;
            var key1 = subSection.Key + ":key" + i++.ToString();
            var key2 = subSection.Key + ":key" + i.ToString();
            s += key1 + " value: " + selection[key1] + "\n";
            s += key2 + " value: " + selection[key2] + "\n";
        }
        return Content(s);
    }
}

The preceding code calls ConfigurationExtensions.Exists to verify the section exists:

Bind an array

The ConfigurationBinder.Bind supports binding arrays to objects using array indices in configuration keys. Any array format that exposes a numeric key segment is capable of array binding to a POCO class array.

Consider MyArray.json from the sample download:

{
  "array": {
    "entries": {
      "0": "value00",
      "1": "value10",
      "2": "value20",
      "4": "value40",
      "5": "value50"
    }
  }
}

The following code adds MyArray.json to the 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.AddJsonFile("MyArray.json", 
                    optional: true, 
                    reloadOnChange: true);
            })
            .ConfigureWebHostDefaults(webBuilder =>
            {
                webBuilder.UseStartup<Startup>();
            });
}

The following code reads the configuration and displays the values:

public class ArrayModel : PageModel
{
    private readonly IConfiguration Config;
    public ArrayExample _array { get; private set; }

    public ArrayModel(IConfiguration config)
    {
        Config = config;
    }

    public ContentResult OnGet()
    {
        _array = Config.GetSection("array").Get<ArrayExample>();
        string s = null;

        for (int j = 0; j < _array.Entries.Length; j++)
        {
            s += $"Index: {j}  Value:  {_array.Entries[j]} \n";
        }

        return Content(s);
    }
}

The preceding code returns the following output:

Index: 0  Value: value00
Index: 1  Value: value10
Index: 2  Value: value20
Index: 3  Value: value40
Index: 4  Value: value50

In the preceding output, Index 3 has value value40, corresponding to "4": "value40", in MyArray.json. The bound array indices are continuous and not bound to the configuration key index. The configuration binder isn't capable of binding null values or creating null entries in bound objects

The following code loads the array:entries configuration with the AddInMemoryCollection extension method:

public class Program
{
    public static void Main(string[] args)
    {
        CreateHostBuilder(args).Build().Run();
    }

    public static IHostBuilder CreateHostBuilder(string[] args)
    {
        var arrayDict = new Dictionary<string, string>
        {
            {"array:entries:0", "value0"},
            {"array:entries:1", "value1"},
            {"array:entries:2", "value2"},
            //              3   Skipped
            {"array:entries:4", "value4"},
            {"array:entries:5", "value5"}
        };

        return Host.CreateDefaultBuilder(args)
            .ConfigureAppConfiguration((hostingContext, config) =>
            {
                config.AddInMemoryCollection(arrayDict);
            })
            .ConfigureWebHostDefaults(webBuilder =>
            {
                webBuilder.UseStartup<Startup>();
            });
    }
}

The following code reads the configuration in the arrayDict Dictionary and displays the values:

public class ArrayModel : PageModel
{
    private readonly IConfiguration Config;
    public ArrayExample _array { get; private set; }

    public ArrayModel(IConfiguration config)
    {
        Config = config;
    }

    public ContentResult OnGet()
    {
        _array = Config.GetSection("array").Get<ArrayExample>();
        string s = null;

        for (int j = 0; j < _array.Entries.Length; j++)
        {
            s += $"Index: {j}  Value:  {_array.Entries[j]} \n";
        }

        return Content(s);
    }
}

The preceding code returns the following output:

Index: 0  Value: value0
Index: 1  Value: value1
Index: 2  Value: value2
Index: 3  Value: value4
Index: 4  Value: value5

Index #3 in the bound object holds the configuration data for the array:4 configuration key and its value of value4. When configuration data containing an array is bound, the array indices in the configuration keys are used to iterate the configuration data when creating the object. A null value can't be retained in configuration data, and a null-valued entry isn't created in a bound object when an array in configuration keys skip one or more indices.

The missing configuration item for index #3 can be supplied before binding to the ArrayExample instance by any configuration provider that reads the index #3 key/value pair. Consider the following Value3.json file from the sample download:

{
  "array:entries:3": "value3"
}

The following code includes configuration for Value3.json and the arrayDict Dictionary:

public class Program
{
    public static void Main(string[] args)
    {
        CreateHostBuilder(args).Build().Run();
    }

    public static IHostBuilder CreateHostBuilder(string[] args)
    {
        var arrayDict = new Dictionary<string, string>
        {
            {"array:entries:0", "value0"},
            {"array:entries:1", "value1"},
            {"array:entries:2", "value2"},
            //              3   Skipped
            {"array:entries:4", "value4"},
            {"array:entries:5", "value5"}
        };

        return Host.CreateDefaultBuilder(args)
            .ConfigureAppConfiguration((hostingContext, config) =>
            {
                config.AddInMemoryCollection(arrayDict);
                config.AddJsonFile("Value3.json",
                                    optional: false, reloadOnChange: false);
            })
            .ConfigureWebHostDefaults(webBuilder =>
            {
                webBuilder.UseStartup<Startup>();
            });
    }
}

The following code reads the preceding configuration and displays the values:

public class ArrayModel : PageModel
{
    private readonly IConfiguration Config;
    public ArrayExample _array { get; private set; }

    public ArrayModel(IConfiguration config)
    {
        Config = config;
    }

    public ContentResult OnGet()
    {
        _array = Config.GetSection("array").Get<ArrayExample>();
        string s = null;

        for (int j = 0; j < _array.Entries.Length; j++)
        {
            s += $"Index: {j}  Value:  {_array.Entries[j]} \n";
        }

        return Content(s);
    }
}

The preceding code returns the following output:

Index: 0  Value: value0
Index: 1  Value: value1
Index: 2  Value: value2
Index: 3  Value: value3
Index: 4  Value: value4
Index: 5  Value: value5

Custom configuration providers aren't required to implement array binding.

Custom configuration provider

The sample app demonstrates how to create a basic configuration provider that reads configuration key-value pairs from a database using Entity Framework (EF).

The provider has the following characteristics:

  • The EF in-memory database is used for demonstration purposes. To use a database that requires a connection string, implement a secondary ConfigurationBuilder to supply the connection string from another configuration provider.
  • The provider reads a database table into configuration at startup. The provider doesn't query the database on a per-key basis.
  • Reload-on-change isn't implemented, so updating the database after the app starts has no effect on the app's configuration.

Define an EFConfigurationValue entity for storing configuration values in the database.

Models/EFConfigurationValue.cs:

public class EFConfigurationValue
{
    public string Id { get; set; }
    public string Value { get; set; }
}

Add an EFConfigurationContext to store and access the configured values.

EFConfigurationProvider/EFConfigurationContext.cs:

// using Microsoft.EntityFrameworkCore;

public class EFConfigurationContext : DbContext
{
    public EFConfigurationContext(DbContextOptions options) : base(options)
    {
    }

    public DbSet<EFConfigurationValue> Values { get; set; }
}

Create a class that implements IConfigurationSource.

EFConfigurationProvider/EFConfigurationSource.cs:

// using Microsoft.EntityFrameworkCore;
// using Microsoft.Extensions.Configuration;

public class EFConfigurationSource : IConfigurationSource
{
    private readonly Action<DbContextOptionsBuilder> _optionsAction;

    public EFConfigurationSource(Action<DbContextOptionsBuilder> optionsAction)
    {
        _optionsAction = optionsAction;
    }

    public IConfigurationProvider Build(IConfigurationBuilder builder)
    {
        return new EFConfigurationProvider(_optionsAction);
    }
}

Create the custom configuration provider by inheriting from ConfigurationProvider. The configuration provider initializes the database when it's empty. Since configuration keys are case-insensitive, the dictionary used to initialize the database is created with the case-insensitive comparer (StringComparer.OrdinalIgnoreCase).

EFConfigurationProvider/EFConfigurationProvider.cs:

// using Microsoft.EntityFrameworkCore;
// using Microsoft.Extensions.Configuration;

public class EFConfigurationProvider : ConfigurationProvider
{
    public EFConfigurationProvider(Action<DbContextOptionsBuilder> optionsAction)
    {
        OptionsAction = optionsAction;
    }

    Action<DbContextOptionsBuilder> OptionsAction { get; }

    public override void Load()
    {
        var builder = new DbContextOptionsBuilder<EFConfigurationContext>();

        OptionsAction(builder);

        using (var dbContext = new EFConfigurationContext(builder.Options))
        {
            dbContext.Database.EnsureCreated();

            Data = !dbContext.Values.Any()
                ? CreateAndSaveDefaultValues(dbContext)
                : dbContext.Values.ToDictionary(c => c.Id, c => c.Value);
        }
    }

    private static IDictionary<string, string> CreateAndSaveDefaultValues(
        EFConfigurationContext dbContext)
    {
        // Quotes (c)2005 Universal Pictures: Serenity
        // https://www.uphe.com/movies/serenity
        var configValues = 
            new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
            {
                { "quote1", "I aim to misbehave." },
                { "quote2", "I swallowed a bug." },
                { "quote3", "You can't stop the signal, Mal." }
            };

        dbContext.Values.AddRange(configValues
            .Select(kvp => new EFConfigurationValue 
                {
                    Id = kvp.Key,
                    Value = kvp.Value
                })
            .ToArray());

        dbContext.SaveChanges();

        return configValues;
    }
}

An AddEFConfiguration extension method permits adding the configuration source to a ConfigurationBuilder.

Extensions/EntityFrameworkExtensions.cs:

// using Microsoft.EntityFrameworkCore;
// using Microsoft.Extensions.Configuration;

public static class EntityFrameworkExtensions
{
    public static IConfigurationBuilder AddEFConfiguration(
        this IConfigurationBuilder builder, 
        Action<DbContextOptionsBuilder> optionsAction)
    {
        return builder.Add(new EFConfigurationSource(optionsAction));
    }
}

The following code shows how to use the custom EFConfigurationProvider in Program.cs:

// using Microsoft.EntityFrameworkCore;

public static IHostBuilder CreateHostBuilder(string[] args) =>
    Host.CreateDefaultBuilder(args)
        .ConfigureAppConfiguration((hostingContext, config) =>
        {
            config.AddEFConfiguration(
                options => options.UseInMemoryDatabase("InMemoryDb"));
        })

Access configuration in Startup

The following code displays configuration data in Startup methods:

public class Startup
{
    public Startup(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public IConfiguration Configuration { get; }

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddRazorPages();
        Console.WriteLine($"MyKey : {Configuration["MyKey"]}");
    }

    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
        Console.WriteLine($"Position:Title : {Configuration["Position:Title"]}");

        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }
        else
        {
            app.UseExceptionHandler("/Error");
            app.UseHsts();
        }

        app.UseHttpsRedirection();
        app.UseStaticFiles();

        app.UseRouting();

        app.UseAuthorization();

        app.UseEndpoints(endpoints =>
        {
            endpoints.MapRazorPages();
        });
    }
}

For an example of accessing configuration using startup convenience methods, see App startup: Convenience methods.

Access configuration in Razor Pages

The following code displays configuration data in a Razor Page:

@page
@model Test5Model
@using Microsoft.Extensions.Configuration
@inject IConfiguration Configuration

Configuration value for 'MyKey': @Configuration["MyKey"]

In the following code, MyOptions is added to the service container with Configure and bound to configuration:

public void ConfigureServices(IServiceCollection services)
{
    services.Configure<MyOptions>(Configuration.GetSection("MyOptions"));

    services.AddRazorPages();
}

The following markup uses the @inject Razor directive to resolve and display the options values:

@page
@model SampleApp.Pages.Test3Model
@using Microsoft.Extensions.Options
@inject IOptions<MyOptions> optionsAccessor


<p><b>Option1:</b> @optionsAccessor.Value.Option1</p>
<p><b>Option2:</b> @optionsAccessor.Value.Option2</p>

Access configuration in a MVC view file

The following code displays configuration data in a MVC view:

@using Microsoft.Extensions.Configuration
@inject IConfiguration Configuration

Configuration value for 'MyKey': @Configuration["MyKey"]

Configure options with a delegate

Options configured in a delegate override values set in the configuration providers.

Configuring options with a delegate is demonstrated as Example 2 in the sample app.

In the following code, an IConfigureOptions<TOptions> service is added to the service container. It uses a delegate to configure values for MyOptions:

public void ConfigureServices(IServiceCollection services)
{
    services.Configure<MyOptions>(myOptions =>
    {
        myOptions.Option1 = "Value configured in delegate";
        myOptions.Option2 = 500;
    });

    services.AddRazorPages();
}

The following code displays the options values:

public class Test2Model : PageModel
{
    private readonly IOptions<MyOptions> _optionsDelegate;

    public Test2Model(IOptions<MyOptions> optionsDelegate )
    {
        _optionsDelegate = optionsDelegate;
    }

    public ContentResult OnGet()
    {
        return Content($"Option1: {_optionsDelegate.Value.Option1} \n" +
                       $"Option2: {_optionsDelegate.Value.Option2}");
    }
}

In the preceding example, the values of Option1 and Option2 are specified in appsettings.json and then overridden by the configured delegate.

Host versus app configuration

Before the app is configured and started, a host is configured and launched. The host is responsible for app startup and lifetime management. Both the app and the host are configured using the configuration providers described in this topic. Host configuration key-value pairs are also included in the app's configuration. For more information on how the configuration providers are used when the host is built and how configuration sources affect host configuration, see ASP.NET Core fundamentals.

Default host configuration

For details on the default configuration when using the Web Host, see the ASP.NET Core 2.2 version of this topic.

  • Host configuration is provided from:
  • Web Host default configuration is established (ConfigureWebHostDefaults):
    • Kestrel is used as the web server and configured using the app's configuration providers.
    • Add Host Filtering Middleware.
    • Add Forwarded Headers Middleware if the ASPNETCORE_FORWARDEDHEADERS_ENABLED environment variable is set to true.
    • Enable IIS integration.

Other configuration

This topic only pertains to app configuration. Other aspects of running and hosting ASP.NET Core apps are configured using configuration files not covered in this topic:

Environment variables set in launchSettings.json override those set in the system environment.

For more information on migrating app configuration from earlier versions of ASP.NET, see Migrate from ASP.NET to ASP.NET Core.

Add configuration from an external assembly

An IHostingStartup implementation allows adding enhancements to an app at startup from an external assembly outside of the app's Startup class. For more information, see Use hosting startup assemblies in ASP.NET Core.

Additional resources

App configuration in ASP.NET Core is based on key-value pairs established by configuration providers. Configuration providers read configuration data into key-value pairs from a variety of configuration sources:

  • Azure Key Vault
  • Azure App Configuration
  • Command-line arguments
  • Custom providers (installed or created)
  • Directory files
  • Environment variables
  • In-memory .NET objects
  • Settings files

Configuration packages for common configuration provider scenarios (Microsoft.Extensions.Configuration) are included in the Microsoft.AspNetCore.App metapackage.

Code examples that follow and in the sample app use the Microsoft.Extensions.Configuration namespace:

using Microsoft.Extensions.Configuration;

The options pattern is an extension of the configuration concepts described in this topic. Options use classes to represent groups of related settings. For more information, see Options pattern in ASP.NET Core.

View or download sample code (how to download)

Host versus app configuration

Before the app is configured and started, a host is configured and launched. The host is responsible for app startup and lifetime management. Both the app and the host are configured using the configuration providers described in this topic. Host configuration key-value pairs are also included in the app's configuration. For more information on how the configuration providers are used when the host is built and how configuration sources affect host configuration, see ASP.NET Core fundamentals.

Other configuration

This topic only pertains to app configuration. Other aspects of running and hosting ASP.NET Core apps are configured using configuration files not covered in this topic:

For more information on migrating app configuration from earlier versions of ASP.NET, see Migrate from ASP.NET to ASP.NET Core.

Default configuration

Web apps based on the ASP.NET Core dotnet new templates call CreateDefaultBuilder when building a host. CreateDefaultBuilder provides default configuration for the app in the following order:

The following applies to apps using the Web Host. For details on the default configuration when using the Generic Host, see the latest version of this topic.

Security

Adopt the following practices to secure sensitive configuration data:

  • Never store passwords or other sensitive data in configuration provider code or in plain text configuration files.
  • Don't use production secrets in development or test environments.
  • Specify secrets outside of the project so that they can't be accidentally committed to a source code repository.

For more information, see the following topics:

Azure Key Vault safely stores app secrets for ASP.NET Core apps. For more information, see Azure Key Vault Configuration Provider in ASP.NET Core.

Hierarchical configuration data

The Configuration API is capable of maintaining hierarchical configuration data by flattening the hierarchical data with the use of a delimiter in the configuration keys.

In the following JSON file, four keys exist in a structured hierarchy of two sections:

{
  "section0": {
    "key0": "value",
    "key1": "value"
  },
  "section1": {
    "key0": "value",
    "key1": "value"
  }
}

When the file is read into configuration, unique keys are created to maintain the original hierarchical data structure of the configuration source. The sections and keys are flattened with the use of a colon (:) to maintain the original structure:

  • section0:key0
  • section0:key1
  • section1:key0
  • section1:key1

GetSection and GetChildren methods are available to isolate sections and children of a section in the configuration data. These methods are described later in GetSection, GetChildren, and Exists.

Conventions

Sources and providers

At app startup, configuration sources are read in the order that their configuration providers are specified.

Configuration providers that implement change detection have the ability to reload configuration when an underlying setting is changed. For example, the File Configuration Provider (described later in this topic) and the Azure Key Vault Configuration Provider implement change detection.

IConfiguration is available in the app's dependency injection (DI) container. IConfiguration can be injected into a Razor Pages PageModel or MVC Controller to obtain configuration for the class.

In the following examples, the _config field is used to access configuration values:

public class IndexModel : PageModel
{
    private readonly IConfiguration _config;

    public IndexModel(IConfiguration config)
    {
        _config = config;
    }
}
public class HomeController : Controller
{
    private readonly IConfiguration _config;

    public HomeController(IConfiguration config)
    {
        _config = config;
    }
}

Configuration providers can't utilize DI, as it's not available when they're set up by the host.

Keys

Configuration keys adopt the following conventions:

  • Keys are case-insensitive. For example, ConnectionString and connectionstring are treated as equivalent keys.
  • If a value for the same key is set by the same or different configuration providers, the last value set on the key is the value used. For more information on duplicate JSON keys, see this GitHub issue.
  • Hierarchical keys
    • Within the Configuration API, a colon separator (:) works on all platforms.
    • In environment variables, a colon separator may not work on all platforms. A double underscore (__) is supported by all platforms and is automatically converted into a colon.
    • In Azure Key Vault, hierarchical keys use -- (two dashes) as a separator. Write code to replace the dashes with a colon when the secrets are loaded into the app's configuration.
  • The ConfigurationBinder supports binding arrays to objects using array indices in configuration keys. Array binding is described in the Bind an array to a class section.

Values

Configuration values adopt the following conventions:

  • Values are strings.
  • Null values can't be stored in configuration or bound to objects.

Providers

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

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

Configuration sources are read in the order that their configuration providers are specified at startup. The configuration providers described in this topic are described in alphabetical order, not in the order that the code arranges them. Order configuration providers in code to suit the priorities for the underlying configuration sources that the app requires.

A typical sequence of configuration providers is:

  1. Files (appsettings.json, appsettings.{Environment}.json, where {Environment} is the app's current hosting environment)
  2. Azure Key Vault
  3. User secrets (Development environment only)
  4. Environment variables
  5. Command-line arguments

A common practice is to position the Command-line Configuration Provider last in a series of providers to allow command-line arguments to override configuration set by the other providers.

The preceding sequence of providers is used when a new host builder is initialized with CreateDefaultBuilder. For more information, see the Default configuration section.

Configure the host builder with UseConfiguration

To configure the host builder, call UseConfiguration on the host builder with the configuration.

public static IWebHostBuilder CreateWebHostBuilder(string[] args)
{
    var dict = new Dictionary<string, string>
    {
        {"MemoryCollectionKey1", "value1"},
        {"MemoryCollectionKey2", "value2"}
    };

    var config = new ConfigurationBuilder()
        .AddInMemoryCollection(dict)
        .Build();

    return WebHost.CreateDefaultBuilder(args)
        .UseConfiguration(config)
        .UseStartup<Startup>();
}

ConfigureAppConfiguration

Call ConfigureAppConfiguration when building the host to specify the app's configuration providers in addition to those added automatically by CreateDefaultBuilder:

public class Program
{
    public static Dictionary<string, string> arrayDict = 
        new Dictionary<string, string>
        {
            {"array:entries:0", "value0"},
            {"array:entries:1", "value1"},
            {"array:entries:2", "value2"},
            {"array:entries:4", "value4"},
            {"array:entries:5", "value5"}
        };

    public static void Main(string[] args)
    {
        CreateWebHostBuilder(args).Build().Run();
    }

    public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
        WebHost.CreateDefaultBuilder(args)
            .ConfigureAppConfiguration((hostingContext, config) =>
            {
                config.AddInMemoryCollection(arrayDict);
                config.AddJsonFile(
                    "json_array.json", optional: false, reloadOnChange: false);
                config.AddJsonFile(
                    "starship.json", optional: false, reloadOnChange: false);
                config.AddXmlFile(
                    "tvshow.xml", optional: false, reloadOnChange: false);
                config.AddEFConfiguration(
                    options => options.UseInMemoryDatabase("InMemoryDb"));
                config.AddCommandLine(args);
            })
            .UseStartup<Startup>();
}

Override previous configuration with command-line arguments

To provide app configuration that can be overridden with command-line arguments, call AddCommandLine last:

.ConfigureAppConfiguration((hostingContext, config) =>
{
    // Call other providers here
    config.AddCommandLine(args);
})

Remove providers added by CreateDefaultBuilder

To remove the providers added by CreateDefaultBuilder, call Clear on the IConfigurationBuilder.Sources first:

.ConfigureAppConfiguration((hostingContext, config) =>
{
    config.Sources.Clear();
    // Add providers here
})

Consume configuration during app startup

Configuration supplied to the app in ConfigureAppConfiguration is available during the app's startup, including Startup.ConfigureServices. For more information, see the Access configuration during startup section.

Command-line Configuration Provider

The CommandLineConfigurationProvider loads configuration from command-line argument key-value pairs at runtime.

To activate command-line configuration, the AddCommandLine extension method is called on an instance of ConfigurationBuilder.

AddCommandLine is automatically called when CreateDefaultBuilder(string []) is called. For more information, see the Default configuration section.

CreateDefaultBuilder also loads:

  • Optional configuration from appsettings.json and appsettings.{Environment}.json files.
  • User secrets in the Development environment.
  • Environment variables.

CreateDefaultBuilder adds the Command-line Configuration Provider last. Command-line arguments passed at runtime override configuration set by the other providers.

CreateDefaultBuilder acts when the host is constructed. Therefore, command-line configuration activated by CreateDefaultBuilder can affect how the host is configured.

For apps based on the ASP.NET Core templates, AddCommandLine has already been called by CreateDefaultBuilder. To add additional configuration providers and maintain the ability to override configuration from those providers with command-line arguments, call the app's additional providers in ConfigureAppConfiguration and call AddCommandLine last.

.ConfigureAppConfiguration((hostingContext, config) =>
{
    // Call other providers here
    config.AddCommandLine(args);
})

Example

The sample app takes advantage of the static convenience method CreateDefaultBuilder to build the host, which includes a call to AddCommandLine.

  1. Open a command prompt in the project's directory.
  2. Supply a command-line argument to the dotnet run command, dotnet run CommandLineKey=CommandLineValue.
  3. After the app is running, open a browser to the app at http://localhost:5000.
  4. Observe that the output contains the key-value pair for the configuration command-line argument provided to dotnet run.

Arguments

The value must follow an equals sign (=), or the key must have a prefix (-- or /) when the value follows a space. The value isn't required if an equals sign is used (for example, CommandLineKey=).

Key prefix Example
No prefix CommandLineKey1=value1
Two dashes (--) --CommandLineKey2=value2, --CommandLineKey2 value2
Forward slash (/) /CommandLineKey3=value3, /CommandLineKey3 value3

Within the same command, don't mix command-line argument key-value pairs that use an equals sign with key-value pairs that use a space.

Example commands:

dotnet run CommandLineKey1=value1 --CommandLineKey2=value2 /CommandLineKey3=value3
dotnet run --CommandLineKey1 value1 /CommandLineKey2 value2
dotnet run CommandLineKey1= CommandLineKey2=value2

Switch mappings

Switch mappings allow key name replacement logic. When manually building configuration with a ConfigurationBuilder, provide a dictionary of switch replacements to the AddCommandLine method.

When the switch mappings dictionary is used, the dictionary is checked for a key that matches the key provided by a command-line argument. If the command-line key is found in the dictionary, the dictionary value (the key replacement) is passed back to set the key-value pair into the app's configuration. A switch mapping is required for any command-line key prefixed with a single dash (-).

Switch mappings dictionary key rules:

  • Switches must start with a dash (-) or double-dash (--).
  • The switch mappings dictionary must not contain duplicate keys.

Create a switch mappings dictionary. In the following example, two switch mappings are created:

public static readonly Dictionary<string, string> _switchMappings = 
    new Dictionary<string, string>
    {
        { "-CLKey1", "CommandLineKey1" },
        { "-CLKey2", "CommandLineKey2" }
    };

When the host is built, call AddCommandLine with the switch mappings dictionary:

.ConfigureAppConfiguration((hostingContext, config) =>
{
    config.AddCommandLine(args, _switchMappings);
})

For apps that use switch mappings, the call to CreateDefaultBuilder shouldn't pass arguments. The CreateDefaultBuilder method's AddCommandLine call doesn't include mapped switches, and there's no way to pass the switch mapping dictionary to CreateDefaultBuilder. The solution isn't to pass the arguments to CreateDefaultBuilder but instead to allow the ConfigurationBuilder method's AddCommandLine method to process both the arguments and the switch mapping dictionary.

After the switch mappings dictionary is created, it contains the data shown in the following table.

Key Value
-CLKey1 CommandLineKey1
-CLKey2 CommandLineKey2

If the switch-mapped keys are used when starting the app, configuration receives the configuration value on the key supplied by the dictionary:

dotnet run -CLKey1=value1 -CLKey2=value2

After running the preceding command, configuration contains the values shown in the following table.

Key Value
CommandLineKey1 value1
CommandLineKey2 value2

Environment Variables Configuration Provider

The EnvironmentVariablesConfigurationProvider loads configuration from environment variable key-value pairs at runtime.

To activate environment variables configuration, call the AddEnvironmentVariables extension method on an instance of ConfigurationBuilder.

The : separator doesn't work with environment variable hierarchical keys on all platforms. __, the double underscore, is:

  • Supported by all platforms. For example, the : separator is not supported by Bash, but __ is.
  • Automatically replaced by a :

Azure App Service permits setting environment variables in the Azure Portal that can override app configuration using the Environment Variables Configuration Provider. For more information, see Azure Apps: Override app configuration using the Azure Portal.

AddEnvironmentVariables is used to load environment variables prefixed with ASPNETCORE_ for host configuration when a new host builder is initialized with the Web Host and CreateDefaultBuilder is called. For more information, see the Default configuration section.

CreateDefaultBuilder also loads:

  • App configuration from unprefixed environment variables by calling AddEnvironmentVariables without a prefix.
  • Optional configuration from appsettings.json and appsettings.{Environment}.json files.
  • User secrets in the Development environment.
  • Command-line arguments.

The Environment Variables Configuration Provider is called after configuration is established from user secrets and appsettings files. Calling the provider in this position allows the environment variables read at runtime to override configuration set by user secrets and appsettings files.

To provide app configuration from additional environment variables, call the app's additional providers in ConfigureAppConfiguration and call AddEnvironmentVariables with the prefix:

.ConfigureAppConfiguration((hostingContext, config) =>
{
    config.AddEnvironmentVariables(prefix: "PREFIX_");
})

Call AddEnvironmentVariables last to allow environment variables with the given prefix to override values from other providers.

Example

The sample app takes advantage of the static convenience method CreateDefaultBuilder to build the host, which includes a call to AddEnvironmentVariables.

  1. Run the sample app. Open a browser to the app at http://localhost:5000.
  2. Observe that the output contains the key-value pair for the environment variable ENVIRONMENT. The value reflects the environment in which the app is running, typically Development when running locally.

To keep the list of environment variables rendered by the app short, the app filters environment variables. See the sample app's Pages/Index.cshtml.cs file.

To expose all of the environment variables available to the app, change the FilteredConfiguration in Pages/Index.cshtml.cs to the following:

FilteredConfiguration = _config.AsEnumerable();

Prefixes

Environment variables loaded into the app's configuration are filtered when supplying a prefix to the AddEnvironmentVariables method. For example, to filter environment variables on the prefix CUSTOM_, supply the prefix to the configuration provider:

var config = new ConfigurationBuilder()
    .AddEnvironmentVariables("CUSTOM_")
    .Build();

The prefix is stripped off when the configuration key-value pairs are created.

When the host builder is created, host configuration is provided by environment variables. For more information on the prefix used for these environment variables, see the Default configuration section.

Connection string prefixes

The Configuration API has special processing rules for four connection string environment variables involved in configuring Azure connection strings for the app environment. Environment variables with the prefixes shown in the table are loaded into the app if no prefix is supplied to AddEnvironmentVariables.

Connection string prefix Provider
CUSTOMCONNSTR_ Custom provider
MYSQLCONNSTR_ MySQL
SQLAZURECONNSTR_ Azure SQL Database
SQLCONNSTR_ SQL Server

When an environment variable is discovered and loaded into configuration with any of the four prefixes shown in the table:

  • The configuration key is created by removing the environment variable prefix and adding a configuration key section (ConnectionStrings).
  • A new configuration key-value pair is created that represents the database connection provider (except for CUSTOMCONNSTR_, which has no stated provider).
Environment variable key Converted configuration key Provider configuration entry
CUSTOMCONNSTR_{KEY} ConnectionStrings:{KEY} Configuration entry not created.
MYSQLCONNSTR_{KEY} ConnectionStrings:{KEY} Key: ConnectionStrings:{KEY}_ProviderName:
Value: MySql.Data.MySqlClient
SQLAZURECONNSTR_{KEY} ConnectionStrings:{KEY} Key: ConnectionStrings:{KEY}_ProviderName:
Value: System.Data.SqlClient
SQLCONNSTR_{KEY} ConnectionStrings:{KEY} Key: ConnectionStrings:{KEY}_ProviderName:
Value: System.Data.SqlClient

Example

A custom connection string environment variable is created on the server:

  • Name: CUSTOMCONNSTR_ReleaseDB
  • Value: Data Source=ReleaseSQLServer;Initial Catalog=MyReleaseDB;Integrated Security=True

If IConfiguration is injected and assigned to a field named _config, read the value:

_config["ConnectionStrings:ReleaseDB"]

File Configuration Provider

FileConfigurationProvider is the base class for loading configuration from the file system. The following configuration providers are dedicated to specific file types:

INI Configuration Provider

The IniConfigurationProvider loads configuration from INI file key-value pairs at runtime.

To activate INI file configuration, call the AddIniFile extension method on an instance of ConfigurationBuilder.

The colon can be used to as a section delimiter in INI file configuration.

Overloads permit specifying:

  • Whether the file is optional.
  • Whether the configuration is reloaded if the file changes.
  • The IFileProvider used to access the file.

Call ConfigureAppConfiguration when building the host to specify the app's configuration:

.ConfigureAppConfiguration((hostingContext, config) =>
{
    config.AddIniFile(
        "config.ini", optional: true, reloadOnChange: true);
})

A generic example of an INI configuration file:

[section0]
key0=value
key1=value

[section1]
subsection:key=value

[section2:subsection0]
key=value

[section2:subsection1]
key=value

The previous configuration file loads the following keys with value:

  • section0:key0
  • section0:key1
  • section1:subsection:key
  • section2:subsection0:key
  • section2:subsection1:key

JSON Configuration Provider

The JsonConfigurationProvider loads configuration from JSON file key-value pairs during runtime.

To activate JSON file configuration, call the AddJsonFile extension method on an instance of ConfigurationBuilder.

Overloads permit specifying:

  • Whether the file is optional.
  • Whether the configuration is reloaded if the file changes.
  • The IFileProvider used to access the file.

AddJsonFile is automatically called twice when a new host builder is initialized with CreateDefaultBuilder. The method is called to load configuration from:

  • appsettings.json: This file is read first. The environment version of the file can override the values provided by the appsettings.json file.
  • appsettings.{Environment}.json: The environment version of the file is loaded based on the IHostingEnvironment.EnvironmentName.

For more information, see the Default configuration section.

CreateDefaultBuilder also loads:

  • Environment variables.
  • User secrets in the Development environment.
  • Command-line arguments.

The JSON Configuration Provider is established first. Therefore, user secrets, environment variables, and command-line arguments override configuration set by the appsettings files.

Call ConfigureAppConfiguration when building the host to specify the app's configuration for files other than appsettings.json and appsettings.{Environment}.json:

.ConfigureAppConfiguration((hostingContext, config) =>
{
    config.AddJsonFile(
        "config.json", optional: true, reloadOnChange: true);
})

Example

The sample app takes advantage of the static convenience method CreateDefaultBuilder to build the host, which includes two calls to AddJsonFile:

  • The first call to AddJsonFile loads configuration from appsettings.json:

    {
      "Logging": {
        "LogLevel": {
          "Default": "Warning"
        }
      },
      "AllowedHosts": "*"
    }
    
  • The second call to AddJsonFile loads configuration from appsettings.{Environment}.json. For appsettings.Development.json in the sample app, the following file is loaded:

    {
      "Logging": {
        "LogLevel": {
          "Default": "Debug",
          "System": "Information",
          "Microsoft": "Information"
        }
      }
    }
    
  1. Run the sample app. Open a browser to the app at http://localhost:5000.
  2. The output contains key-value pairs for the configuration based on the app's environment. The log level for the key Logging:LogLevel:Default is Debug when running the app in the Development environment.
  3. Run the sample app again in the Production environment:
    1. Open the Properties/launchSettings.json file.
    2. In the ConfigurationSample profile, change the value of the ASPNETCORE_ENVIRONMENT environment variable to Production.
    3. Save the file and run the app with dotnet run in a command shell.
  4. The settings in the appsettings.Development.json no longer override the settings in appsettings.json. The log level for the key Logging:LogLevel:Default is Warning.

XML Configuration Provider

The XmlConfigurationProvider loads configuration from XML file key-value pairs at runtime.

To activate XML file configuration, call the AddXmlFile extension method on an instance of ConfigurationBuilder.

Overloads permit specifying:

  • Whether the file is optional.
  • Whether the configuration is reloaded if the file changes.
  • The IFileProvider used to access the file.

The root node of the configuration file is ignored when the configuration key-value pairs are created. Don't specify a Document Type Definition (DTD) or namespace in the file.

Call ConfigureAppConfiguration when building the host to specify the app's configuration:

.ConfigureAppConfiguration((hostingContext, config) =>
{
    config.AddXmlFile(
        "config.xml", optional: true, reloadOnChange: true);
})

XML configuration files can use distinct element names for repeating sections:

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
  <section0>
    <key0>value</key0>
    <key1>value</key1>
  </section0>
  <section1>
    <key0>value</key0>
    <key1>value</key1>
  </section1>
</configuration>

The previous configuration file loads the following keys with value:

  • section0:key0
  • section0:key1
  • section1:key0
  • section1:key1

Repeating elements that use the same element name work if the name attribute is used to distinguish the elements:

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
  <section name="section0">
    <key name="key0">value</key>
    <key name="key1">value</key>
  </section>
  <section name="section1">
    <key name="key0">value</key>
    <key name="key1">value</key>
  </section>
</configuration>

The previous configuration file loads the following keys with value:

  • section:section0:key:key0
  • section:section0:key:key1
  • section:section1:key:key0
  • section:section1:key:key1

Attributes can be used to supply values:

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
  <key attribute="value" />
  <section>
    <key attribute="value" />
  </section>
</configuration>

The previous configuration file loads the following keys with value:

  • key:attribute
  • section:key:attribute

Key-per-file Configuration Provider

The KeyPerFileConfigurationProvider uses a directory's files as configuration key-value pairs. The key is the file name. The value contains the file's contents. The Key-per-file Configuration Provider is used in Docker hosting scenarios.

To activate key-per-file configuration, call the AddKeyPerFile extension method on an instance of ConfigurationBuilder. The directoryPath to the files must be an absolute path.

Overloads permit specifying:

  • An Action<KeyPerFileConfigurationSource> delegate that configures the source.
  • Whether the directory is optional and the path to the directory.

The double-underscore (__) is used as a configuration key delimiter in file names. For example, the file name Logging__LogLevel__System produces the configuration key Logging:LogLevel:System.

Call ConfigureAppConfiguration when building the host to specify the app's configuration:

.ConfigureAppConfiguration((hostingContext, config) =>
{
    var path = Path.Combine(
        Directory.GetCurrentDirectory(), "path/to/files");
    config.AddKeyPerFile(directoryPath: path, optional: true);
})

Memory Configuration Provider

The MemoryConfigurationProvider uses an in-memory collection as configuration key-value pairs.

To activate in-memory collection configuration, call the AddInMemoryCollection extension method on an instance of ConfigurationBuilder.

The configuration provider can be initialized with an IEnumerable<KeyValuePair<String,String>>.

Call ConfigureAppConfiguration when building the host to specify the app's configuration.

In the following example, a configuration dictionary is created:

public static readonly Dictionary<string, string> _dict = 
    new Dictionary<string, string>
    {
        {"MemoryCollectionKey1", "value1"},
        {"MemoryCollectionKey2", "value2"}
    };

The dictionary is used with a call to AddInMemoryCollection to provide the configuration:

.ConfigureAppConfiguration((hostingContext, config) =>
{
    config.AddInMemoryCollection(_dict);
})

GetValue

ConfigurationBinder.GetValue<T> extracts a single value from configuration with a specified key and converts it to the specified noncollection type. An overload accepts a default value.

The following example:

  • Extracts the string value from configuration with the key NumberKey. If NumberKey isn't found in the configuration keys, the default value of 99 is used.
  • Types the value as an int.
  • Stores the value in the NumberConfig property for use by the page.
public class IndexModel : PageModel
{
    public IndexModel(IConfiguration config)
    {
        _config = config;
    }

    public int NumberConfig { get; private set; }

    public void OnGet()
    {
        NumberConfig = _config.GetValue<int>("NumberKey", 99);
    }
}

GetSection, GetChildren, and Exists

For the examples that follow, consider the following JSON file. Four keys are found across two sections, one of which includes a pair of subsections:

{
  "section0": {
    "key0": "value",
    "key1": "value"
  },
  "section1": {
    "key0": "value",
    "key1": "value"
  },
  "section2": {
    "subsection0" : {
      "key0": "value",
      "key1": "value"
    },
    "subsection1" : {
      "key0": "value",
      "key1": "value"
    }
  }
}

When the file is read into configuration, the following unique hierarchical keys are created to hold the configuration values:

  • section0:key0
  • section0:key1
  • section1:key0
  • section1:key1
  • section2:subsection0:key0
  • section2:subsection0:key1
  • section2:subsection1:key0
  • section2:subsection1:key1

GetSection

IConfiguration.GetSection extracts a configuration subsection with the specified subsection key.

To return an IConfigurationSection containing only the key-value pairs in section1, call GetSection and supply the section name:

var configSection = _config.GetSection("section1");

The configSection doesn't have a value, only a key and a path.

Similarly, to obtain the values for keys in section2:subsection0, call GetSection and supply the section path:

var configSection = _config.GetSection("section2:subsection0");

GetSection never returns null. If a matching section isn't found, an empty IConfigurationSection is returned.

When GetSection returns a matching section, Value isn't populated. A Key and Path are returned when the section exists.

GetChildren

A call to IConfiguration.GetChildren on section2 obtains an IEnumerable<IConfigurationSection> that includes:

  • subsection0
  • subsection1
var configSection = _config.GetSection("section2");

var children = configSection.GetChildren();

Exists

Use ConfigurationExtensions.Exists to determine if a configuration section exists:

var sectionExists = _config.GetSection("section2:subsection2").Exists();

Given the example data, sectionExists is false because there isn't a section2:subsection2 section in the configuration data.

Bind to an object graph

Bind is capable of binding an entire POCO object graph. As with binding a simple object, only public read/write properties are bound.

The sample contains a TvShow model whose object graph includes Metadata and Actors classes (Models/TvShow.cs):

public class TvShow
{
    public Metadata Metadata { get; set; }
    public Actors Actors { get; set; }
    public string Legal { get; set; }
}

public class Metadata
{
    public string Series { get; set; }
    public string Title { get; set; }
    public DateTime AirDate { get; set; }
    public int Episodes { get; set; }
}

public class Actors
{
    public string Names { get; set; }
}

The sample app has a tvshow.xml file containing the configuration data:

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
  <tvshow>
    <metadata>
      <series>Dr. Who</series>
      <title>The Sun Makers</title>
      <airdate>11/26/1977</airdate>
      <episodes>4</episodes>
    </metadata>
    <actors>
      <names>Tom Baker, Louise Jameson, John Leeson</names>
    </actors>
    <legal>(c)1977 BBC https://www.bbc.co.uk/programmes/b006q2x0</legal>
  </tvshow>
</configuration>

Configuration is bound to the entire TvShow object graph with the Bind method. The bound instance is assigned to a property for rendering:

var tvShow = new TvShow();
_config.GetSection("tvshow").Bind(tvShow);
TvShow = tvShow;

ConfigurationBinder.Get<T> binds and returns the specified type. Get<T> is more convenient than using Bind. The following code shows how to use Get<T> with the preceding example:

TvShow = _config.GetSection("tvshow").Get<TvShow>();

Bind an array to a class

The sample app demonstrates the concepts explained in this section.

The Bind supports binding arrays to objects using array indices in configuration keys. Any array format that exposes a numeric key segment (:0:, :1:, … :{n}:) is capable of array binding to a POCO class array.

Note

Binding is provided by convention. Custom configuration providers aren't required to implement array binding.

In-memory array processing

Consider the configuration keys and values shown in the following table.

Key Value
array:entries:0 value0
array:entries:1 value1
array:entries:2 value2
array:entries:4 value4
array:entries:5 value5

These keys and values are loaded in the sample app using the Memory Configuration Provider:

public class Program
{
    public static Dictionary<string, string> arrayDict = 
        new Dictionary<string, string>
        {
            {"array:entries:0", "value0"},
            {"array:entries:1", "value1"},
            {"array:entries:2", "value2"},
            {"array:entries:4", "value4"},
            {"array:entries:5", "value5"}
        };

    public static void Main(string[] args)
    {
        CreateWebHostBuilder(args).Build().Run();
    }

    public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
        WebHost.CreateDefaultBuilder(args)
            .ConfigureAppConfiguration((hostingContext, config) =>
            {
                config.AddInMemoryCollection(arrayDict);
                config.AddJsonFile(
                    "json_array.json", optional: false, reloadOnChange: false);
                config.AddJsonFile(
                    "starship.json", optional: false, reloadOnChange: false);
                config.AddXmlFile(
                    "tvshow.xml", optional: false, reloadOnChange: false);
                config.AddEFConfiguration(
                    options => options.UseInMemoryDatabase("InMemoryDb"));
                config.AddCommandLine(args);
            })
            .UseStartup<Startup>();
}

The array skips a value for index #3. The configuration binder isn't capable of binding null values or creating null entries in bound objects, which becomes clear in a moment when the result of binding this array to an object is demonstrated.

In the sample app, a POCO class is available to hold the bound configuration data:

public class ArrayExample
{
    public string[] Entries { get; set; }
}

The configuration data is bound to the object:

var arrayExample = new ArrayExample();
_config.GetSection("array").Bind(arrayExample);

ConfigurationBinder.Get<T> syntax can also be used, which results in more compact code:

ArrayExample = _config.GetSection("array").Get<ArrayExample>();

The bound object, an instance of ArrayExample, receives the array data from configuration.

ArrayExample.Entries Index ArrayExample.Entries Value
0 value0
1 value1
2 value2
3 value4
4 value5

Index #3 in the bound object holds the configuration data for the array:4 configuration key and its value of value4. When configuration data containing an array is bound, the array indices in the configuration keys are merely used to iterate the configuration data when creating the object. A null value can't be retained in configuration data, and a null-valued entry isn't created in a bound object when an array in configuration keys skip one or more indices.

The missing configuration item for index #3 can be supplied before binding to the ArrayExample instance by any configuration provider that produces the correct key-value pair in configuration. If the sample included an additional JSON Configuration Provider with the missing key-value pair, the ArrayExample.Entries matches the complete configuration array:

missing_value.json:

{
  "array:entries:3": "value3"
}

In ConfigureAppConfiguration:

config.AddJsonFile(
    "missing_value.json", optional: false, reloadOnChange: false);

The key-value pair shown in the table is loaded into configuration.

Key Value
array:entries:3 value3

If the ArrayExample class instance is bound after the JSON Configuration Provider includes the entry for index #3, the ArrayExample.Entries array includes the value.

ArrayExample.Entries Index ArrayExample.Entries Value
0 value0
1 value1
2 value2
3 value3
4 value4
5 value5

JSON array processing

If a JSON file contains an array, configuration keys are created for the array elements with a zero-based section index. In the following configuration file, subsection is an array:

{
  "json_array": {
    "key": "valueA",
    "subsection": [
      "valueB",
      "valueC",
      "valueD"
    ]
  }
}

The JSON Configuration Provider reads the configuration data into the following key-value pairs:

Key Value
json_array:key valueA
json_array:subsection:0 valueB
json_array:subsection:1 valueC
json_array:subsection:2 valueD

In the sample app, the following POCO class is available to bind the configuration key-value pairs:

public class JsonArrayExample
{
    public string Key { get; set; }
    public string[] Subsection { get; set; }
}

After binding, JsonArrayExample.Key holds the value valueA. The subsection values are stored in the POCO array property, Subsection.

JsonArrayExample.Subsection Index JsonArrayExample.Subsection Value
0 valueB
1 valueC
2 valueD

Custom configuration provider

The sample app demonstrates how to create a basic configuration provider that reads configuration key-value pairs from a database using Entity Framework (EF).

The provider has the following characteristics:

  • The EF in-memory database is used for demonstration purposes. To use a database that requires a connection string, implement a secondary ConfigurationBuilder to supply the connection string from another configuration provider.
  • The provider reads a database table into configuration at startup. The provider doesn't query the database on a per-key basis.
  • Reload-on-change isn't implemented, so updating the database after the app starts has no effect on the app's configuration.

Define an EFConfigurationValue entity for storing configuration values in the database.

Models/EFConfigurationValue.cs:

public class EFConfigurationValue
{
    public string Id { get; set; }
    public string Value { get; set; }
}

Add an EFConfigurationContext to store and access the configured values.

EFConfigurationProvider/EFConfigurationContext.cs:

public class EFConfigurationContext : DbContext
{
    public EFConfigurationContext(DbContextOptions options) : base(options)
    {
    }

    public DbSet<EFConfigurationValue> Values { get; set; }
}

Create a class that implements IConfigurationSource.

EFConfigurationProvider/EFConfigurationSource.cs:

public class EFConfigurationSource : IConfigurationSource
{
    private readonly Action<DbContextOptionsBuilder> _optionsAction;

    public EFConfigurationSource(Action<DbContextOptionsBuilder> optionsAction)
    {
        _optionsAction = optionsAction;
    }

    public IConfigurationProvider Build(IConfigurationBuilder builder)
    {
        return new EFConfigurationProvider(_optionsAction);
    }
}

Create the custom configuration provider by inheriting from ConfigurationProvider. The configuration provider initializes the database when it's empty.

EFConfigurationProvider/EFConfigurationProvider.cs:

public class EFConfigurationProvider : ConfigurationProvider
{
    public EFConfigurationProvider(Action<DbContextOptionsBuilder> optionsAction)
    {
        OptionsAction = optionsAction;
    }

    Action<DbContextOptionsBuilder> OptionsAction { get; }

    // Load config data from EF DB.
    public override void Load()
    {
        var builder = new DbContextOptionsBuilder<EFConfigurationContext>();

        OptionsAction(builder);

        using (var dbContext = new EFConfigurationContext(builder.Options))
        {
            dbContext.Database.EnsureCreated();

            Data = !dbContext.Values.Any()
                ? CreateAndSaveDefaultValues(dbContext)
                : dbContext.Values.ToDictionary(c => c.Id, c => c.Value);
        }
    }

    private static IDictionary<string, string> CreateAndSaveDefaultValues(
        EFConfigurationContext dbContext)
    {
        // Quotes (c)2005 Universal Pictures: Serenity
        // https://www.uphe.com/movies/serenity
        var configValues = 
            new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
            {
                { "quote1", "I aim to misbehave." },
                { "quote2", "I swallowed a bug." },
                { "quote3", "You can't stop the signal, Mal." }
            };

        dbContext.Values.AddRange(configValues
            .Select(kvp => new EFConfigurationValue 
                {
                    Id = kvp.Key,
                    Value = kvp.Value
                })
            .ToArray());

        dbContext.SaveChanges();

        return configValues;
    }
}

An AddEFConfiguration extension method permits adding the configuration source to a ConfigurationBuilder.

Extensions/EntityFrameworkExtensions.cs:

public static class EntityFrameworkExtensions
{
    public static IConfigurationBuilder AddEFConfiguration(
        this IConfigurationBuilder builder, 
        Action<DbContextOptionsBuilder> optionsAction)
    {
        return builder.Add(new EFConfigurationSource(optionsAction));
    }
}

The following code shows how to use the custom EFConfigurationProvider in Program.cs:

public class Program
{
    public static Dictionary<string, string> arrayDict = 
        new Dictionary<string, string>
        {
            {"array:entries:0", "value0"},
            {"array:entries:1", "value1"},
            {"array:entries:2", "value2"},
            {"array:entries:4", "value4"},
            {"array:entries:5", "value5"}
        };

    public static void Main(string[] args)
    {
        CreateWebHostBuilder(args).Build().Run();
    }

    public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
        WebHost.CreateDefaultBuilder(args)
            .ConfigureAppConfiguration((hostingContext, config) =>
            {
                config.AddInMemoryCollection(arrayDict);
                config.AddJsonFile(
                    "json_array.json", optional: false, reloadOnChange: false);
                config.AddJsonFile(
                    "starship.json", optional: false, reloadOnChange: false);
                config.AddXmlFile(
                    "tvshow.xml", optional: false, reloadOnChange: false);
                config.AddEFConfiguration(
                    options => options.UseInMemoryDatabase("InMemoryDb"));
                config.AddCommandLine(args);
            })
            .UseStartup<Startup>();
}

Access configuration during startup

Inject IConfiguration into the Startup constructor to access configuration values in Startup.ConfigureServices. To access configuration in Startup.Configure, either inject IConfiguration directly into the method or use the instance from the constructor:

public class Startup
{
    private readonly IConfiguration _config;

    public Startup(IConfiguration config)
    {
        _config = config;
    }

    public void ConfigureServices(IServiceCollection services)
    {
        var value = _config["key"];
    }

    public void Configure(IApplicationBuilder app, IConfiguration config)
    {
        var value = config["key"];
    }
}

For an example of accessing configuration using startup convenience methods, see App startup: Convenience methods.

Access configuration in a Razor Pages page or MVC view

To access configuration settings in a Razor Pages page or an MVC view, add a using directive (C# reference: using directive) for the Microsoft.Extensions.Configuration namespace and inject IConfiguration into the page or view.

In a Razor Pages page:

@page
@model IndexModel
@using Microsoft.Extensions.Configuration
@inject IConfiguration Configuration

<!DOCTYPE html>
<html lang="en">
<head>
    <title>Index Page</title>
</head>
<body>
    <h1>Access configuration in a Razor Pages page</h1>
    <p>Configuration value for 'key': @Configuration["key"]</p>
</body>
</html>

In an MVC view:

@using Microsoft.Extensions.Configuration
@inject IConfiguration Configuration

<!DOCTYPE html>
<html lang="en">
<head>
    <title>Index View</title>
</head>
<body>
    <h1>Access configuration in an MVC view</h1>
    <p>Configuration value for 'key': @Configuration["key"]</p>
</body>
</html>

Add configuration from an external assembly

An IHostingStartup implementation allows adding enhancements to an app at startup from an external assembly outside of the app's Startup class. For more information, see Use hosting startup assemblies in ASP.NET Core.

Additional resources