Массивы в провайдере конфигурации XML в ASP.NET Core - PullRequest
0 голосов
/ 28 февраля 2019

Приложение ASP.NET Core (2.1), которое я пишу, использует два источника конфигурации: JSON и XML (с использованием стандартных фреймворков AddJsonFile и AddXmlFile. Настройки XML имеют более высокий приоритет (например, должны перезаписывать настройки сопоставления изJSON-файл).

Пока все работает нормально, до того момента, когда мне пришлось создавать массив в XML-файле. Возможно ли это вообще?

Ответы [ 2 ]

0 голосов
/ 05 марта 2019

Вы можете добиться поведения массива, добавив несколько тегов с дублированным именем массива, включая атрибут Name с элементом «index in array».Например, xml-эквивалент этого json

{
  "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>

Если вы изучите Data соответствующих ConfigurationProvider s, которые проанализировали xml и json файлы конфигурации

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 работает со сторонними библиотеками.И я попытался преобразовать json config в xml для Serilog.Этот json

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

преобразуется в

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

И в этот момент возникает исключение

System.FormatException: 'Дублирующий ключ' WriteTo: 0: Имя 'было найдено.Строка 11, позиция 11. '

Помните, что дополнительные записи из xml ConfigurationProvider?Ну, теперь все из-за них падает.Таким образом, вывод заключается в том, что вы не можете преобразовать массив json в xml , если его объекты содержат ключ Name.

Некоторые хорошие новости

Существует запрос на получение , который позволяет использовать теги с дублированными именами без атрибута Name.Это должно исправить этот недостаток.Также есть код для XmlConfigurationProvider от того же парня, которого вы уже можете использовать в своем проекте.

0 голосов
/ 05 марта 2019

Ссылка Конфигурация в ASP.NET Core: привязка массива к классу

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связать с массивами.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...