Skip to content

Commit 5003389

Browse files
Add a few additional concepts to Configuration and Options articles (#29442)
* Initial updates, images, etc. * Getting closer, let's push to draft * Remove unused diagram * Apply suggestions from code review Co-authored-by: Tom Dykstra <[email protected]> * Revert appsettings.json change * Corrected pasted output that auto-reformatted Co-authored-by: Tom Dykstra <[email protected]>
1 parent fa04ac9 commit 5003389

File tree

9 files changed

+158
-8
lines changed

9 files changed

+158
-8
lines changed

docs/core/extensions/configuration.md

Lines changed: 60 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,15 @@ Configuration in .NET is performed using one or more [configuration providers](#
2424
> [!NOTE]
2525
> For information about configuring the .NET runtime itself, see [.NET Runtime configuration settings](../runtime-config/index.md).
2626
27+
## Concepts and abstractions
28+
29+
Given one or more configuration sources, the <xref:Microsoft.Extensions.Configuration.IConfiguration> type provides a unified view of the configuration data. Configuration is read-only, and the configuration pattern is not designed to be programmatically writable. The `IConfiguration` interface is a single representation of all the configuration sources, as shown in the following diagram:
30+
31+
:::image type="content" source="media/configuration-sources.svg" lightbox="media/configuration-sources.svg" alt-text="The `IConfiguration` interface is a single representation of all the configuration sources.":::
32+
2733
## Configure console apps
2834

29-
New .NET console applications created using [dotnet new](../tools/dotnet-new.md) or Visual Studio by default *do not* expose configuration capabilities. To add configuration in a new .NET console application, [add a package reference](../tools/dotnet-add-package.md) to [`Microsoft.Extensions.Hosting`](https://www.nuget.org/packages/Microsoft.Extensions.Hosting). Modify the *Program.cs* file to match the following code:
35+
.NET console applications created using the [dotnet new](../tools/dotnet-new.md) command template or Visual Studio by default *do not* expose configuration capabilities. To add configuration in a new .NET console application, [add a package reference](../tools/dotnet-add-package.md) to [Microsoft.Extensions.Hosting](https://www.nuget.org/packages/Microsoft.Extensions.Hosting). Modify the *Program.cs* file to match the following code:
3036

3137
:::code language="csharp" source="snippets/configuration/console/Program.cs" highlight="3":::
3238

@@ -51,6 +57,44 @@ One of the key advantages of using the .NET configuration abstractions is the ab
5157

5258
These abstractions are agnostic to their underlying configuration provider (<xref:Microsoft.Extensions.Configuration.IConfigurationProvider>). In other words, you can use an `IConfiguration` instance to access any configuration value from multiple providers.
5359

60+
The binder can use different approaches to process configuration values:​
61+
62+
- Direct deserialization (using built-in converters) for primitive types​.
63+
- The <xref:System.ComponentModel.TypeConverter> for a complex type when the type has one​.
64+
- Reflection for a complex type that has properties.
65+
66+
> [!NOTE]
67+
> The binder has a few limitations:
68+
>
69+
> - Properties are ignored if they have private setters or their type can't be converted.
70+
> - Properties without corresponding configuration keys are ignored.
71+
72+
#### Binding hierarchies
73+
74+
Configuration values can contain hierarchical data. Hierarchical objects are represented with the use of the `:` delimiter in the configuration keys. To access a configuration value, use the `:` character to delimit a hierarchy. For example, consider the following configuration values:
75+
76+
```json
77+
{
78+
"Parent": {
79+
"FavoriteNumber": 7,
80+
"Child": {
81+
"Name": "Example",
82+
"GrandChild": {
83+
"Age": 3
84+
}
85+
}
86+
}
87+
}
88+
```
89+
90+
The following table represents example keys and their corresponding values for the preceding example JSON:
91+
92+
| Key | Value |
93+
|---------------------------------|-------------|
94+
| `"Parent:FavoriteNumber"` | `7` |
95+
| `"Parent:Child:Name"` | `"Example"` |
96+
| `"Parent:Child:GrandChild:Age"` | `3` |
97+
5498
### Basic example
5599

56100
To access configuration values in their basic form, without the assistance of the _generic host_ approach, use the <xref:Microsoft.Extensions.Configuration.ConfigurationBuilder> type directly.
@@ -114,6 +158,18 @@ When you run this application, the `Host.CreateDefaultBuilder` defines the behav
114158
> [!TIP]
115159
> Using the raw `IConfiguration` instance in this way, while convenient, doesn't scale very well. When applications grow in complexity, and their corresponding configurations become more complex, we recommend that you use the [_options pattern_](options.md) as an alternative.
116160
161+
### Basic example with hosting and using the indexer API
162+
163+
Consider the same _appsettings.json_ file contents from the previous example:
164+
165+
:::code language="json" source="snippets/configuration/console-indexer/appsettings.json":::
166+
167+
Replace the contents of the _Program.cs_ file with the following C# code:
168+
169+
:::code language="csharp" source="snippets/configuration/console-indexer/Program.cs" highlight="11-15,17-22":::
170+
171+
The values are accessed using the indexer API where each key is a string, and the value is a string. Configuration supports properties, objects, arrays, and dictionaries.
172+
117173
## Configuration providers
118174

119175
The following table shows the configuration providers available to .NET Core apps.
@@ -130,6 +186,9 @@ The following table shows the configuration providers available to .NET Core app
130186
| [Memory configuration provider](configuration-providers.md#memory-configuration-provider) | In-memory collections |
131187
| [App secrets (Secret Manager)](/aspnet/core/security/app-secrets) | File in the user profile directory |
132188

189+
> [!TIP]
190+
> The order in which configuration providers are added matters. When multiple configuration providers are used and more than one provided specifies the same key, the last one added is used.
191+
133192
For more information on various configuration providers, see [Configuration providers in .NET](configuration-providers.md).
134193

135194
## See also
Lines changed: 16 additions & 0 deletions
Loading

docs/core/extensions/options.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,15 @@ title: Options pattern in .NET
33
author: IEvangelist
44
description: Learn how to use the options pattern to represent groups of related settings in .NET apps.
55
ms.author: dapine
6-
ms.date: 03/10/2022
6+
ms.date: 05/12/2022
77
---
88

99
# Options pattern in .NET
1010

1111
The options pattern uses classes to provide strongly-typed access to groups of related settings. When [configuration settings](configuration.md) are isolated by scenario into separate classes, the app adheres to two important software engineering principles:
1212

1313
- The [Interface Segregation Principle (ISP) or Encapsulation](../../architecture/modern-web-apps-azure/architectural-principles.md#encapsulation): Scenarios (classes) that depend on configuration settings depend only on the configuration settings that they use.
14-
- [Separation of Concerns](../../architecture/modern-web-apps-azure/architectural-principles.md#separation-of-concerns): Settings for different parts of the app aren't dependent or coupled to one another.
14+
- [Separation of Concerns](../../architecture/modern-web-apps-azure/architectural-principles.md#separation-of-concerns): Settings for different parts of the app aren't dependent or coupled with one another.
1515

1616
Options also provide a mechanism to validate configuration data. For more information, see the [Options validation](#options-validation) section.
1717

@@ -42,7 +42,7 @@ The following code is part of the _Program.cs_ C# file and:
4242

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

45-
[`ConfigurationBinder.Get<T>`](xref:Microsoft.Extensions.Configuration.ConfigurationBinder.Get%2A) 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 `TransientFaultHandlingOptions` class:
45+
[`ConfigurationBinder.Get<T>`](xref:Microsoft.Extensions.Configuration.ConfigurationBinder.Get%2A) binds and returns the specified type. `ConfigurationBinder.Get<T>` maybe more convenient than using `ConfigurationBinder.Bind`. The following code shows how to use `ConfigurationBinder.Get<T>` with the `TransientFaultHandlingOptions` class:
4646

4747
```csharp
4848
IConfigurationRoot configurationRoot = configuration.Build();
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
using Microsoft.Extensions.Configuration;
2+
using Microsoft.Extensions.DependencyInjection;
3+
using Microsoft.Extensions.Hosting;
4+
5+
using IHost host = Host.CreateDefaultBuilder(args).Build();
6+
7+
// Ask the service provider for the configuration abstraction.
8+
IConfiguration config = host.Services.GetRequiredService<IConfiguration>();
9+
10+
// Get values from the config given their key and their target type.
11+
string ipOne = config["IPAddressRange:0"];
12+
string ipTwo = config["IPAddressRange:1"];
13+
string ipThree = config["IPAddressRange:2"];
14+
string versionOne = config["SupportedVersions:v1"];
15+
string versionThree = config["SupportedVersions:v3"];
16+
17+
// Write the values to the console.
18+
Console.WriteLine($"IPAddressRange:0 = {ipOne}");
19+
Console.WriteLine($"IPAddressRange:1 = {ipTwo}");
20+
Console.WriteLine($"IPAddressRange:2 = {ipThree}");
21+
Console.WriteLine($"SupportedVersions:v1 = {versionOne}");
22+
Console.WriteLine($"SupportedVersions:v3 = {versionThree}");
23+
24+
// Application code which might rely on the config could start here.
25+
26+
await host.RunAsync();
27+
28+
// This will output the following:
29+
// IPAddressRange:0 = 46.36.198.123
30+
// IPAddressRange:1 = 46.36.198.124
31+
// IPAddressRange:2 = 46.36.198.125
32+
// SupportedVersions:v1 = 1.0.0
33+
// SupportedVersions:v3 = 3.0.7
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
{
2+
"SupportedVersions": {
3+
"v1": "1.0.0",
4+
"v3": "3.0.7"
5+
},
6+
"IPAddressRange": [
7+
"46.36.198.123",
8+
"46.36.198.124",
9+
"46.36.198.125"
10+
]
11+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<OutputType>Exe</OutputType>
5+
<TargetFramework>net6.0</TargetFramework>
6+
<Nullable>enable</Nullable>
7+
<ImplicitUsings>true</ImplicitUsings>
8+
</PropertyGroup>
9+
10+
<ItemGroup>
11+
<Content Include="appsettings.json">
12+
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
13+
</Content>
14+
</ItemGroup>
15+
16+
<ItemGroup>
17+
<PackageReference Include="Microsoft.Extensions.Hosting" Version="6.0.0" />
18+
</ItemGroup>
19+
20+
</Project>
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
public class NestedSettings
1+
public sealed class NestedSettings
22
{
33
public string Message { get; set; } = null!;
44
}

docs/core/extensions/snippets/configuration/console-raw/Settings.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
public class Settings
1+
public sealed class Settings
22
{
33
public int KeyOne { get; set; }
44
public bool KeyTwo { get; set; }

docs/core/extensions/snippets/configuration/console-raw/appsettings.json

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,18 @@
33
"KeyOne": 1,
44
"KeyTwo": true,
55
"KeyThree": {
6-
"Message": "Oh, that's nice..."
7-
}
6+
"Message": "Oh, that's nice...",
7+
"SupportedVersions": {
8+
"v1": "1.0.0",
9+
"v3": "3.0.7"
10+
}
11+
},
12+
"IPAddressRange": [
13+
"46.36.198.121",
14+
"46.36.198.122",
15+
"46.36.198.123",
16+
"46.36.198.124",
17+
"46.36.198.125"
18+
]
819
}
920
}

0 commit comments

Comments
 (0)