-
Notifications
You must be signed in to change notification settings - Fork 5.4k
Description
Description
Hello, I have a question regarding the behavior of IConfiguration.Get().
In a .NET application, we use IConfiguration.Get() (which internally uses ConfigurationBinder) to read configuration values.
When upgrading the target framework from .NET 6 to .NET 8, and updating the Microsoft.Extensions.Configuration packages from 6.x to 8.x, we noticed that the binding behavior for array (or array-like) properties has changed.
1. What I already understand (Breaking change)
I’m aware of the .NET 8 breaking change where:
ConfigurationBinder.Get<T>(..., options => options.ErrorOnUnknownConfiguration = true)
will now throw an exception when a value cannot be converted to the destination type.
However, the behavior I’m asking about is the default behavior of IConfiguration.Get() when no BinderOptions are specified.
2. What I would like to confirm
With the default IConfiguration.Get() (no options), the behavior when an array element fails type conversion seems to differ
between .NET 6 and .NET 8.
Is this behavior:
- an intended change in .NET 7/8+,a regression, or a documentation gap?
Reproduction Steps
Reproduction (simplified)
appsettings.json
{
"ApiUrl": "https://example.com/api",
"Timeout": 5,
"OutputPath": "./output",
"List": [
{
"Name": "A",
"Address": "AA",
"Interval": 10
},
{
"Name": "B",
"Address": "BB",
"Interval": "a"
}
]
} Settings classes
public class SampleSettings
{
public string ApiUrl { get; set; }
public int Timeout { get; set; }
public string OutputPath { get; set; }
public ListSetting[] List { get; set; }
}
public class ListSetting
{
public string Name { get; set; }
public string Address { get; set; }
public int Interval { get; set; }
}Loading method
public static SampleSettings LoadSettings(IConfiguration configuration)
{
SampleSettings settings = configuration.Get<SampleSettings>();
return settings;
}Then, run the loading method shown above to bind the configuration.
Expected behavior
.NET 6 Expected behavior
List[0] = { Name = "A", Address = "AA", Interval = 10 }
List[1] = null // Conversion failed but null placeholder remains (array length 2)
Actual behavior
.NET 8 Actual behavior
List[0] = { Name = "A", Address = "AA", Interval = 10 }
List[1] is skipped entirely (array length becomes 1)
Note: I also tested this behavior on .NET 10, and it behaves the same.
Regression?
No response
Known Workarounds
No response
Configuration
NET versions tested:
- .NET 6
- .NET 8
Other information
Additional notes (speculated cause)
After checking the public ConfigurationBinder implementation in dotnet/runtime, it appears that:
In .NET 6, the binder pre-allocated the array and attempted to bind each element, resulting in failed elements becoming null.
In .NET 8, the binder first collects only successfully bound elements into a list, and then materializes the final array afterwards.
This difference may explain why failed elements are no longer preserved as null, but instead skipped.
This is only an observation based on the public source code.
Questions
-
For the default IConfiguration.Get() (no BinderOptions),
is it intended that elements which fail type conversion are now skipped rather than preserved as null? -
If this is an intended behavior change,from which
.NET version does this change originate?
If this is simply my misunderstanding or a documentation oversight, I apologize.
Thank you very much for your help.