Description
Description
Potentially related/similar: #36390
Using .NET 6 and Microsoft.Extensions.Configuration
v6 to bind key-value pairs to an IReadOnlyDictionary
doesn't work if the property is initialized (to an empty Dictionary).
It works when using .NET 8 and Microsoft.Extensions.Configuration
v8, but I'm not sure whether there's some fix that needs to be done internally so that this issue doesn't show up in some other scenario.
I also want to validate that the suggested workaround is the best way to move forward.
Reproduction Steps
Repro in Bind-Not-Null-IReadOnlyDictionary repo
git clone https://github.com/eduherminio/Bind-Not-Null-IReadOnlyDictionary IReadOnlyDictionary
cd IReadOnlyDictionary
dotnet run --framework net8.0
dotnet run --framework net6.0
, opt => opt.ErrorOnUnknownConfiguration = true
can be uncommented to see the exception described below.
Expected behavior
Binding to an initialized IReadOnlyDictionary
works
{
"Options": {
"Enabled": true,
"Fields": {
"Name": "",
"Id": "1"
}
}
}
public class MyOptions
{
public bool Enabled { get; set; } = false;
public IReadOnlyDictionary<string, object> Fields { get; set; } = new Dictionary<string, object>();
}
Actual behavior
Binding to an initialized IReadOnlyDictionary
doesn't work and it shows up as empty
With ErrorOnUnknownConfiguration = true
the following exception shows up:
Unhandled exception. System.InvalidOperationException: 'ErrorOnUnknownConfiguration' was set on the provided BinderOptions, but the following properties were not found on the instance of System.Collections.Generic.Dictionary`2[System.String,System.Object]: 'Id', 'Name'
at Microsoft.Extensions.Configuration.ConfigurationBinder.BindNonScalar(IConfiguration configuration, Object instance, BinderOptions options)
at Microsoft.Extensions.Configuration.ConfigurationBinder.BindInstance(Type type, Object instance, IConfiguration config, BinderOptions options)
at Microsoft.Extensions.Configuration.ConfigurationBinder.GetPropertyValue(PropertyInfo property, Object instance, IConfiguration config, BinderOptions options)
at Microsoft.Extensions.Configuration.ConfigurationBinder.BindProperty(PropertyInfo property, Object instance, IConfiguration config, BinderOptions options)
at Microsoft.Extensions.Configuration.ConfigurationBinder.BindNonScalar(IConfiguration configuration, Object instance, BinderOptions options)
at Microsoft.Extensions.Configuration.ConfigurationBinder.BindInstance(Type type, Object instance, IConfiguration config, BinderOptions options)
at Microsoft.Extensions.Configuration.ConfigurationBinder.Bind(IConfiguration configuration, Object instance, Action`1 configureOptions)
at Program.<Main>$(String[] args) in C:\dev\dotnet\IReadOnlyDictionaryIssue\Program.cs:line 10
Regression?
No response
Known Workarounds
Our use case is a library targeting .NET 6 and .NET 8, so not initializing the IReadOnlyDictionary
is one of the workarounds
public IReadOnlyDictionary<string, object> Fields { get; set; }
//#if NET8_0_OR_GREATER
// = new Dictionary<string, object>();
//#else
// = null!;
//#endif
Another one would be to avoid using IReadOnlyDictionary
, but in our case we can't change our API surface like that.
Can you think of any other workaround that doesn't imply pinky promising that the property will be initialized somewhere?
Configuration
.NET SDK 6.0.424
, .NET runtime Microsoft.NETCore.App 6.0.32
<PackageReference Include="Microsoft.Extensions.Configuration" Version="6.0.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="6.0.0" />
<PackageReference Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="6.0.0" />
Other information
No response