Description
We have a configuration type which defines an array field, in net8.0 we were able to have an entry in our appsettings.json file which was an empty array and we could safely handle it. It was unhelpful that it arrived as null, but you can pass a null to the constructor and handle it safely.
In net 10 the behaviour has "improved" - see #36510 - specifically #36510 (comment)
Now this is arguably better in some ways, but it's extremely surprising, since a typed config object now cannot safely handle deserialization of this kind of value. Rather than null which passes the type check and can then be caught with a null guard in the constructor, the Binder now throws:
Unhandled exception. System.ArgumentException: Object of type 'System.String' cannot be converted to type 'System.String[]'.
at System.RuntimeType.CheckValue(Object& value, Binder binder, CultureInfo culture, BindingFlags invokeAttr)
at System.Reflection.MethodBaseInvoker.InvokeWithManyArgs(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
at System.Reflection.RuntimeConstructorInfo.Invoke(BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
at System.Reflection.ConstructorInfo.Invoke(Object[] parameters)
at Microsoft.Extensions.Configuration.ConfigurationBinder.CreateInstance(Type type, IConfiguration config, BinderOptions options, ParameterInfo[]& constructorParameters)
at Microsoft.Extensions.Configuration.ConfigurationBinder.BindInstance(Type type, BindingPoint bindingPoint, IConfiguration config, BinderOptions options, Boolean isParentCollection)
at Microsoft.Extensions.Configuration.ConfigurationBinder.Get(IConfiguration configuration, Type type, Action`1 configureOptions)
at Microsoft.Extensions.Configuration.ConfigurationBinder.Get[T](IConfiguration configuration, Action`1 configureOptions)
Reproduction Steps
Run in dotnetfiddle against .NET 8 to see an empty array, and against .NET 10 to see the exception.
using System;
using System.IO;
using Microsoft.Extensions.Configuration;
RunTest("Empty array []", @"{ ""ArrayField"": [] }");
static void RunTest(string label, string json)
{
Console.WriteLine($"\n=== {label} ===");
try
{
var config = new ConfigurationBuilder()
.AddJsonStream(new MemoryStream(System.Text.Encoding.UTF8.GetBytes(json)))
.Build();
var options = config.Get<MyOptions>();
var values = options.ArrayField;
Console.WriteLine($" Bound: {values.Length} item(s): [{string.Join(", ", values)}]");
}
catch (Exception ex)
{
Console.WriteLine($" FAIL — {ex.GetType().Name}: {ex.Message}");
}
}
public class MyOptions
{
public MyOptions(string[] arrayField = null)
{
ArrayField = arrayField ?? Array.Empty<string>();
}
public string[] ArrayField { get; }
}
Expected behavior
Object is deserialized into an empty array with no trouble - specifically null is passed and caught
Actual behavior
ArgumentException: Object of type 'System.String' cannot be converted to type 'System.String[]'.
Regression?
Regression from .net9.0 and .net8.0 (which I was using before)
Known Workarounds
Removing the key entirely works, as does passing [null] or [""] but neither of these are the same object as []
Configuration
Net 10 - 10.0.4
Windows 11 x64
Other information
Most of the fixes in the issue are improvements but this seems like a clear regression, as we can no longer safely type string[] entries and expect that they will be deserialized from valid json inputs. At the least it ought to have a documentation warning to make clear that this is not a valid operation, or it needs fixing properly.
Description
We have a configuration type which defines an array field, in net8.0 we were able to have an entry in our appsettings.json file which was an empty array and we could safely handle it. It was unhelpful that it arrived as null, but you can pass a null to the constructor and handle it safely.
In net 10 the behaviour has "improved" - see #36510 - specifically #36510 (comment)
Now this is arguably better in some ways, but it's extremely surprising, since a typed config object now cannot safely handle deserialization of this kind of value. Rather than null which passes the type check and can then be caught with a null guard in the constructor, the Binder now throws:
Reproduction Steps
Run in dotnetfiddle against .NET 8 to see an empty array, and against .NET 10 to see the exception.
Expected behavior
Object is deserialized into an empty array with no trouble - specifically null is passed and caught
Actual behavior
ArgumentException: Object of type 'System.String' cannot be converted to type 'System.String[]'.
Regression?
Regression from .net9.0 and .net8.0 (which I was using before)
Known Workarounds
Removing the key entirely works, as does passing [null] or [""] but neither of these are the same object as []
Configuration
Net 10 - 10.0.4
Windows 11 x64
Other information
Most of the fixes in the issue are improvements but this seems like a clear regression, as we can no longer safely type string[] entries and expect that they will be deserialized from valid json inputs. At the least it ought to have a documentation warning to make clear that this is not a valid operation, or it needs fixing properly.