This information relates to a pre-release product that may be substantially modified before it's commercially released. Microsoft makes no warranties, express or implied, with respect to the information provided here.
Application 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 article provides information on configuration in ASP.NET Core. For information on using configuration in non-ASP.NET Core apps, see .NET Configuration.
ASP.NET Core apps configure and launch a host. The host is responsible for app startup and lifetime management. The ASP.NET Core templates create a WebApplicationBuilder which contains the host. While some configuration can be done in both the host and the application configuration providers, generally, only configuration that is necessary for the host should be done in host configuration.
Application configuration is the highest priority and is detailed in the next section. Host configuration follows application configuration, and is described in this article.
Default application configuration sources
ASP.NET Core web apps created with dotnet new or Visual Studio generate the following code:
var builder = WebApplication.CreateBuilder(args);
WebApplication.CreateBuilder initializes a new instance of the WebApplicationBuilder class with preconfigured defaults. The initialized WebApplicationBuilder (builder) provides default configuration for the app in the following order, from highest to lowest priority:
Every other host setting is read from application config instead of host config.
URLS is one of the many common host settings that is not a bootstrap setting. Like every other host setting not in the previous list, URLS is read later from application config. Host config is a fallback for application config, so host config can be used to set URLS, but it will be overridden by any configuration source in application config like appsettings.json.
Configuration providers that are added later have higher priority and 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.
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.
If a configuration value must be guaranteed, see GetValue. The preceding example only reads strings and doesn’t support a default value.
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.
Comments in appsettings.json
Comments in appsettings.json and appsettings.{Environment}.json files are supported using JavaScript or C# style comments.
Some integrated development environments (IDE) display errors when editing a JSON file that contains comments. You can generally ignore comment errors and warnings, but you can also usually disable them with a setting in the IDE. In Visual Studio Code, for example, add the following to the settings.json file to disable the errors:
public class PositionOptions
{
public const string Position = "Position";
public string Title { get; set; } = String.Empty;
public string Name { get; set; } = String.Empty;
}
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 field is used so the string "Position" doesn't need to be hard coded in the app when binding the class to a configuration provider.
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:
using ConfigSample.Options;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages();
builder.Services.Configure<PositionOptions>(
builder.Configuration.GetSection(PositionOptions.Position));
var app = builder.Build();
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 which registers services and configures options:
using ConfigSample.Options;
using Microsoft.Extensions.DependencyInjection.ConfigSample.Options;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages();
builder.Services.Configure<PositionOptions>(
builder.Configuration.GetSection(PositionOptions.Position));
builder.Services.Configure<ColorOptions>(
builder.Configuration.GetSection(ColorOptions.Color));
builder.Services.AddScoped<IMyDependency, MyDependency>();
builder.Services.AddScoped<IMyDependency2, MyDependency2>();
var app = builder.Build();
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;
}
public static IServiceCollection AddMyDependencyGroup(
this IServiceCollection services)
{
services.AddScoped<IMyDependency, MyDependency>();
services.AddScoped<IMyDependency2, MyDependency2>();
return services;
}
}
}
The remaining services are registered in a similar class. The following code uses the new extension methods to register the services:
using Microsoft.Extensions.DependencyInjection.ConfigSample.Options;
var builder = WebApplication.CreateBuilder(args);
builder.Services
.AddConfig(builder.Configuration)
.AddMyDependencyGroup();
builder.Services.AddRazorPages();
var app = builder.Build();
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.
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.
Production apps should use the most secure authentication flow available. For more information, see Secure authentication flows.
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:
Non-prefixed environment variables are environment variables other than those prefixed by ASPNETCORE_ or DOTNET_. For example, the ASP.NET Core web application templates set "ASPNETCORE_ENVIRONMENT": "Development" in launchSettings.json. For more information on ASPNETCORE_ and DOTNET_ environment variables, see:
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. For example, the : separator is not supported by Bash. The double underscore, __, is:
Supported by all platforms.
Automatically replaced by a colon, :.
The following 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 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.
Environment variables set with the MyCustomPrefix_ prefix override the default configuration providers. This includes environment variables without the prefix.
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.
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.
Environment variables set in generated launchSettings.json
Environment variables set in launchSettings.json override those set in the system environment. For example, the ASP.NET Core web templates generate a launchSettings.json file that sets the endpoint configuration to:
Configuring the applicationUrl sets the ASPNETCORE_URLS environment variable and overrides values set in the environment.
Escape environment variables on Linux
On Linux, the value of URL environment variables must be escaped so systemd can parse it. Use the linux tool systemd-escape which yields http:--localhost:5001
The following code displays the environment variables and values on application startup, which can be helpful when debugging environment settings:
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
foreach (var c in builder.Configuration.AsEnumerable())
{
Console.WriteLine(c.Key + " = " + c.Value);
}
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.
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="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 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:
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.
Set environment and command-line arguments with Visual Studio
Environment and command-line arguments can be set in Visual Studio from the launch profiles dialog:
In Solution Explorer, right click the project and select Properties.
Select the Debug > General tab and select Open debug launch profiles UI.
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:
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.
This article shows the use of connection strings. With a local database the user doesn't have to be authenticated, but in production, connection strings sometimes include a password to authenticate. A resource owner password credential (ROPC) is a security risk that should be avoided in production databases. Production apps should use the most secure authentication flow available. For more information on authentication for apps deployed to test or production environments, see Secure authentication flows.
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 provider, 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.
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 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.
This article shows the use of connection strings. With a local database the user doesn't have to be authenticated, but in production, connection strings sometimes include a password to authenticate. A resource owner password credential (ROPC) is a security risk that should be avoided in production databases. Production apps should use the most secure authentication flow available. For more information on authentication for apps deployed to test or production environments, see Secure authentication flows.
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.
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).
FileConfigurationProvider is the base class for loading configuration from the file system. The following configuration providers derive from FileConfigurationProvider:
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:
When the preceding highlighted markup is used in an ASP.NET Core web app and the app is launched on the command line with the following cross-server endpoint configuration:
dotnet run --urls="https://localhost:7777"
Kestrel binds to the endpoint configured specifically for Kestrel in the appsettings.json file (https://localhost:9999) and not https://localhost:7777.
Consider the Kestrel specific endpoint configured as an environment variable:
set Kestrel__Endpoints__Https__Url=https://localhost:8888
In the preceding environment variable, Https is the name of the Kestrel specific endpoint. The preceding appsettings.json file also defines a Kestrel specific endpoint named Https. By default, environment variables using the Environment Variables configuration provider are read after appsettings.{Environment}.json, therefore, the preceding environment variable is used for the Https endpoint.
GetValue
ConfigurationBinder.GetValue 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:
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.
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.
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; } = String.Empty;
public string Value { get; set; } = String.Empty;
}
Add an EFConfigurationContext to store and access the configured values.
public class EFConfigurationContext : DbContext
{
public EFConfigurationContext(DbContextOptions<EFConfigurationContext> options) : base(options)
{
}
public DbSet<EFConfigurationValue> Values => Set<EFConfigurationValue>();
}
public class EFConfigurationSource : IConfigurationSource
{
private readonly Action<DbContextOptionsBuilder> _optionsAction;
public EFConfigurationSource(Action<DbContextOptionsBuilder> optionsAction) => _optionsAction = optionsAction;
public IConfigurationProvider Build(IConfigurationBuilder builder) => 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).
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))
{
if (dbContext == null || dbContext.Values == null)
{
throw new Exception("Null DB context");
}
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-2005
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." }
};
if (dbContext == null || dbContext.Values == null)
{
throw new Exception("Null DB context");
}
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:
//using Microsoft.EntityFrameworkCore;
var builder = WebApplication.CreateBuilder(args);
builder.Configuration.AddEFConfiguration(
opt => opt.UseInMemoryDatabase("InMemoryDb"));
var app = builder.Build();
app.Run();
Access configuration with Dependency Injection (DI)
public class Service
{
private readonly IConfiguration _config;
public Service(IConfiguration config) =>
_config = config;
public void DoSomething()
{
var configSettingValue = _config["ConfigSetting"];
// ...
}
}
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:
using SampleApp.Models;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages();
builder.Services.Configure<MyOptions>(
builder.Configuration.GetSection("MyOptions"));
var app = builder.Build();
The following markup uses the @inject Razor directive to resolve and display the options values:
Options configured in a delegate override values set in the configuration providers.
In the following code, an IConfigureOptions<TOptions> service is added to the service container. It uses a delegate to configure values for MyOptions:
using SampleApp.Models;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages();
builder.Services.Configure<MyOptions>(myOptions =>
{
myOptions.Option1 = "Value configured in delegate";
myOptions.Option2 = 500;
});
var app = builder.Build();
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 overview.
Environment variables prefixed with DOTNET_ (for example, DOTNET_ENVIRONMENT) using the Environment Variables configuration provider. The prefix (DOTNET_) is stripped when the configuration key-value pairs are loaded.
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:
launch.json/launchSettings.json are tooling configuration files for the Development environment, described:
Application 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 article provides information on configuration in ASP.NET Core. For information on using configuration in console apps, see .NET Configuration.
Application and Host Configuration
ASP.NET Core apps configure and launch a host. The host is responsible for app startup and lifetime management. The ASP.NET Core templates create a WebApplicationBuilder which contains the host. While some configuration can be done in both the host and the application configuration providers, generally, only configuration that is necessary for the host should be done in host configuration.
Application configuration is the highest priority and is detailed in the next section. Host configuration follows application configuration, and is described in this article.
Default application configuration sources
ASP.NET Core web apps created with dotnet new or Visual Studio generate the following code:
var builder = WebApplication.CreateBuilder(args);
WebApplication.CreateBuilder initializes a new instance of the WebApplicationBuilder class with preconfigured defaults. The initialized WebApplicationBuilder (builder) provides default configuration for the app in the following order, from highest to lowest priority:
Every other host setting is read from application config instead of host config.
URLS is one of the many common host settings that is not a bootstrap setting. Like every other host setting not in the previous list, URLS is read later from application config. Host config is a fallback for application config, so host config can be used to set URLS, but it will be overridden by any configuration source in application config like appsettings.json.
Configuration providers that are added later have higher priority and 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.
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.
If a configuration value must be guaranteed, see GetValue. The preceding example only reads strings and doesn’t support a default value.
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.
Comments in appsettings.json
Comments in appsettings.json and appsettings.{Environment}.jsonfiles are supported using JavaScript or C# style comments.
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:
public class PositionOptions
{
public const string Position = "Position";
public string Title { get; set; } = String.Empty;
public string Name { get; set; } = String.Empty;
}
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 field is used so the string "Position" doesn't need to be hard coded in the app when binding the class to a configuration provider.
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:
using ConfigSample.Options;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages();
builder.Services.Configure<PositionOptions>(
builder.Configuration.GetSection(PositionOptions.Position));
var app = builder.Build();
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 which registers services and configures options:
using ConfigSample.Options;
using Microsoft.Extensions.DependencyInjection.ConfigSample.Options;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages();
builder.Services.Configure<PositionOptions>(
builder.Configuration.GetSection(PositionOptions.Position));
builder.Services.Configure<ColorOptions>(
builder.Configuration.GetSection(ColorOptions.Color));
builder.Services.AddScoped<IMyDependency, MyDependency>();
builder.Services.AddScoped<IMyDependency2, MyDependency2>();
var app = builder.Build();
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;
}
public static IServiceCollection AddMyDependencyGroup(
this IServiceCollection services)
{
services.AddScoped<IMyDependency, MyDependency>();
services.AddScoped<IMyDependency2, MyDependency2>();
return services;
}
}
}
The remaining services are registered in a similar class. The following code uses the new extension methods to register the services:
using Microsoft.Extensions.DependencyInjection.ConfigSample.Options;
var builder = WebApplication.CreateBuilder(args);
builder.Services
.AddConfig(builder.Configuration)
.AddMyDependencyGroup();
builder.Services.AddRazorPages();
var app = builder.Build();
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.
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.
Production apps should use the most secure authentication flow available. For more information, see Secure authentication flows.
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:
Non-prefixed environment variables are environment variables other than those prefixed by ASPNETCORE_ or DOTNET_. For example, the ASP.NET Core web application templates set "ASPNETCORE_ENVIRONMENT": "Development" in launchSettings.json. For more information on ASPNETCORE_ and DOTNET_ environment variables, see:
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. For example, the : separator is not supported by Bash. The double underscore, __, is:
Supported by all platforms.
Automatically replaced by a colon, :.
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 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.
Environment variables set with the MyCustomPrefix_ prefix override the default configuration providers. This includes environment variables without the prefix.
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.
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.
Environment variables set in generated launchSettings.json
Environment variables set in launchSettings.json override those set in the system environment. For example, the ASP.NET Core web templates generate a launchSettings.json file that sets the endpoint configuration to:
Configuring the applicationUrl sets the ASPNETCORE_URLS environment variable and overrides values set in the environment.
Escape environment variables on Linux
On Linux, the value of URL environment variables must be escaped so systemd can parse it. Use the linux tool systemd-escape which yields http:--localhost:5001
The following code displays the environment variables and values on application startup, which can be helpful when debugging environment settings:
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
foreach (var c in builder.Configuration.AsEnumerable())
{
Console.WriteLine(c.Key + " = " + c.Value);
}
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.
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="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 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:
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.
Set environment and command-line arguments with Visual Studio
Environment and command-line arguments can be set in Visual Studio from the launch profiles dialog:
In Solution Explorer, right click the project and select Properties.
Select the Debug > General tab and select Open debug launch profiles UI.
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:
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.
This article shows the use of connection strings. With a local database the user doesn't have to be authenticated, but in production, connection strings sometimes include a password to authenticate. A resource owner password credential (ROPC) is a security risk that should be avoided in production databases. Production apps should use the most secure authentication flow available. For more information on authentication for apps deployed to test or production environments, see Secure authentication flows.
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 provider, 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.
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 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.
This article shows the use of connection strings. With a local database the user doesn't have to be authenticated, but in production, connection strings sometimes include a password to authenticate. A resource owner password credential (ROPC) is a security risk that should be avoided in production databases. Production apps should use the most secure authentication flow available. For more information on authentication for apps deployed to test or production environments, see Secure authentication flows.
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.
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).
FileConfigurationProvider is the base class for loading configuration from the file system. The following configuration providers derive from FileConfigurationProvider:
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:
When the preceding highlighted markup is used in an ASP.NET Core web app and the app is launched on the command line with the following cross-server endpoint configuration:
dotnet run --urls="https://localhost:7777"
Kestrel binds to the endpoint configured specifically for Kestrel in the appsettings.json file (https://localhost:9999) and not https://localhost:7777.
Consider the Kestrel specific endpoint configured as an environment variable:
set Kestrel__Endpoints__Https__Url=https://localhost:8888
In the preceding environment variable, Https is the name of the Kestrel specific endpoint. The preceding appsettings.json file also defines a Kestrel specific endpoint named Https. By default, environment variables using the Environment Variables configuration provider are read after appsettings.{Environment}.json, therefore, the preceding environment variable is used for the Https endpoint.
GetValue
ConfigurationBinder.GetValue 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:
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.
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.
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; } = String.Empty;
public string Value { get; set; } = String.Empty;
}
Add an EFConfigurationContext to store and access the configured values.
public class EFConfigurationContext : DbContext
{
public EFConfigurationContext(DbContextOptions<EFConfigurationContext> options) : base(options)
{
}
public DbSet<EFConfigurationValue> Values => Set<EFConfigurationValue>();
}
public class EFConfigurationSource : IConfigurationSource
{
private readonly Action<DbContextOptionsBuilder> _optionsAction;
public EFConfigurationSource(Action<DbContextOptionsBuilder> optionsAction) => _optionsAction = optionsAction;
public IConfigurationProvider Build(IConfigurationBuilder builder) => 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).
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))
{
if (dbContext == null || dbContext.Values == null)
{
throw new Exception("Null DB context");
}
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-2005
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." }
};
if (dbContext == null || dbContext.Values == null)
{
throw new Exception("Null DB context");
}
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:
//using Microsoft.EntityFrameworkCore;
var builder = WebApplication.CreateBuilder(args);
builder.Configuration.AddEFConfiguration(
opt => opt.UseInMemoryDatabase("InMemoryDb"));
var app = builder.Build();
app.Run();
Access configuration with Dependency Injection (DI)
public class Service
{
private readonly IConfiguration _config;
public Service(IConfiguration config) =>
_config = config;
public void DoSomething()
{
var configSettingValue = _config["ConfigSetting"];
// ...
}
}
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:
using SampleApp.Models;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages();
builder.Services.Configure<MyOptions>(
builder.Configuration.GetSection("MyOptions"));
var app = builder.Build();
The following markup uses the @inject Razor directive to resolve and display the options values:
Options configured in a delegate override values set in the configuration providers.
In the following code, an IConfigureOptions<TOptions> service is added to the service container. It uses a delegate to configure values for MyOptions:
using SampleApp.Models;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages();
builder.Services.Configure<MyOptions>(myOptions =>
{
myOptions.Option1 = "Value configured in delegate";
myOptions.Option2 = 500;
});
var app = builder.Build();
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 overview.
Environment variables prefixed with DOTNET_ (for example, DOTNET_ENVIRONMENT) using the Environment Variables configuration provider. The prefix (DOTNET_) is stripped when the configuration key-value pairs are loaded.
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:
launch.json/launchSettings.json are tooling configuration files for the Development environment, described:
Application 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 article provides information on configuration in ASP.NET Core. For information on using configuration in console apps, see .NET Configuration.
Application and Host Configuration
ASP.NET Core apps configure and launch a host. The host is responsible for app startup and lifetime management. The ASP.NET Core templates create a WebApplicationBuilder which contains the host. While some configuration can be done in both the host and the application configuration providers, generally, only configuration that is necessary for the host should be done in host configuration.
Application configuration is the highest priority and is detailed in the next section. Host configuration follows application configuration, and is described in this article.
Default application configuration sources
ASP.NET Core web apps created with dotnet new or Visual Studio generate the following code:
var builder = WebApplication.CreateBuilder(args);
WebApplication.CreateBuilder initializes a new instance of the WebApplicationBuilder class with preconfigured defaults. The initialized WebApplicationBuilder (builder) provides default configuration for the app in the following order, from highest to lowest priority:
When a configuration value is set in host and application configuration, the application configuration is used.
See Explanation in this GitHub comment for an explanation of why in host configuration, ASPNETCORE_ prefixed environment variables have higher priority than command-line arguments.
Host variables
The following variables are locked in early when initializing the host builders and can't be influenced by application config:
Every other host setting is read from application config instead of host config.
URLS is one of the many common host settings that is not a bootstrap setting. Like every other host setting not in the previous list, URLS is read later from application config. Host config is a fallback for application config, so host config can be used to set URLS, but it will be overridden by any configuration source in application config like appsettings.json.
Configuration providers that are added later have higher priority and 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.
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.
If a configuration value must be guaranteed, see GetValue. The preceding example only reads strings and doesn’t support a default value.
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.
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:
public class PositionOptions
{
public const string Position = "Position";
public string Title { get; set; } = String.Empty;
public string Name { get; set; } = String.Empty;
}
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 field is used so the string "Position" doesn't need to be hard coded in the app when binding the class to a configuration provider.
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:
using ConfigSample.Options;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages();
builder.Services.Configure<PositionOptions>(
builder.Configuration.GetSection(PositionOptions.Position));
var app = builder.Build();
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 which registers services and configures options:
using ConfigSample.Options;
using Microsoft.Extensions.DependencyInjection.ConfigSample.Options;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages();
builder.Services.Configure<PositionOptions>(
builder.Configuration.GetSection(PositionOptions.Position));
builder.Services.Configure<ColorOptions>(
builder.Configuration.GetSection(ColorOptions.Color));
builder.Services.AddScoped<IMyDependency, MyDependency>();
builder.Services.AddScoped<IMyDependency2, MyDependency2>();
var app = builder.Build();
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;
}
public static IServiceCollection AddMyDependencyGroup(
this IServiceCollection services)
{
services.AddScoped<IMyDependency, MyDependency>();
services.AddScoped<IMyDependency2, MyDependency2>();
return services;
}
}
}
The remaining services are registered in a similar class. The following code uses the new extension methods to register the services:
using Microsoft.Extensions.DependencyInjection.ConfigSample.Options;
var builder = WebApplication.CreateBuilder(args);
builder.Services
.AddConfig(builder.Configuration)
.AddMyDependencyGroup();
builder.Services.AddRazorPages();
var app = builder.Build();
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.
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.
Production apps should use the most secure authentication flow available. For more information, see Secure authentication flows.
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:
Non-prefixed environment variables are environment variables other than those prefixed by ASPNETCORE_ or DOTNET_. For example, the ASP.NET Core web application templates set "ASPNETCORE_ENVIRONMENT": "Development" in launchSettings.json. For more information on ASPNETCORE_ and DOTNET_ environment variables, see:
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. For example, the : separator is not supported by Bash. The double underscore, __, is:
Supported by all platforms.
Automatically replaced by a colon, :.
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 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.
Environment variables set with the MyCustomPrefix_ prefix override the default configuration providers. This includes environment variables without the prefix.
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.
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.
Environment variables set in generated launchSettings.json
Environment variables set in launchSettings.json override those set in the system environment. For example, the ASP.NET Core web templates generate a launchSettings.json file that sets the endpoint configuration to:
Configuring the applicationUrl sets the ASPNETCORE_URLS environment variable and overrides values set in the environment.
Escape environment variables on Linux
On Linux, the value of URL environment variables must be escaped so systemd can parse it. Use the linux tool systemd-escape which yields http:--localhost:5001
The following code displays the environment variables and values on application startup, which can be helpful when debugging environment settings:
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
foreach (var c in builder.Configuration.AsEnumerable())
{
Console.WriteLine(c.Key + " = " + c.Value);
}
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.
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="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 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:
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.
Set environment and command-line arguments with Visual Studio
Environment and command-line arguments can be set in Visual Studio from the launch profiles dialog:
In Solution Explorer, right click the project and select Properties.
Select the Debug > General tab and select Open debug launch profiles UI.
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:
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.
This article shows the use of connection strings. With a local database the user doesn't have to be authenticated, but in production, connection strings sometimes include a password to authenticate. A resource owner password credential (ROPC) is a security risk that should be avoided in production databases. Production apps should use the most secure authentication flow available. For more information on authentication for apps deployed to test or production environments, see Secure authentication flows.
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.
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 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.
This article shows the use of connection strings. With a local database the user doesn't have to be authenticated, but in production, connection strings sometimes include a password to authenticate. A resource owner password credential (ROPC) is a security risk that should be avoided in production databases. Production apps should use the most secure authentication flow available. For more information on authentication for apps deployed to test or production environments, see Secure authentication flows.
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.
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).
FileConfigurationProvider is the base class for loading configuration from the file system. The following configuration providers derive from FileConfigurationProvider:
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:
When the preceding highlighted markup is used in an ASP.NET Core web app and the app is launched on the command line with the following cross-server endpoint configuration:
dotnet run --urls="https://localhost:7777"
Kestrel binds to the endpoint configured specifically for Kestrel in the appsettings.json file (https://localhost:9999) and not https://localhost:7777.
Consider the Kestrel specific endpoint configured as an environment variable:
set Kestrel__Endpoints__Https__Url=https://localhost:8888
In the preceding environment variable, Https is the name of the Kestrel specific endpoint. The preceding appsettings.json file also defines a Kestrel specific endpoint named Https. By default, environment variables using the Environment Variables configuration provider are read after appsettings.{Environment}.json, therefore, the preceding environment variable is used for the Https endpoint.
GetValue
ConfigurationBinder.GetValue 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:
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.
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.
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; } = String.Empty;
public string Value { get; set; } = String.Empty;
}
Add an EFConfigurationContext to store and access the configured values.
public class EFConfigurationContext : DbContext
{
public EFConfigurationContext(DbContextOptions<EFConfigurationContext> options) : base(options)
{
}
public DbSet<EFConfigurationValue> Values => Set<EFConfigurationValue>();
}
public class EFConfigurationSource : IConfigurationSource
{
private readonly Action<DbContextOptionsBuilder> _optionsAction;
public EFConfigurationSource(Action<DbContextOptionsBuilder> optionsAction) => _optionsAction = optionsAction;
public IConfigurationProvider Build(IConfigurationBuilder builder) => 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).
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))
{
if (dbContext == null || dbContext.Values == null)
{
throw new Exception("Null DB context");
}
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-2005
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." }
};
if (dbContext == null || dbContext.Values == null)
{
throw new Exception("Null DB context");
}
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:
//using Microsoft.EntityFrameworkCore;
var builder = WebApplication.CreateBuilder(args);
builder.Configuration.AddEFConfiguration(
opt => opt.UseInMemoryDatabase("InMemoryDb"));
var app = builder.Build();
app.Run();
Access configuration with Dependency Injection (DI)
public class Service
{
private readonly IConfiguration _config;
public Service(IConfiguration config) =>
_config = config;
public void DoSomething()
{
var configSettingValue = _config["ConfigSetting"];
// ...
}
}
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:
using SampleApp.Models;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages();
builder.Services.Configure<MyOptions>(
builder.Configuration.GetSection("MyOptions"));
var app = builder.Build();
The following markup uses the @inject Razor directive to resolve and display the options values:
Options configured in a delegate override values set in the configuration providers.
In the following code, an IConfigureOptions<TOptions> service is added to the service container. It uses a delegate to configure values for MyOptions:
using SampleApp.Models;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages();
builder.Services.Configure<MyOptions>(myOptions =>
{
myOptions.Option1 = "Value configured in delegate";
myOptions.Option2 = 500;
});
var app = builder.Build();
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 overview.
Environment variables prefixed with DOTNET_ (for example, DOTNET_ENVIRONMENT) using the Environment Variables configuration provider. The prefix (DOTNET_) is stripped when the configuration key-value pairs are loaded.
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:
launch.json/launchSettings.json are tooling configuration files for the Development environment, described:
When the preceding highlighted markup is used in an ASP.NET Core web app and the app is launched on the command line with the following cross-server endpoint configuration:
dotnet run --urls="https://localhost:7777"
Kestrel binds to the endpoint configured specifically for Kestrel in the appsettings.json file (https://localhost:9999) and not https://localhost:7777.
Consider the Kestrel specific endpoint configured as an environment variable:
set Kestrel__Endpoints__Https__Url=https://localhost:8888
In the preceding environment variable, Https is the name of the Kestrel specific endpoint. The preceding appsettings.json file also defines a Kestrel specific endpoint named Https. By default, environment variables using the Environment Variables configuration provider are read after appsettings.{Environment}.json, therefore, the preceding environment variable is used for the Https endpoint.
GetValue
ConfigurationBinder.GetValue extracts a single value from configuration with a specified key and converts it to the specified type. This method is an extension method for IConfiguration:
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:
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.
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 arrayDictDictionary 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);
}
}
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 arrayDictDictionary:
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);
}
}
Custom configuration providers aren't required to implement array binding.
Custom configuration provider
Warning
This article shows the use of connection strings. With a local database the user doesn't have to be authenticated, but in production, connection strings sometimes include a password to authenticate. A resource owner password credential (ROPC) is a security risk that should be avoided in production databases. Production apps should use the most secure authentication flow available. For more information on authentication for apps deployed to test or production environments, see Secure authentication flows.
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.
// using Microsoft.EntityFrameworkCore;
public class EFConfigurationContext : DbContext
{
public EFConfigurationContext(DbContextOptions options) : base(options)
{
}
public DbSet<EFConfigurationValue> Values { get; set; }
}
// 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).
// 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-2005
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();
});
}
}
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 overview.
Environment variables prefixed with DOTNET_ (for example, DOTNET_ENVIRONMENT) using the Environment Variables configuration provider. The prefix (DOTNET_) is stripped when the configuration key-value pairs are loaded.
Command-line arguments using the Command-line configuration provider.
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:
launch.json/launchSettings.json are tooling configuration files for the Development environment, described:
The source for this content can be found on GitHub, where you can also create and review issues and pull requests. For more information, see our contributor guide.
ASP.NET Core
feedback
ASP.NET Core
is an open source project. Select a link to provide feedback: