24 KiB
title | author | description | keywords | ms.author | manager | ms.date | ms.topic | ms.assetid | ms.technology | ms.prod | uid |
---|---|---|---|---|---|---|---|---|---|---|---|
Configuration in ASP.NET Core | rick-anderson | Learn how to use the Configuration API to configure an ASP.NET Core app from multiple sources. | ASP.NET Core,configuration,JSON,config | riande | wpickett | 6/24/2017 | article | b3a5984d-e172-42eb-8a48-547e4acb6806 | aspnet | asp.net-core | fundamentals/configuration |
Configuration in ASP.NET Core
Rick Anderson, Mark Michaelis, Steve Smith, Daniel Roth, and Luke Latham
The Configuration API provides a way of configuring an app based on a list of name-value pairs. Configuration is read at runtime from multiple sources. The name-value pairs can be grouped into a multi-level hierarchy. There are configuration providers for:
- File formats (INI, JSON, and XML)
- Command-line arguments
- Environment variables
- In-memory .NET objects
- An encrypted user store
- Azure Key Vault
- Custom providers, which you install or create
Each configuration value maps to a string key. There's built-in binding support to deserialize settings into a custom POCO object (a simple .NET class with properties).
View or download sample code (how to download)
Simple configuration
The following console app uses the JSON configuration provider:
[!code-csharpMain]
The app reads and displays the following configuration settings:
[!code-jsonMain]
Configuration consists of a hierarchical list of name-value pairs in which the nodes are separated by a colon. To retrieve a value, access the Configuration
indexer with the corresponding item's key:
Console.WriteLine($"option1 = {Configuration["subsection:suboption1"]}");
To work with arrays in JSON-formatted configuration sources, use a array index as part of the colon-separated string. The following example gets the name of the first item in the preceding wizards
array:
Console.Write($"{Configuration["wizards:0:Name"]}, ");
Name-value pairs written to the built in Configuration
providers are not persisted, however, you can create a custom provider that saves values. See custom configuration provider.
The preceding sample uses the configuration indexer to read values. To access configuration outside of Startup
, use the options pattern. The options pattern is shown later in this article.
It's typical to have different configuration settings for different environments, for example, development, test, and production. The CreateDefaultBuilder
extension method in an ASP.NET Core 2.x app (or using AddJsonFile
and AddEnvironmentVariables
directly in an ASP.NET Core 1.x app) adds configuration providers for reading JSON files and system configuration sources:
- appsettings.json
- appsettings.<EnvironmentName>.json
- environment variables
See AddJsonFile for an explanation of the parameters. reloadOnChange
is only supported in ASP.NET Core 1.1 and higher.
Configuration sources are read in the order they are specified. In the code above, the environment variables are read last. Any configuration values set through the environment would replace those set in the two previous providers.
The environment is typically set to one of Development
, Staging
, or Production
. See Working with Multiple Environments for more information.
Configuration considerations:
IOptionsSnapshot
can reload configuration data when it changes. UseIOptionsSnapshot
if you need to reload configuration data. See IOptionsSnapshot for more information.- Configuration keys are case insensitive.
- A best practice is to specify environment variables last, so that the local environment can override anything set in deployed configuration files.
- Never store passwords or other sensitive data in configuration provider code or in plain text configuration files. Don't use production secrets in your development or test environments. Instead, specify secrets outside the project tree, so they cannot be accidentally committed into your repository. Learn more about Working with Multiple Environments and managing safe storage of app secrets during development.
- If
:
cannot be used in environment variables in your system, replace:
with__
(double underscore).
Using Options and configuration objects
The options pattern uses custom options classes to represent a group of related settings. We recommended that you create decoupled classes for each feature within your app. Decoupled classes follow:
- The Interface Segregation Principle (ISP) : Classes depend only on the configuration settings they use.
- Separation of Concerns : Settings for different parts of your app are not dependent or coupled with one another.
The options class must be non-abstract with a public parameterless constructor. For example:
[!code-csharpMain]
In the following code, the JSON configuration provider is enabled. The MyOptions
class is added to the service container and bound to configuration.
[!code-csharpMain]
The following controller uses constructor Dependency Injection on IOptions<TOptions>
to access settings:
[!code-csharpMain]
With the following appsettings.json file:
[!code-jsonMain]
The HomeController.Index
method returns option1 = value1_from_json, option2 = 2
.
Typical apps won't bind the entire configuration to a single options file. Later on I'll show how to use GetSection
to bind to a section.
In the following code, a second IConfigureOptions<TOptions>
service is added to the service container. It uses a delegate to configure the binding with MyOptions
.
[!code-csharpMain]
You can add multiple configuration providers. Configuration providers are available in NuGet packages. They are applied in order they are registered.
Each call to Configure<TOptions>
adds an IConfigureOptions<TOptions>
service to the service container. In the preceding example, the values of Option1
and Option2
are both specified in appsettings.json -- but the value of Option1
is overridden by the configured delegate.
When more than one configuration service is enabled, the last configuration source specified "wins" (sets the configuration value). In the preceding code, the HomeController.Index
method returns option1 = value1_from_action, option2 = 2
.
When you bind options to configuration, each property in your options type is bound to a configuration key of the form property[:sub-property:]
. For example, the MyOptions.Option1
property is bound to the key Option1
, which is read from the option1
property in appsettings.json. A sub-property sample is shown later in this article.
In the following code, a third IConfigureOptions<TOptions>
service is added to the service container. It binds MySubOptions
to the section subsection
of the appsettings.json file:
[!code-csharpMain]
Note: This extension method requires the Microsoft.Extensions.Options.ConfigurationExtensions
NuGet package.
Using the following appsettings.json file:
[!code-jsonMain]
The MySubOptions
class:
[!code-csharpMain]
With the following Controller
:
[!code-csharpMain]
subOption1 = subvalue1_from_json, subOption2 = 200
is returned.
You can also supply options in a view model or inject IOptions<TOptions>
directly into a view:
[!code-htmlMain]
IOptionsSnapshot
Requires ASP.NET Core 1.1 or higher.
IOptionsSnapshot
supports reloading configuration data when the configuration file has changed. It has minimal overhead. Using IOptionsSnapshot
with reloadOnChange: true
, the options are bound to IConfiguration
and reloaded when changed.
The following sample demonstrates how a new IOptionsSnapshot
is created after config.json changes. Requests to the server will return the same time when config.json has not changed. The first request after config.json changes will show a new time.
[!code-csharpMain]
The following image shows the server output:
Refreshing the browser doesn't change the message value or time displayed (when config.json has not changed).
Change and save the config.json and then refresh the browser:
In-memory provider and binding to a POCO class
The following sample shows how to use the in-memory provider and bind to a class:
[!code-csharpMain]
Configuration values are returned as strings, but binding enables the construction of objects. Binding allows you to retrieve POCO objects or even entire object graphs. The following sample shows how to bind to MyWindow
and use the options pattern with a ASP.NET Core MVC app:
[!code-csharpMain]
[!code-jsonMain]
Bind the custom class in ConfigureServices
when building the host:
[!code-csharpMain]
Display the settings from the HomeController
:
[!code-csharpMain]
GetValue
The following sample demonstrates the GetValue extension method:
[!code-csharpMain]
The ConfigurationBinder's GetValue<T>
method allows you to specify a default value (80 in the sample). GetValue<T>
is for simple scenarios and does not bind to entire sections. GetValue<T>
gets scalar values from GetSection(key).Value
converted to a specific type.
Binding to an object graph
You can recursively bind to each object in a class. Consider the following AppOptions
class:
[!code-csharpMain]
The following sample binds to the AppOptions
class:
[!code-csharpMain]
ASP.NET Core 1.1 and higher can use Get<T>
, which works with entire sections. Get<T>
can be more convienent than using Bind
. The following code shows how to use Get<T>
with the sample above:
var appConfig = config.GetSection("App").Get<AppOptions>();
Using the following appsettings.json file:
[!code-jsonMain]
The program displays Height 11
.
The following code can be used to unit test the configuration:
[Fact]
public void CanBindObjectTree()
{
var dict = new Dictionary<string, string>
{
{"App:Profile:Machine", "Rick"},
{"App:Connection:Value", "connectionstring"},
{"App:Window:Height", "11"},
{"App:Window:Width", "11"}
};
var builder = new ConfigurationBuilder();
builder.AddInMemoryCollection(dict);
var config = builder.Build();
var options = new AppOptions();
config.GetSection("App").Bind(options);
Assert.Equal("Rick", options.Profile.Machine);
Assert.Equal(11, options.Window.Height);
Assert.Equal(11, options.Window.Width);
Assert.Equal("connectionstring", options.Connection.Value);
}
Basic sample of Entity Framework custom provider
In this section, a basic configuration provider that reads name-value pairs from a database using EF is created.
Define a ConfigurationValue
entity for storing configuration values in the database:
[!code-csharpMain]
Add a ConfigurationContext
to store and access the configured values:
[!code-csharpMain]
Create an class that implements IConfigurationSource:
[!code-csharpMain]
Create the custom configuration provider by inheriting from ConfigurationProvider. The configuration provider initializes the database when it's empty:
[!code-csharpMain]
The highlighted values from the database ("value_from_ef_1" and "value_from_ef_2") are displayed when the sample is run.
You can add an EFConfigSource
extension method for adding the configuration source:
[!code-csharpMain]
The following code shows how to use the custom EFConfigProvider
:
[!code-csharpMain]
Note the sample adds the custom EFConfigProvider
after the JSON provider, so any settings from the database will override settings from the appsettings.json file.
Using the following appsettings.json file:
[!code-jsonMain]
The following is displayed:
key1=value_from_ef_1
key2=value_from_ef_2
key3=value_from_json_3
CommandLine configuration provider
The CommandLine configuration provider receives command-line argument key-value pairs for configuration at runtime.
View or download the CommandLine configuration sample
Setting up the provider
Basic Configuration
To activate command-line configuration, call the AddCommandLine
extension method on an instance of ConfigurationBuilder:
[!code-csharpMain]
Running the code, the following output is displayed:
MachineName: MairaPC
Left: 1980
Passing argument key-value pairs on the command line changes the values of Profile:MachineName
and App:MainWindow:Left
:
dotnet run Profile:MachineName=BartPC App:MainWindow:Left=1979
The console window displays:
MachineName: BartPC
Left: 1979
To override configuration provided by other configuration providers with command-line configuration, call AddCommandLine
last on ConfigurationBuilder
:
[!code-csharpMain]
ASP.NET Core 2.x
Typical ASP.NET Core 2.x apps use the static convenience method CreateDefaultBuilder
to build the host:
[!code-csharpMain]
CreateDefaultBuilder
loads optional configuration from appsettings.json, appsettings.{Environment}.json, user secrets (in the Development
environment), environment variables, and command-line arguments. The CommandLine configuration provider is called last. Calling the provider last allows the command-line arguments passed at runtime to override configuration set by the other configuration providers called earlier.
Note that for appsettings files that reloadOnChange
is enabled. Command-line arguments are overridden if a matching configuration value in an appsettings file is changed after the app starts.
[!NOTE] As an alternative to using the
CreateDefaultBuilder
method, creating a host using WebHostBuilder and manually building configuration with ConfigurationBuilder is supported in ASP.NET Core 2.x. See the ASP.NET Core 1.x tab for more information.
ASP.NET Core 1.x
Create a ConfigurationBuilder and call the AddCommandLine
method to use the CommandLine configuration provider. Calling the provider last allows the command-line arguments passed at runtime to override configuration set by the other configuration providers called earlier. Apply the configuration to WebHostBuilder with the UseConfiguration
method:
[!code-csharpMain]
Arguments
Arguments passed on the command line must conform to one of two formats shown in the following table.
Argument format | Example |
---|---|
Single argument: a key-value pair separated by an equals sign (= ) |
key1=value |
Sequence of two arguments: a key-value pair separated by a space | /key1 value1 |
Single argument
The value must follow an equals sign (=
). The value can be null (for example, mykey=
).
The key may have a prefix.
Key prefix | Example |
---|---|
No prefix | key1=value1 |
Single dash (- )† |
-key2=value2 |
Two dashes (-- ) |
--key3=value3 |
Forward slash (/ ) |
/key4=value4 |
†A key with a single dash prefix (-
) must be provided in switch mappings, described below.
Example command:
dotnet run key1=value1 -key2=value2 --key3=value3 /key4=value4
Note: If -key1
isn't present in the switch mappings given to the configuration provider, a FormatException
is thrown.
Sequence of two arguments
The value can't be null and must follow the key separated by a space.
The key must have a prefix.
Key prefix | Example |
---|---|
Single dash (- )† |
-key1 value1 |
Two dashes (-- ) |
--key2 value2 |
Forward slash (/ ) |
/key3 value3 |
†A key with a single dash prefix (-
) must be provided in switch mappings, described below.
Example command:
dotnet run -key1 value1 --key2 value2 /key3 value3
Note: If -key1
isn't present in the switch mappings given to the configuration provider, a FormatException
is thrown.
Duplicate keys
If duplicate keys are provided, the last key-value pair is used.
Switch mappings
When manually building configuration with ConfigurationBuilder
, you can optionally provide a switch mappings dictionary to the AddCommandLine
method. Switch mappings allow you to provide key name replacement logic.
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 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.
In the following example, the GetSwitchMappings
method allows your command-line arguments to use a single dash (-
) key prefix and avoid leading subkey prefixes.
[!code-csharpMain]
Without providing command-line arguments, the dictionary provided to AddInMemoryCollection
sets the configuration values. Run the app with the following command:
dotnet run
The console window displays:
MachineName: RickPC
Left: 1980
Use the following to pass in configuration settings:
dotnet run /Profile:MachineName=DahliaPC /App:MainWindow:Left=1984
The console window displays:
MachineName: DahliaPC
Left: 1984
After the switch mappings dictionary is created, it contains the data shown in the following table.
Key | Value |
---|---|
-MachineName |
Profile:MachineName |
-Left |
App:MainWindow:Left |
To demonstrate key switching using the dictionary, run the following command:
dotnet run -MachineName=ChadPC -Left=1988
The command-line keys are swapped. The console window displays the configuration values for Profile:MachineName
and App:MainWindow:Left
:
MachineName: ChadPC
Left: 1988
The web.config file
A web.config file is required when you host the app in IIS or IIS-Express. web.config turns on the AspNetCoreModule in IIS to launch your app. Settings in web.config enable the AspNetCoreModule in IIS to launch your app and configure other IIS settings and modules. If you are using Visual Studio and delete web.config, Visual Studio will create a new one.
Additional notes
- Dependency Injection (DI) is not set up until after
ConfigureServices
is invoked. - The configuration system is not DI aware.
IConfiguration
has two specializations:IConfigurationRoot
Used for the root node. Can trigger a reload.IConfigurationSection
Represents a section of configuration values. TheGetSection
andGetChildren
methods return anIConfigurationSection
.