为什么这个自定义配置提供程序不正确地绑定数组元素?

Why does this custom configuration provider incorrectly bind array elements?

我正准备在 .NET Core 2.2 中编写自定义配置提供程序。我的自定义配置提供程序扩展了 ConfigurationProvider class。它将 Data 属性 设置为表示包含字符串数组的对象的字典。当我尝试将构建的配置绑定到 class 时,数组值最终为空。当我将同一个字典与 InMemoryCollection 提供程序一起使用时,数组值被正确绑定。

public class TestConfigProvider : ConfigurationProvider
    {
        public override void Load()
        {
            Data = new Dictionary<string, string>
                {
                    {"array:entries:0", "value0"},
                    {"array:entries:1", "value1"}
                };
        }
    }
    public class TestConfigSource : IConfigurationSource
    {
        public IConfigurationProvider Build(IConfigurationBuilder builder)
        {
            return new TestConfigProvider();
        }
    }
    public static class TestConfigExtensions
    {
        public static IConfigurationBuilder AddCustomConfig(this IConfigurationBuilder builder)
        {
            return builder.Add(new TestConfigSource());
        }
    }

    public class ArrayExample
    {
        public string[] Entries { get; set; }
    }

    public class Program
    {
        public static Dictionary<string, string> _data = new Dictionary<string, string>
                {
                    {"array:entries:0", "value0"},
                    {"array:entries:1", "value1"}
                };

        static void Main(string[] args)
        {
            IConfiguration config1 = new ConfigurationBuilder()
                .AddCustomConfig()
                .Build();

            IConfiguration config2 = new ConfigurationBuilder()
                .AddInMemoryCollection(_data)
                .Build();

            var test1 = config1.GetSection("array").Get<ArrayExample>();
            var test2 = config2.GetSection("array").Get<ArrayExample>();

            Console.WriteLine(JsonConvert.SerializeObject(test1)); // {"Entries":[null,null,null,null,null]}
            Console.WriteLine(JsonConvert.SerializeObject(test2)); // {"Entries":["value0","value1","value2","value4","value5"]}
        }
    }

我希望两个配置都能绑定数组值。

我可以使用配置对象上的索引运算符提取各个值。

查看 MemoryConfigurationProvider 的来源并查看它们如何填充提供的初始数据后

public MemoryConfigurationProvider(MemoryConfigurationSource source)
{
    if (source == null)
    {
        throw new ArgumentNullException(nameof(source));
    }

    _source = source;

    if (_source.InitialData != null)
    {
        foreach (var pair in _source.InitialData)
        {
            Data.Add(pair.Key, pair.Value);
        }
    }
}

通过填充 Data 而不是替换整个对象。

我在 TestConfigProvider

中做了同样的事情
public class TestConfigProvider : ConfigurationProvider {
    public override void Load() {
        var initialData = new Dictionary<string, string>
        {
            {"array:entries:0", "value0"},
            {"array:entries:1", "value1"}
        };

        foreach (var pair in initialData) {
            Data.Add(pair.Key, pair.Value);
        }
    }
}

并获得了与使用内存中提供程序类似的结果,通过在测试时填充数组值来实现所需的绑定行为

[TestClass]
public class CustomConfigurationTests {
    public static Dictionary<string, string> _data = new Dictionary<string, string>
            {
                {"array:entries:0", "value0"},
                {"array:entries:1", "value1"}
            };

    [TestMethod]
    public void Should_Bind_Array() {
        //Arrange
        IConfiguration config1 = new ConfigurationBuilder()
            .AddCustomConfig()
            .Build();

        IConfiguration config2 = new ConfigurationBuilder()
            .AddInMemoryCollection(_data)
            .Build();

        //Act
        var test1 = config1.GetSection("array").Get<ArrayExample>();
        var test2 = config2.GetSection("array").Get<ArrayExample>();

        //Assert
        test1.Entries.Should().BeEquivalentTo(test2.Entries);
    }
}