ASP.NET Core的XML配置提供程序中的数组

时间:2019-02-27 22:29:19

标签: xml asp.net-core .net-core

我正在编写的ASP.NET Core(2.1)应用程序使用两个配置源:JSON和XML(使用框架的标准AddJsonFileAddXmlFile。XML设置具有更高的优先级(例如,应覆盖)匹配JSON文件中的设置)。

到目前为止,一切正常,直到我不得不在XML文件中创建数组为止。甚至有可能吗?

2 个答案:

答案 0 :(得分:2)

您可以通过添加多个标签来实现数组行为,这些标签具有重复的数组名称,包括带有元素“数组中的索引”的Name属性。例如,此json的xml等效文件

{
  "Values": [
    "value1",
    "value2",
    "value3"
  ],
  "Users": [
    {
      "Login": "log1",
      "Pass": "pass1"
    },
    {
      "Login": "log2",
      "Pass": "pass2"
    }
  ]
}

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <Values name="0">value1</Values>
  <Values name="1">value2</Values>
  <Values name="2">value3</Values>
  <Users name="0">
    <Login>log1</Login>
    <Pass>pas1</Pass>
  </Users>
  <Users name="1">
    <Login>log2</Login>
    <Pass>pas2</Pass>
  </Users>
</configuration>

如果您检查解析了 xml json 配置文件的各个Data中的ConfigurationProvider

configuration providers data

您将看到 xml 提供程序包含带有name后缀的额外条目,后缀包含name属性的值,但实际上两个集合都是相等的。

一些简单的测试证实了两种配置是否相同

public class Configuration
{
    public List<string> Values { get; set; }

    public List<User> Users { get; set; }

}

public class User
{
    public string Login { get; set; }

    public string Pass { get; set; }
}

//this code returns the same result for every configuration
var config = new Configuration();
_configuration.Bind(config);

string value = _configuration.GetValue<string>("Values:0");
string login = _configuration.GetValue<string>("Users:0:Login");

但这不是完整的答案

这种方法有一个严重的缺点。发布此答案之前,我测试了 xml 配置如何与第三方库一起使用。我尝试将Serilog json 配置转换为 xml 。这个json

//..
"WriteTo": [
  { "Name": "Console" }
]
//..

转换为

//..
<WriteTo name="0">
  <Name>Console</Name>
</WriteTo>
//...

这时出现异常

  

System.FormatException:'发现重复的键'WriteTo:0:Name'。第11行,位置11。'

还记得xml ConfigurationProvider中的额外条目吗?好吧,现在一切都因它们而崩溃。因此结论是,如果对象的对象包含Name键,则无法将 json 数组转换为 xml

一些好消息

有一个pull request允许使用名称重复且没有Name属性的标签。这应该可以解决该缺陷。还有codeXmlConfigurationProvider来自您已经可以在项目中使用的同一个人。

答案 1 :(得分:1)

引用Configuration in ASP.NET Core: Bind an array to a class

  

Bind支持使用配置键中的数组索引将数组绑定到对象。公开数字键段(:0:1,…:{n})的任何数组格式都可以将数组绑定到POCO类数组。

我将提供两个有关如何在XML配置文件中使用数组的示例

使用以下 config.xml

<configuration>
  <tvshow>
    <metadata>
      <series>Dr. Who</series>
      <title>The Sun Makers</title>
      <airdate>11/26/1977</airdate>
      <episodes>4</episodes>
    </metadata>
    <actors name="0">Tom Baker</actors>
    <actors name="1">Louise Jameson</actors>
    <actors name="2">John Leeson</actors>
    <legal>(c)1977 BBC https://www.bbc.co.uk/programmes/b006q2x0</legal>
  </tvshow>
</configuration>

匹配的POCO看起来像

public class TvShow {
    public Metadata Metadata { get; set; }
    public string[] Actors { get; set; } //<-- TAKE NOTE
    public string Legal { get; set; }
}

public class Metadata {
    public string Series { get; set; }
    public string Title { get; set; }
    public DateTime AirDate { get; set; }
    public int Episodes { get; set; }
}

给出<actors>元素的名称,结果路径将是

tvshow:actors:0
tvshow:actors:1
tvshow:actors:2

遵循文件中规定的惯例

因此在下面的单元测试中,它会按预期通过。

[TestClass]
public class Configuration_Should {
    [TestMethod]
    public void Bind_Xml_Arrays() {
        var config = new ConfigurationBuilder()
        .SetBasePath(Directory.GetCurrentDirectory())
        .AddXmlFile("config.xml", optional: true, reloadOnChange: true)
        .Build();

        var tvShow = config.GetSection("tvshow").Get<TvShow>();

        tvShow.Should().NotBeNull();

        tvShow.Actors.Should().HaveCount(3);
    }
}

在另一个示例中,假设将config.xml修改为以下内容

<?xml version="1.0" encoding="utf-8" ?> 
<configuration>
  <tvshow>
    <metadata>
      <series>Dr. Who</series>
      <title>The Sun Makers</title>
      <airdate>11/26/1977</airdate>
      <episodes>4</episodes>
    </metadata>
    <actors>
      <names name="0">Tom Baker</names>
      <names name="1">Louise Jameson</names>
      <names name="2">John Leeson</names>
    </actors>
    <legal>(c)1977 BBC https://www.bbc.co.uk/programmes/b006q2x0</legal>
  </tvshow>
</configuration>

将受影响的POCO重构为

public class TvShow {
    public Metadata Metadata { get; set; }
    public Actors Actors { get; set; }
    public string Legal { get; set; }
}

//...Metadata omitted for brevity

public class Actors {
    public string[] Names { get; set; }
}

再次,按照约定,数组元素的路径应类似于

tvshow:actors:names:0
tvshow:actors:names:1
tvshow:actors:names:2

在测试时还能表现出预期的效果

[TestClass]
public class Configuration_Should {
    [TestMethod]
    public void Bind_Xml_Arrays() {
        var config = new ConfigurationBuilder()
        .SetBasePath(Directory.GetCurrentDirectory())
        .AddXmlFile("config.xml", optional: true, reloadOnChange: true)
        .Build();

        var tvShow = config.GetSection("tvshow").Get<TvShow>();

        tvShow.Should().NotBeNull();

        tvShow.Actors.Names.Should().HaveCount(3);
    }
}

这以及文档应该为您提供足够的基础,以正确地构造XML配置以绑定到数组。