.NET Core 使用配置绑定到带有数组的选项

.NET Core use Configuration to bind to Options with Array

使用 .NET Core Microsoft.Extensions.Configuration 是否可以将配置绑定到包含数组的对象?

ConfigurationBinder 有一个方法 BindArray,所以我认为它会起作用。

但是当我尝试时出现异常:

System.NotSupportedException: ArrayConverter cannot convert from System.String.

这是我精简后的代码:

public class Test
{
   private class ExampleOption
   { 
      public int[] Array {get;set;}
   }

   [Test]
   public void CanBindArray()
   {
       // ARRANGE
       var config =
            new ConfigurationBuilder()
            .AddInMemoryCollection(new List<KeyValuePair<string, string>>
            {
                new KeyValuePair<string, string>("Array", "[1,2,3]")
            })
            .Build();

        var exampleOption= new ExampleOption();

        // ACT
        config.Bind(complexOptions); // throws exception

       // ASSERT
       exampleOption.ShouldContain(1);
   }
}

您可以使用 ConfigureServices 方法中的代码配置 ExampleOption

 public void ConfigureServices(IServiceCollection services)
 {
      services.Configure<ExampleOption>(myOptions =>
      {
          myOptions.Array = new int[] { 1, 2, 3 };
      });
 }

或者如果你想使用json配置文件

appsettings.json:

{
  "ExampleOption": {
     "Array": [1,2,3]
  }
}

ConfigureServices:

public void ConfigureServices(IServiceCollection services)
{
    services.Configure<ExampleOption>(Configuration.GetSection("ExampleOption"));
}

错误在您的输入定义中。该示例将键 "Array" 设置为字符串值“[1,2,3]”(在基于 C# 的 InMemoryCollection 中)并假设它是按 JSON 样式解析的。那是错的。它只是没有被解析。

配置系统中数组值的编码约定是重复带有冒号和后面索引的键。以下示例的工作方式与您打算的一样:

var config = new ConfigurationBuilder()
        .AddInMemoryCollection(new List<KeyValuePair<string, string>>
        {
            new KeyValuePair<string, string>("Array:0", "1"),
            new KeyValuePair<string, string>("Array:1", "2"),
            new KeyValuePair<string, string>("Array:2", "3")
        })
        .Build();

如果使用 JSON 文件(此处通过额外调用 AddJsonFile),也会发生冒号键重复方案 ...

{
  "mySecondArray":  [1, 2, 3]
}

生成的组合配置将包含键,这些键遵循与上面内存中使用说明相同的模式:

Count = 8
[0]: {[mySecondArray, ]}
[1]: {[mySecondArray:2, 3]}
[2]: {[mySecondArray:1, 2]}
[3]: {[mySecondArray:0, 1]}
[4]: {[Array, ]}
[5]: {[Array:2, 3]}
[6]: {[Array:1, 2]}
[7]: {[Array:0, 1]}

配置系统与 JSON/INI/XML/... 等存储格式无关,本质上只是一个字符串-> 字符串字典,冒号在键 中构成层次结构 =].

Bind 能够通过约定 解释一些层次结构,因此也可以绑定数组、集合、对象和字典。有趣的是,对于数组,它不关心冒号后面的数字,而只关心子项的 iterate the children of the configuration section (here "Array") and take the values of the children. The sorting,将数字考虑在内,但还将字符串排序为第二个选项(OrdinalIgnoreCase)。

随着最近对 C# 语言的补充,使用更新的语法更加简洁:

var config = new ConfigurationBuilder()
    .AddInMemoryCollection(new Dictionary<string, string>
    {
        { "Array:0", "1" },
        { "Array:1", "2" },
        { "Array:2", "3" },
    })
    .Build();

或者您可以使用其他新语法

var config = new ConfigurationBuilder()
    .AddInMemoryCollection(new Dictionary<string, string>
    {
        ["Array:0"] = "1",
        ["Array:1"] = "2",
        ["Array:2"] = "3",
    })
    .Build();