Skip to content

[Breaking change]: ConfigurationBinder raises exceptions if ErrorOnUnknownConfiguration is set #32175

@SteveDunn

Description

@SteveDunn

Description

If BinderOptions.ErrorOnUnknownConfiguration is set and a value in specified in config that cannot be bound to the corresponding property in the bound model, an InvalidOperationException is now thrown.

Previously, BinderOptions.ErrorOnUnknownConfiguration was solely used to raise an exception if a value existed in config but didn't exist in the model being bound to.

As part of PR dotnet/runtime#77708 (which fixes #73915), this property is now also used to throw exceptions if the value in config cannot be converted to the type of value in the model being bound to.

Version

.NET 8 Preview 1

Previous behavior

Previously, this would silently swallow the exceptions for the fields containing invalid enums:

public enum TestSettingsEnum
{
    Option1,
    Option2,
}

public class MyModelContainingArray
{
    public TestSettingsEnum[] Enums { get; set; }
}

public void SilentlySwallowsInvalidItems()
{
    var dic = new Dictionary<string, string>
        {
            {"Section:Enums:0", "Option1"},
            {"Section:Enums:1", "Option3"}, // invalid - ignored
            {"Section:Enums:2", "Option4"}, // invalid - ignored
            {"Section:Enums:3", "Option2"},
        };

    var configurationBuilder = new ConfigurationBuilder();
    configurationBuilder.AddInMemoryCollection(dic);
    var config = configurationBuilder.Build();
    var configSection = config.GetSection("Section");

    var model = configSection.Get<MyModelContainingArray>(o => o.ErrorOnUnknownConfiguration = true);

    // we previously would end up with just Option1 and Option2 in the bound collection
}

New behavior

Now, if the value cannot be converted to the type of the value in the model, an InvalidOperationException is thrown.

Type of breaking change

  • Binary incompatible: Existing binaries may encounter a breaking change in behavior, such as failure to load/execute or different run-time behavior.
  • Source incompatible: Source code may encounter a breaking change in behavior when targeting the new runtime/component/SDK, such as compile errors or different run-time behavior.

Reason for change

In the bug report, users were setting BinderOptions.ErrorOnUnknownConfiguration and expecting that to throw if there were any issues in binding configuration.

But the original intention of it was to just throw if something was missing from the bound model.

Perhaps if I'd originally chosen a clearer name, this might've avoided this confusion. I suggested adding another property in BinderOptions, but we went instead with making the existing property dual purpose.

Recommended action

The recommended action is to change or remove the configuration values that cannot be converted to the properties in the bound model.

Alternatively, change BinderOptions.ErrorOnUnknownConfiguration from true to false

Feature area

Core .NET libraries, Serialization

Affected APIs

All of the following in ConfigurationBinder:

  • public static T? Get<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] T>(this IConfiguration configuration, Action<BinderOptions>? configureOptions)
  • public static object? Get(this IConfiguration configuration, Type type, Action<BinderOptions>? configureOptions)
  • public static void Bind(this IConfiguration configuration, object? instance, Action<BinderOptions>? configureOptions)

Associated WorkItem - 61240

Metadata

Metadata

Assignees

Labels

🏁 Release: .NET 8Work items for the .NET 8 release📌 seQUESTeredIdentifies that an issue has been imported into Quest.binary incompatibleExisting binaries may encounter a breaking change in behavior.breaking-changeIndicates a .NET Core breaking change

Type

No type

Projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions