From d464f3923835dbfe792194be198d5d6f5890fe7c Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 6 Feb 2026 16:28:16 +0000 Subject: [PATCH 1/6] Initial plan From 38a80153bcfd3be5efe017b66a1d4e159dc7233f Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 6 Feb 2026 16:32:04 +0000 Subject: [PATCH 2/6] Add comprehensive binding scenarios documentation with code examples Co-authored-by: gewarren <24882762+gewarren@users.noreply.github.com> --- docs/core/extensions/configuration.md | 55 ++++++++ .../DictionaryBinding.csproj | 15 ++ .../DictionaryBinding/Program.cs | 129 ++++++++++++++++++ 3 files changed, 199 insertions(+) create mode 100644 docs/core/extensions/snippets/configuration/binding-scenarios/DictionaryBinding/DictionaryBinding.csproj create mode 100644 docs/core/extensions/snippets/configuration/binding-scenarios/DictionaryBinding/Program.cs diff --git a/docs/core/extensions/configuration.md b/docs/core/extensions/configuration.md index e776960db98b6..f6fb70086fde7 100644 --- a/docs/core/extensions/configuration.md +++ b/docs/core/extensions/configuration.md @@ -110,6 +110,61 @@ The following table represents example keys and their corresponding values for t | `"Parent:Child:Name"` | `"Example"` | | `"Parent:Child:GrandChild:Age"` | `3` | +#### Advanced binding scenarios + +The configuration binder has specific behaviors and limitations when working with certain types. Understanding these scenarios helps avoid common pitfalls. + +##### Binding to dictionaries + +When binding configuration to a where the value is a mutable collection type (like arrays or lists), binding behavior changed in .NET 7. Starting with .NET 7, binding to the same key multiple times extends the collection values instead of replacing them. For more information, see [Binding config to dictionary extends values](../compatibility/extensions/7.0/config-bind-dictionary.md). + +The following example demonstrates this behavior: + +:::code language="csharp" source="snippets/configuration/binding-scenarios/DictionaryBinding/Program.cs" id="DictionaryWithCollectionValues"::: + +In .NET 7 and later, each bind operation adds to the existing collection values rather than replacing them entirely. + +##### Dictionary keys with colons + +The colon (`:`) character is reserved as a hierarchy delimiter in configuration keys. This means you cannot use colons in dictionary keys when binding configuration. If your keys contain colons (such as URLs or other formatted identifiers), the configuration system will interpret them as hierarchy paths rather than literal characters. + +The following example shows this limitation: + +:::code language="csharp" source="snippets/configuration/binding-scenarios/DictionaryBinding/Program.cs" id="DictionaryKeysWithColons"::: + +**Workarounds for keys with colons:** + +- Use alternative delimiter characters (such as double underscores `__`) in your configuration keys and transform them programmatically if needed. +- Manually deserialize the configuration as raw JSON using or a similar library, which supports colons in keys. +- Create a custom mapping layer that translates safe keys to your desired keys with colons. + +##### Binding to IReadOnly* types + +The configuration binder doesn't support binding directly to `IReadOnlyList`, `IReadOnlyDictionary`, or other read-only collection interfaces. These interfaces lack the mechanisms the binder needs to populate the collections. + +To work with read-only collections, use mutable types for the properties that the binder populates, then expose them as read-only interfaces for consumers: + +:::code language="csharp" source="snippets/configuration/binding-scenarios/DictionaryBinding/Program.cs" id="IReadOnlyCollections"::: + +The configuration class implementation: + +:::code language="csharp" source="snippets/configuration/binding-scenarios/DictionaryBinding/Program.cs" id="SettingsWithReadOnly"::: + +This approach allows the binder to populate the mutable `List` while presenting an immutable interface to consumers through `IReadOnlyList`. + +##### Binding with parameterized constructors + +Starting with .NET 7, the configuration binder supports binding to types with a single public parameterized constructor. This enables immutable types and records to be populated directly from configuration: + +:::code language="csharp" source="snippets/configuration/binding-scenarios/DictionaryBinding/Program.cs" id="ParameterizedConstructor"::: + +The immutable settings class: + +:::code language="csharp" source="snippets/configuration/binding-scenarios/DictionaryBinding/Program.cs" id="AppSettings"::: + +> [!IMPORTANT] +> The binder only supports types with a single public parameterized constructor. If a type has multiple public parameterized constructors, the binder cannot determine which one to use and binding will fail. Use either a single parameterized constructor or a parameterless constructor with property setters. + ### Basic example To access configuration values in their basic form, without the assistance of the _generic host_ approach, use the type directly. diff --git a/docs/core/extensions/snippets/configuration/binding-scenarios/DictionaryBinding/DictionaryBinding.csproj b/docs/core/extensions/snippets/configuration/binding-scenarios/DictionaryBinding/DictionaryBinding.csproj new file mode 100644 index 0000000000000..334bd58ed8ae3 --- /dev/null +++ b/docs/core/extensions/snippets/configuration/binding-scenarios/DictionaryBinding/DictionaryBinding.csproj @@ -0,0 +1,15 @@ + + + + Exe + net10.0 + enable + enable + + + + + + + + diff --git a/docs/core/extensions/snippets/configuration/binding-scenarios/DictionaryBinding/Program.cs b/docs/core/extensions/snippets/configuration/binding-scenarios/DictionaryBinding/Program.cs new file mode 100644 index 0000000000000..600a4a149b505 --- /dev/null +++ b/docs/core/extensions/snippets/configuration/binding-scenarios/DictionaryBinding/Program.cs @@ -0,0 +1,129 @@ +using Microsoft.Extensions.Configuration; + +// +// Demo: Dictionary binding with collection values extends, not replaces (since .NET 7) +IConfiguration config = new ConfigurationBuilder() + .AddInMemoryCollection() + .Build(); + +config["Queue:0"] = "Value1"; +var dict = new Dictionary() { { "Queue", new[] { "InitialValue" } } }; + +Console.WriteLine("=== Dictionary Binding with Collection Values ==="); +Console.WriteLine($"Initially: {string.Join(", ", dict["Queue"])}"); + +// In .NET 7+, binding extends the collection instead of replacing it +config.Bind(dict); +Console.WriteLine($"After Bind: {string.Join(", ", dict["Queue"])}"); + +config["Queue:1"] = "Value2"; +config.Bind(dict); +Console.WriteLine($"After 2nd Bind: {string.Join(", ", dict["Queue"])}"); +// + +Console.WriteLine(); + +// +// Demo: Colons in dictionary keys are NOT supported (used as hierarchy delimiter) +Console.WriteLine("=== Dictionary Keys with Colons (NOT Supported) ==="); + +var colonConfig = new ConfigurationBuilder() + .AddInMemoryCollection(new Dictionary + { + // Attempting to use a colon in a key - will be interpreted as hierarchy + ["MyDict:key__with__colon"] = "value1", // Use double underscore as workaround + ["MyDict:normalkey"] = "value2" + }) + .Build(); + +var dictWithKeys = new Dictionary(); +colonConfig.GetSection("MyDict").Bind(dictWithKeys); + +Console.WriteLine("Keys retrieved from config:"); +foreach (var kvp in dictWithKeys) +{ + Console.WriteLine($" '{kvp.Key}' = '{kvp.Value}'"); +} +Console.WriteLine("Note: Use alternative delimiters (like '__') instead of colons in keys"); +// + +Console.WriteLine(); + +// +// Demo: IReadOnly* types are NOT directly bindable - use mutable types +Console.WriteLine("=== IReadOnly* Types (NOT Directly Supported) ==="); + +var readonlyConfig = new ConfigurationBuilder() + .AddInMemoryCollection(new Dictionary + { + ["Settings:Values:0"] = "Item1", + ["Settings:Values:1"] = "Item2", + ["Settings:Values:2"] = "Item3", + }) + .Build(); + +// This class uses List for binding, exposes as IReadOnlyList +var settings = new SettingsWithReadOnly(); +readonlyConfig.GetSection("Settings").Bind(settings); + +Console.WriteLine("Values bound to mutable List, exposed as IReadOnlyList:"); +foreach (var value in settings.ValuesReadOnly) +{ + Console.WriteLine($" {value}"); +} +// + +Console.WriteLine(); + +// +// Demo: Single parameterized constructor binding (supported in .NET 7+) +Console.WriteLine("=== Parameterized Constructor Binding ==="); + +var ctorConfig = new ConfigurationBuilder() + .AddInMemoryCollection(new Dictionary + { + ["AppSettings:Name"] = "MyApp", + ["AppSettings:MaxConnections"] = "100", + ["AppSettings:Timeout"] = "30" + }) + .Build(); + +// Binding to a type with a single parameterized constructor +var appSettings = ctorConfig.GetSection("AppSettings").Get(); +if (appSettings != null) +{ + Console.WriteLine($"Name: {appSettings.Name}"); + Console.WriteLine($"MaxConnections: {appSettings.MaxConnections}"); + Console.WriteLine($"Timeout: {appSettings.Timeout}"); +} + +Console.WriteLine("\nNote: Multiple parameterized constructors are NOT supported."); +// + +// +class SettingsWithReadOnly +{ + // Use mutable type for binding + public List Values { get; set; } = new(); + + // Expose as read-only for consumers + public IReadOnlyList ValuesReadOnly => Values; +} +// + +// +// Immutable type with single parameterized constructor +class AppSettings +{ + public string Name { get; } + public int MaxConnections { get; } + public int Timeout { get; } + + public AppSettings(string name, int maxConnections, int timeout) + { + Name = name; + MaxConnections = maxConnections; + Timeout = timeout; + } +} +// From 961ae07d75e6cc294695a65440dccc331e974e13 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 6 Feb 2026 16:33:10 +0000 Subject: [PATCH 3/6] Address code review feedback: improve clarity and examples Co-authored-by: gewarren <24882762+gewarren@users.noreply.github.com> --- docs/core/extensions/configuration.md | 2 +- .../binding-scenarios/DictionaryBinding/Program.cs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/core/extensions/configuration.md b/docs/core/extensions/configuration.md index f6fb70086fde7..afa883594886e 100644 --- a/docs/core/extensions/configuration.md +++ b/docs/core/extensions/configuration.md @@ -116,7 +116,7 @@ The configuration binder has specific behaviors and limitations when working wit ##### Binding to dictionaries -When binding configuration to a where the value is a mutable collection type (like arrays or lists), binding behavior changed in .NET 7. Starting with .NET 7, binding to the same key multiple times extends the collection values instead of replacing them. For more information, see [Binding config to dictionary extends values](../compatibility/extensions/7.0/config-bind-dictionary.md). +When you bind configuration to a where the value is a mutable collection type (like arrays or lists), the behavior changed in .NET 7. Starting with .NET 7, repeated binds to the same key extend the collection values instead of replacing them. For more information, see [Binding config to dictionary extends values](../compatibility/extensions/7.0/config-bind-dictionary.md). The following example demonstrates this behavior: diff --git a/docs/core/extensions/snippets/configuration/binding-scenarios/DictionaryBinding/Program.cs b/docs/core/extensions/snippets/configuration/binding-scenarios/DictionaryBinding/Program.cs index 600a4a149b505..af4ff852b2d68 100644 --- a/docs/core/extensions/snippets/configuration/binding-scenarios/DictionaryBinding/Program.cs +++ b/docs/core/extensions/snippets/configuration/binding-scenarios/DictionaryBinding/Program.cs @@ -30,8 +30,8 @@ var colonConfig = new ConfigurationBuilder() .AddInMemoryCollection(new Dictionary { - // Attempting to use a colon in a key - will be interpreted as hierarchy - ["MyDict:key__with__colon"] = "value1", // Use double underscore as workaround + // Using double underscore instead of colon (e.g., "http://example.com" becomes "http__//example.com") + ["MyDict:http__//example.com"] = "value1", ["MyDict:normalkey"] = "value2" }) .Build(); From 1ef0dcaf83e40b62587039457893c2eb47e5dd74 Mon Sep 17 00:00:00 2001 From: Genevieve Warren <24882762+gewarren@users.noreply.github.com> Date: Fri, 6 Feb 2026 10:06:11 -0800 Subject: [PATCH 4/6] human edits --- .../extensions/7.0/config-bind-dictionary.md | 2 +- docs/core/extensions/configuration.md | 73 +++++++++---------- .../DictionaryBinding/Program.cs | 37 +--------- 3 files changed, 41 insertions(+), 71 deletions(-) diff --git a/docs/core/compatibility/extensions/7.0/config-bind-dictionary.md b/docs/core/compatibility/extensions/7.0/config-bind-dictionary.md index 810f1f6ef4b15..0b64cc5c87cde 100644 --- a/docs/core/compatibility/extensions/7.0/config-bind-dictionary.md +++ b/docs/core/compatibility/extensions/7.0/config-bind-dictionary.md @@ -5,7 +5,7 @@ ms.date: 08/02/2023 --- # Binding config to dictionary extends values -When binding a configuration using a object where the value is a mutable collection type, binding to the same key more than once now extends the values collection instead of replacing the whole collection with the new value. +When binding a configuration using a object where the value is a mutable collection type, binding to the same key more than once now extends the values collection instead of replacing the whole collection with the new value. ## Version introduced diff --git a/docs/core/extensions/configuration.md b/docs/core/extensions/configuration.md index afa883594886e..220d53a8ebf89 100644 --- a/docs/core/extensions/configuration.md +++ b/docs/core/extensions/configuration.md @@ -14,7 +14,7 @@ Configuration in .NET is performed using one or more [configuration providers](# - [Azure Key Vault](/azure/key-vault/general/overview) - [Azure App Configuration](/azure/azure-app-configuration/overview) - Command-line arguments -- Custom providers, installed or created +- Custom providers (installed or created) - Directory files - In-memory .NET objects - Third-party providers @@ -30,7 +30,7 @@ Given one or more configuration sources, the and related types. +.NET console apps created using the [dotnet new](../tools/dotnet-new.md) command template or Visual Studio by default *don't* expose configuration capabilities. To add configuration in a new .NET console application, [add a package reference](../tools/dotnet-package-add.md) to [📦 Microsoft.Extensions.Configuration](https://www.nuget.org/packages/Microsoft.Extensions.Configuration). This package is the foundation for configuration in .NET apps. It provides the and related types. :::code source="snippets/configuration/console-basic-builder/Program.cs"::: @@ -41,11 +41,11 @@ The preceding code: - Calls the method to create an instance. - Writes the value of the `SomeKey` key to the console. -While this example uses an in-memory configuration, there are many configuration providers available, exposing functionality for file-based, environment variables, command line arguments, and other configuration sources. For more information, see [Configuration providers in .NET](configuration-providers.md). +While this example uses an in-memory configuration, there are many configuration providers available, exposing functionality for file-based, environment variables, command-line arguments, and other configuration sources. For more information, see [Configuration providers in .NET](configuration-providers.md). -### Alternative hosting approach +## Alternative hosting approach -Commonly, your apps will do more than just read configuration. They'll likely use dependency injection, logging, and other services. The [.NET Generic Host](generic-host.md) approach is recommended for apps that use these services. Instead, consider [adding a package reference](../tools/dotnet-package-add.md) to [Microsoft.Extensions.Hosting](https://www.nuget.org/packages/Microsoft.Extensions.Hosting). Modify the *Program.cs* file to match the following code: +Commonly, your apps will do more than just read configuration. They'll likely use dependency injection, logging, and other services. The [.NET Generic Host](generic-host.md) approach is recommended for apps that use these services. Instead, consider [adding a package reference](../tools/dotnet-package-add.md) to [📦 Microsoft.Extensions.Hosting](https://www.nuget.org/packages/Microsoft.Extensions.Hosting). Modify the *Program.cs* file to match the following code: :::code source="snippets/configuration/console/Program.cs" highlight="3"::: @@ -60,9 +60,9 @@ The - Properties are ignored if they have private setters or their type can't be converted. > - Properties without corresponding configuration keys are ignored. -#### Binding hierarchies +### Binding hierarchies 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: @@ -110,35 +110,34 @@ The following table represents example keys and their corresponding values for t | `"Parent:Child:Name"` | `"Example"` | | `"Parent:Child:GrandChild:Age"` | `3` | -#### Advanced binding scenarios +### Advanced binding scenarios -The configuration binder has specific behaviors and limitations when working with certain types. Understanding these scenarios helps avoid common pitfalls. +The configuration binder has specific behaviors and limitations when working with certain types. This section includes the following subsections: -##### Binding to dictionaries +- [Bind to dictionaries](#bind-to-dictionaries) +- [Dictionary keys with colons](#dictionary-keys-with-colons) +- [Bind to IReadOnly* types](#bind-to-ireadonly-types) +- [Bind with parameterized constructors](#bind-with-parameterized-constructors) -When you bind configuration to a where the value is a mutable collection type (like arrays or lists), the behavior changed in .NET 7. Starting with .NET 7, repeated binds to the same key extend the collection values instead of replacing them. For more information, see [Binding config to dictionary extends values](../compatibility/extensions/7.0/config-bind-dictionary.md). +#### Bind to dictionaries + +When you bind configuration to a where the value is a mutable collection type (like arrays or lists), repeated binds to the same key extend the collection values instead of replacing them. The following example demonstrates this behavior: :::code language="csharp" source="snippets/configuration/binding-scenarios/DictionaryBinding/Program.cs" id="DictionaryWithCollectionValues"::: -In .NET 7 and later, each bind operation adds to the existing collection values rather than replacing them entirely. - -##### Dictionary keys with colons - -The colon (`:`) character is reserved as a hierarchy delimiter in configuration keys. This means you cannot use colons in dictionary keys when binding configuration. If your keys contain colons (such as URLs or other formatted identifiers), the configuration system will interpret them as hierarchy paths rather than literal characters. - -The following example shows this limitation: +For more information, see [Binding config to dictionary extends values](../compatibility/extensions/7.0/config-bind-dictionary.md). -:::code language="csharp" source="snippets/configuration/binding-scenarios/DictionaryBinding/Program.cs" id="DictionaryKeysWithColons"::: +#### Dictionary keys with colons -**Workarounds for keys with colons:** +The colon (`:`) character is reserved as a hierarchy delimiter in configuration keys. This means you can't use colons in dictionary keys when binding configuration. If your keys contain colons (such as URLs or other formatted identifiers), the configuration system interprets them as hierarchy paths rather than literal characters. Consider the following workarounds: - Use alternative delimiter characters (such as double underscores `__`) in your configuration keys and transform them programmatically if needed. - Manually deserialize the configuration as raw JSON using or a similar library, which supports colons in keys. - Create a custom mapping layer that translates safe keys to your desired keys with colons. -##### Binding to IReadOnly* types +#### Bind to IReadOnly\* types The configuration binder doesn't support binding directly to `IReadOnlyList`, `IReadOnlyDictionary`, or other read-only collection interfaces. These interfaces lack the mechanisms the binder needs to populate the collections. @@ -152,7 +151,7 @@ The configuration class implementation: This approach allows the binder to populate the mutable `List` while presenting an immutable interface to consumers through `IReadOnlyList`. -##### Binding with parameterized constructors +#### Bind with parameterized constructors Starting with .NET 7, the configuration binder supports binding to types with a single public parameterized constructor. This enables immutable types and records to be populated directly from configuration: @@ -165,7 +164,7 @@ The immutable settings class: > [!IMPORTANT] > The binder only supports types with a single public parameterized constructor. If a type has multiple public parameterized constructors, the binder cannot determine which one to use and binding will fail. Use either a single parameterized constructor or a parameterless constructor with property setters. -### Basic example +## Basic example To access configuration values in their basic form, without the assistance of the _generic host_ approach, use the type directly. @@ -203,7 +202,7 @@ The `Settings` object is shaped as follows: :::code source="snippets/configuration/console-raw/NestedSettings.cs"::: -### Basic example with hosting +## Basic example with hosting To access the `IConfiguration` value, you can rely again on the [`Microsoft.Extensions.Hosting`](https://www.nuget.org/packages/Microsoft.Extensions.Hosting) NuGet package. Create a new console application, and paste the following project file contents into it: @@ -228,7 +227,7 @@ When you run this application, the `Host.CreateApplicationBuilder` defines the b > [!TIP] > 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. -### Basic example with hosting and using the indexer API +## Basic example with hosting and using the indexer API Consider the same _appsettings.json_ file contents from the previous example: @@ -244,17 +243,17 @@ The values are accessed using the indexer API where each key is a string, and th The following table shows the configuration providers available to .NET Core apps. -| Provider | Provides configuration from | -|------------------------------------------------------------------------------------------------------------------------|------------------------------------| -| [Azure App configuration provider](/azure/azure-app-configuration/quickstart-aspnet-core-app) | Azure App Configuration | -| [Azure Key Vault configuration provider](/azure/key-vault/general/tutorial-net-virtual-machine) | Azure Key Vault | -| [Command-line configuration provider](configuration-providers.md#command-line-configuration-provider) | Command-line parameters | -| [Custom configuration provider](custom-configuration-provider.md) | Custom source | -| [Environment Variables configuration provider](configuration-providers.md#environment-variable-configuration-provider) | Environment variables | -| [File configuration provider](configuration-providers.md#file-configuration-provider) | JSON, XML, and INI files | -| [Key-per-file configuration provider](configuration-providers.md#key-per-file-configuration-provider) | Directory files | -| [Memory configuration provider](configuration-providers.md#memory-configuration-provider) | In-memory collections | -| [App secrets (Secret Manager)](/aspnet/core/security/app-secrets) | File in the user profile directory | +| Configuration provider | Provides configuration from | +|--------------------------------------------------------------------------------|-----------------------------| +| [Azure app](/azure/azure-app-configuration/quickstart-aspnet-core-app) | Azure App Configuration | +| [Azure Key Vault](/azure/key-vault/general/tutorial-net-virtual-machine) | Azure Key Vault | +| [Command-line](configuration-providers.md#command-line-configuration-provider) | Command-line parameters | +| [Custom](custom-configuration-provider.md) | Custom source | +| [Environment variables](configuration-providers.md#environment-variable-configuration-provider) | Environment variables | +| [File](configuration-providers.md#file-configuration-provider) | JSON, XML, and INI files | +| [Key-per-file](configuration-providers.md#key-per-file-configuration-provider) | Directory files | +| [Memory](configuration-providers.md#memory-configuration-provider) | In-memory collections | +| [App secrets (secret manager)](/aspnet/core/security/app-secrets) | File in the user profile directory | > [!TIP] > The order in which configuration providers are added matters. When multiple configuration providers are used and more than one provider specifies the same key, the last one added is used. diff --git a/docs/core/extensions/snippets/configuration/binding-scenarios/DictionaryBinding/Program.cs b/docs/core/extensions/snippets/configuration/binding-scenarios/DictionaryBinding/Program.cs index af4ff852b2d68..c6df7a0b7742b 100644 --- a/docs/core/extensions/snippets/configuration/binding-scenarios/DictionaryBinding/Program.cs +++ b/docs/core/extensions/snippets/configuration/binding-scenarios/DictionaryBinding/Program.cs @@ -1,7 +1,6 @@ using Microsoft.Extensions.Configuration; // -// Demo: Dictionary binding with collection values extends, not replaces (since .NET 7) IConfiguration config = new ConfigurationBuilder() .AddInMemoryCollection() .Build(); @@ -12,7 +11,7 @@ Console.WriteLine("=== Dictionary Binding with Collection Values ==="); Console.WriteLine($"Initially: {string.Join(", ", dict["Queue"])}"); -// In .NET 7+, binding extends the collection instead of replacing it +// In .NET 7+, binding extends the collection instead of replacing it. config.Bind(dict); Console.WriteLine($"After Bind: {string.Join(", ", dict["Queue"])}"); @@ -23,34 +22,9 @@ Console.WriteLine(); -// -// Demo: Colons in dictionary keys are NOT supported (used as hierarchy delimiter) -Console.WriteLine("=== Dictionary Keys with Colons (NOT Supported) ==="); - -var colonConfig = new ConfigurationBuilder() - .AddInMemoryCollection(new Dictionary - { - // Using double underscore instead of colon (e.g., "http://example.com" becomes "http__//example.com") - ["MyDict:http__//example.com"] = "value1", - ["MyDict:normalkey"] = "value2" - }) - .Build(); - -var dictWithKeys = new Dictionary(); -colonConfig.GetSection("MyDict").Bind(dictWithKeys); - -Console.WriteLine("Keys retrieved from config:"); -foreach (var kvp in dictWithKeys) -{ - Console.WriteLine($" '{kvp.Key}' = '{kvp.Value}'"); -} -Console.WriteLine("Note: Use alternative delimiters (like '__') instead of colons in keys"); -// - Console.WriteLine(); // -// Demo: IReadOnly* types are NOT directly bindable - use mutable types Console.WriteLine("=== IReadOnly* Types (NOT Directly Supported) ==="); var readonlyConfig = new ConfigurationBuilder() @@ -62,7 +36,7 @@ }) .Build(); -// This class uses List for binding, exposes as IReadOnlyList +// This class uses List for binding, exposes as IReadOnlyList. var settings = new SettingsWithReadOnly(); readonlyConfig.GetSection("Settings").Bind(settings); @@ -76,7 +50,6 @@ Console.WriteLine(); // -// Demo: Single parameterized constructor binding (supported in .NET 7+) Console.WriteLine("=== Parameterized Constructor Binding ==="); var ctorConfig = new ConfigurationBuilder() @@ -96,15 +69,13 @@ Console.WriteLine($"MaxConnections: {appSettings.MaxConnections}"); Console.WriteLine($"Timeout: {appSettings.Timeout}"); } - -Console.WriteLine("\nNote: Multiple parameterized constructors are NOT supported."); // // class SettingsWithReadOnly { // Use mutable type for binding - public List Values { get; set; } = new(); + public List Values { get; set; } = []; // Expose as read-only for consumers public IReadOnlyList ValuesReadOnly => Values; @@ -112,7 +83,7 @@ class SettingsWithReadOnly // // -// Immutable type with single parameterized constructor +// Immutable type with single parameterized constructor. class AppSettings { public string Name { get; } From 6bab73aa86ac90fbc6482922b70ca2343d7efdde Mon Sep 17 00:00:00 2001 From: Genevieve Warren <24882762+gewarren@users.noreply.github.com> Date: Fri, 6 Feb 2026 10:29:01 -0800 Subject: [PATCH 5/6] Apply suggestions from code review Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- docs/core/extensions/configuration.md | 2 +- .../binding-scenarios/DictionaryBinding/Program.cs | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/docs/core/extensions/configuration.md b/docs/core/extensions/configuration.md index 220d53a8ebf89..41628bbae8d25 100644 --- a/docs/core/extensions/configuration.md +++ b/docs/core/extensions/configuration.md @@ -245,7 +245,7 @@ The following table shows the configuration providers available to .NET Core app | Configuration provider | Provides configuration from | |--------------------------------------------------------------------------------|-----------------------------| -| [Azure app](/azure/azure-app-configuration/quickstart-aspnet-core-app) | Azure App Configuration | +| [Azure App Configuration](/azure/azure-app-configuration/quickstart-aspnet-core-app) | Azure App Configuration | | [Azure Key Vault](/azure/key-vault/general/tutorial-net-virtual-machine) | Azure Key Vault | | [Command-line](configuration-providers.md#command-line-configuration-provider) | Command-line parameters | | [Custom](custom-configuration-provider.md) | Custom source | diff --git a/docs/core/extensions/snippets/configuration/binding-scenarios/DictionaryBinding/Program.cs b/docs/core/extensions/snippets/configuration/binding-scenarios/DictionaryBinding/Program.cs index c6df7a0b7742b..2ace93416077f 100644 --- a/docs/core/extensions/snippets/configuration/binding-scenarios/DictionaryBinding/Program.cs +++ b/docs/core/extensions/snippets/configuration/binding-scenarios/DictionaryBinding/Program.cs @@ -22,8 +22,6 @@ Console.WriteLine(); -Console.WriteLine(); - // Console.WriteLine("=== IReadOnly* Types (NOT Directly Supported) ==="); From d1ab9b069f0b28d5913894e1d16bafdacbe55ee3 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 6 Feb 2026 18:31:43 +0000 Subject: [PATCH 6/6] Update package versions to 10.0.2 and add ai-usage metadata Co-authored-by: gewarren <24882762+gewarren@users.noreply.github.com> --- docs/core/extensions/configuration.md | 1 + .../DictionaryBinding/DictionaryBinding.csproj | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/core/extensions/configuration.md b/docs/core/extensions/configuration.md index 41628bbae8d25..b83db3d94099a 100644 --- a/docs/core/extensions/configuration.md +++ b/docs/core/extensions/configuration.md @@ -3,6 +3,7 @@ title: Configuration description: Learn how to use the Configuration API to configure .NET applications. Explore various inbuilt configuration providers. ms.date: 10/09/2024 ms.topic: overview +ai-usage: ai-assisted --- # Configuration in .NET diff --git a/docs/core/extensions/snippets/configuration/binding-scenarios/DictionaryBinding/DictionaryBinding.csproj b/docs/core/extensions/snippets/configuration/binding-scenarios/DictionaryBinding/DictionaryBinding.csproj index 334bd58ed8ae3..f3dc8bbb1bba2 100644 --- a/docs/core/extensions/snippets/configuration/binding-scenarios/DictionaryBinding/DictionaryBinding.csproj +++ b/docs/core/extensions/snippets/configuration/binding-scenarios/DictionaryBinding/DictionaryBinding.csproj @@ -8,8 +8,8 @@ - - + +