Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Configuration during startup #5241

Merged
merged 9 commits into from
Jan 24, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 15 additions & 11 deletions aspnetcore/fundamentals/configuration/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ uid: fundamentals/configuration/index

By [Rick Anderson](https://twitter.com/RickAndMSFT), [Mark Michaelis](http://intellitect.com/author/mark-michaelis/), [Steve Smith](https://ardalis.com/), [Daniel Roth](https://github.com/danroth27), and [Luke Latham](https://github.com/guardrex)

The Configuration API provides a way to configure an ASP.NET Core web app based on a list of name-value pairs. Configuration is read at runtime from multiple sources. You can group these name-value pairs into a multi-level hierarchy.
The Configuration API provides a way to configure an ASP.NET Core web app based on a list of name-value pairs. Configuration is read at runtime from multiple sources. Name-value pairs can be grouped into a multi-level hierarchy.

There are configuration providers for:

Expand Down Expand Up @@ -54,7 +54,7 @@ Console.Write($"{Configuration["wizards:0:Name"]}");
// Output: Gandalf
```

Name-value pairs written to the built-in [Configuration](/dotnet/api/microsoft.extensions.configuration) providers are **not** persisted. However, you can create a custom provider that saves values. See [custom configuration provider](xref:fundamentals/configuration/index#custom-config-providers).
Name-value pairs written to the built-in [Configuration](/dotnet/api/microsoft.extensions.configuration) providers are **not** persisted. However, a custom provider that saves values can be created. See [custom configuration provider](xref:fundamentals/configuration/index#custom-config-providers).

The preceding sample uses the configuration indexer to read values. To access configuration outside of `Startup`, use the *options pattern*. For more information, see the [Options](xref:fundamentals/configuration/options) topic.

Expand Down Expand Up @@ -88,28 +88,28 @@ Configuration considerations:

* `IOptionsSnapshot` can reload configuration data when it changes. For more information, see [IOptionsSnapshot](xref:fundamentals/configuration/options#reload-configuration-data-with-ioptionssnapshot).,
* Configuration keys are **not** case-sensitive.
* **Never** store passwords or other sensitive data in configuration provider code or in plain text configuration files. Don't use production secrets in your development or test environments. Specify secrets outside of the project so that they can't be accidentally committed to your repository. Learn more about [working with multiple environments](xref:fundamentals/environments) and managing [safe storage of app secrets during development](xref:security/app-secrets).
* If a colon (`:`) can't be used in environment variables on your system, replace the colon (`:`) with a double-underscore (`__`).
* **Never** store passwords or other sensitive data in configuration provider code or in plain text configuration files. Don't use production secrets in development or test environments. Specify secrets outside of the project so that they can't be accidentally committed to a source code repository. Learn more about [working with multiple environments](xref:fundamentals/environments) and managing [safe storage of app secrets during development](xref:security/app-secrets).
* If a colon (`:`) can't be used in environment variables on a system, replace the colon (`:`) with a double-underscore (`__`).
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I recommend adding an example of where the double underscore may be necessary. Maybe we have this documented somewhere already, in which case you could just link to that info.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's in-progress on 👉 #4968

I'll add your comment on the issue referencing this topic.


## In-memory provider and binding to a POCO class

The following sample shows how to use the in-memory provider and bind to a class:

[!code-csharp[Main](index/sample/InMemory/Program.cs)]

Configuration values are returned as strings, but binding enables the construction of objects. Binding allows you to retrieve POCO objects or even entire object graphs.
Configuration values are returned as strings, but binding enables the construction of objects. Binding allows the retrieval of POCO objects or even entire object graphs.

### GetValue

The following sample demonstrates the [GetValue<T>](/dotnet/api/microsoft.extensions.configuration.configurationbinder.get?view=aspnetcore-2.0#Microsoft_Extensions_Configuration_ConfigurationBinder_Get__1_Microsoft_Extensions_Configuration_IConfiguration_) extension method:

[!code-csharp[Main](index/sample/InMemoryGetValue/Program.cs?highlight=31)]

The ConfigurationBinder's `GetValue<T>` method allows you to specify a default value (80 in the sample). `GetValue<T>` is for simple scenarios and doesn't bind to entire sections. `GetValue<T>` gets scalar values from `GetSection(key).Value` converted to a specific type.
The ConfigurationBinder's `GetValue<T>` method allows the specification of a default value (80 in the sample). `GetValue<T>` is for simple scenarios and doesn't bind to entire sections. `GetValue<T>` obtains scalar values from `GetSection(key).Value` converted to a specific type.

## Bind to an object graph

You can recursively bind to each object in a class. Consider the following `AppSettings` class:
Each object in a class can be recursively bound. Consider the following `AppSettings` class:

[!code-csharp[Main](index/sample/ObjectGraph/AppSettings.cs)]

Expand Down Expand Up @@ -180,7 +180,7 @@ Create the custom configuration provider by inheriting from [ConfigurationProvid

The highlighted values from the database ("value_from_ef_1" and "value_from_ef_2") are displayed when the sample is run.

You can add an `EFConfigSource` extension method for adding the configuration source:
An `EFConfigSource` extension method for adding the configuration source can be used:

[!code-csharp[Main](index/sample/CustomConfigurationProvider/EntityFrameworkExtensions.cs?highlight=12)]

Expand Down Expand Up @@ -326,7 +326,7 @@ If duplicate keys are provided, the last key-value pair is used.

### Switch mappings

When manually building configuration with `ConfigurationBuilder`, you can optionally provide a switch mappings dictionary to the `AddCommandLine` method. Switch mappings allow you to provide key name replacement logic.
When manually building configuration with `ConfigurationBuilder`, a switch mappings dictionary can be added to the `AddCommandLine` method. Switch mappings allow key name replacement logic.

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

Expand All @@ -335,7 +335,7 @@ Switch mappings dictionary key rules:
* Switches must start with a dash (`-`) or double-dash (`--`).
* The switch mappings dictionary must not contain duplicate keys.

In the following example, the `GetSwitchMappings` method allows your command-line arguments to use a single dash (`-`) key prefix and avoid leading subkey prefixes.
In the following example, the `GetSwitchMappings` method allows command-line arguments to use a single dash (`-`) key prefix and avoid leading subkey prefixes.

[!code-csharp[Main](index/sample/CommandLine/Program.cs?highlight=10-19,32)]

Expand Down Expand Up @@ -389,14 +389,18 @@ Left: 1988

A *web.config* file is required when hosting the app in IIS or IIS Express. Settings in *web.config* enable the [ASP.NET Core Module](xref:fundamentals/servers/aspnet-core-module) to launch the app and configure other IIS settings and modules. If the *web.config* file isn't present and the project file includes `<Project Sdk="Microsoft.NET.Sdk.Web">`, publishing the project creates a *web.config* file in the published output (the *publish* folder). For more information, see [Host ASP.NET Core on Windows with IIS](xref:host-and-deploy/iis/index#webconfig).

## Accessing configuration during startup

To access configuration within `ConfigureServices` or `Configure` during startup, see the examples in the [Application startup](xref:fundamentals/startup) topic.

## Additional notes

* Dependency Injection (DI) isn't set up until after `ConfigureServices` is invoked.
* The configuration system isn't DI aware.
* `IConfiguration` has two specializations:
* `IConfigurationRoot` Used for the root node. Can trigger a reload.
* `IConfigurationSection` Represents a section of configuration values. The `GetSection` and `GetChildren` methods return an `IConfigurationSection`.
* Use [IConfigurationRoot](/dotnet/api/microsoft.extensions.configuration.iconfigurationroot) when reloading configuration or need access to each provider. Neither of these situations are common.
* Use [IConfigurationRoot](/dotnet/api/microsoft.extensions.configuration.iconfigurationroot) when reloading configuration or for access to each provider. Neither of these situations are common.

## Additional resources

Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
using System;
using System.Collections.Generic;
// Requires NuGet package
// Microsoft.Extensions.Configuration.Json
using Microsoft.Extensions.Configuration;

public class Program
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
using System;
using System.Collections.Generic;
// Requires NuGet package
// Microsoft.Extensions.Configuration.Json
using Microsoft.Extensions.Configuration;

public class Program
Expand Down
6 changes: 6 additions & 0 deletions aspnetcore/fundamentals/configuration/options.md
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,12 @@ services.PostConfigureAll<MyOptions>("named_options_1", myOptions =>

[IOptionsMonitorCache&lt;TOptions&gt;](/dotnet/api/microsoft.extensions.options.ioptionsmonitorcache-1) (ASP.NET Core 2.0 or later) is used by `IOptionsMonitor` to cache `TOptions` instances. The `IOptionsMonitorCache` invalidates options instances in the monitor so that the value is recomputed ([TryRemove](/dotnet/api/microsoft.extensions.options.ioptionsmonitorcache-1.tryremove)). Values can be manually introduced as well with [TryAdd](/dotnet/api/microsoft.extensions.options.ioptionsmonitorcache-1.tryadd). The [Clear](/dotnet/api/microsoft.extensions.options.ioptionsmonitorcache-1.clear) method is used when all named instances should be recreated on demand.

## Accessing options during startup

`IOptions` can be used in `Configure`, since services are built before the `Configure` method executes. If a service provider is built in `ConfigureServices` to access options, it wouldn't contain any options configurations provided after the service provider is built. Therefore, an inconsistent options state may exist due to the ordering of service registrations.

Since options are typically loaded from configuration, configuration can be used in startup in both `Configure` and `ConfigureServices`. For examples of using configuration during startup, see the [Application startup](xref:fundamentals/startup) topic.

## See also

* [Configuration](xref:fundamentals/configuration/index)
9 changes: 6 additions & 3 deletions aspnetcore/fundamentals/startup.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,14 @@ Specify the `Startup` class with the [WebHostBuilderExtensions](/dotnet/api/Micr

[!code-csharp[Main](../common/samples/WebApplication1DotNetCore2.0App/Program.cs?name=snippet_Main&highlight=10)]

The `Startup` class constructor accepts dependencies defined by the host. A common use of [dependency injection](xref:fundamentals/dependency-injection) into the `Startup` class is to inject [IHostingEnvironment](/dotnet/api/Microsoft.AspNetCore.Hosting.IHostingEnvironment) to configure services by environment:
The `Startup` class constructor accepts dependencies defined by the host. A common use of [dependency injection](xref:fundamentals/dependency-injection) into the `Startup` class is to inject:

* [IHostingEnvironment](/dotnet/api/Microsoft.AspNetCore.Hosting.IHostingEnvironment) to configure services by environment.
* [IConfiguration](/dotnet/api/microsoft.extensions.configuration.iconfiguration) to configure the app during startup.

[!code-csharp[Main](startup/snapshot_sample/Startup2.cs)]

An alternative to injecting `IHostingStartup` is to use a conventions-based approach. The app can define separate `Startup` classes for different environments (for example, `StartupDevelopment`), and the appropriate startup class is selected at runtime. The class whose name suffix matches the current environment is prioritized. If the app is run in the Development environment and includes both a `Startup` class and a `StartupDevelopment` class, the `StartupDevelopment` class is used. For more information see [Working with multiple environments](xref:fundamentals/environments#startup-conventions).
An alternative to injecting `IHostingEnvironment` is to use a conventions-based approach. The app can define separate `Startup` classes for different environments (for example, `StartupDevelopment`), and the appropriate startup class is selected at runtime. The class whose name suffix matches the current environment is prioritized. If the app is run in the Development environment and includes both a `Startup` class and a `StartupDevelopment` class, the `StartupDevelopment` class is used. For more information, see [Working with multiple environments](xref:fundamentals/environments#startup-conventions).

To learn more about `WebHostBuilder`, see the [Hosting](xref:fundamentals/hosting) topic. For information on handling errors during startup, see [Startup exception handling](xref:fundamentals/error-handling#startup-exception-handling).

Expand Down Expand Up @@ -78,7 +81,7 @@ For more information on how to use `IApplicationBuilder`, see [Middleware](xref:

[ConfigureServices](/dotnet/api/microsoft.aspnetcore.hosting.iwebhostbuilder.configureservices) and [Configure](/dotnet/api/microsoft.aspnetcore.hosting.webhostbuilderextensions.configure) convenience methods can be used instead of specifying a `Startup` class. Multiple calls to `ConfigureServices` append to one another. Multiple calls to `Configure` use the last method call.

[!code-csharp[Main](startup/snapshot_sample/Program.cs?highlight=16,20)]
[!code-csharp[Main](startup/snapshot_sample/Program.cs?highlight=18,22)]

## Startup filters

Expand Down
8 changes: 7 additions & 1 deletion aspnetcore/fundamentals/startup/snapshot_sample/Program.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
public class Program
{
public static IHostingEnvironment HostingEnvironment { get; set; }
public static IHostingEnvironment HostingEnvironment { get; }
public static IConfiguration Configuration { get; }

public static void Main(string[] args)
{
Expand All @@ -12,6 +13,7 @@ public static IWebHost BuildWebHost(string[] args) =>
.ConfigureAppConfiguration((hostingContext, config) =>
{
HostingEnvironment = hostingContext.HostingEnvironment;
Configuration = config.Build();
})
.ConfigureServices(services =>
{
Expand All @@ -28,6 +30,10 @@ public static IWebHost BuildWebHost(string[] args) =>
app.UseExceptionHandler("/Error");
}

// Configuration is available during startup. Examples:
// Configuration["key"]
// Configuration["subsection:suboption1"]

app.UseMvcWithDefaultRoute();
app.UseStaticFiles();
})
Expand Down
8 changes: 7 additions & 1 deletion aspnetcore/fundamentals/startup/snapshot_sample/Startup2.cs
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
public class Startup
{
public Startup(IHostingEnvironment env)
public Startup(IHostingEnvironment env, IConfiguration config)
{
HostingEnvironment = env;
Configuration = config;
}

public IHostingEnvironment HostingEnvironment { get; }
public IConfiguration Configuration { get; }

public void ConfigureServices(IServiceCollection services)
{
Expand All @@ -17,5 +19,9 @@ public void ConfigureServices(IServiceCollection services)
{
// Staging/Production configuration
}

// Configuration is available during startup. Examples:
// Configuration["key"]
// Configuration["subsection:suboption1"]
}
}