Я использую ASP.NET Core 2.1. У меня есть настройки в appsettings.json, и я привязываю их к классам, используя шаблон параметров. Я хочу переопределить некоторые из них в appsettings.Production.json.
Переопределение поддерживается в соответствии с документацией и в целом работает для меня. Но для массивов это не работает.
appsettings.json:
"MySectionOuter": {
"MySectionInner": [
{
"foo": "1",
"bar": "2",
"baz": "3"
},
{
"foo": "a",
"bar": "b",
"baz": "c"
}
]
}
Мои переопределения в appsettings.Production.json
"MySectionOuter": {
"MySectionInner": [
{
"bar": "4",
},
{
"baz": "d"
}
]
}
Однако это не работает - он скорее добавляет, чем заменяет.
Я прочтите это массив является синтаксическим сахаром для хранилища значений ключей. Итак, я также попробовал это:
"MySectionOuter": {
"MySection:1": {
"bar": "4",
},
"MySection:2": {
"baz": "b",
}
}
Но это тоже не работает.
Какой правильный синтаксис?
ОБНОВИТЬ
Комментарии показывают, что я не объяснил должным образом. Я хочу вот что:
В процессе разработки:
element1: foo=1
element1: bar=2
element1: baz=3
element2: foo=a
element2: bar=b
element2: baz=c
В процессе производства:
element1: foo=1
element1: bar=2
element1: baz=4 // this was changed
element2: foo=a
element2: bar=b
element2: baz=d // this was changed
Кроме того, в настройках конфигурации есть нет гарантии заказа. Провайдер (например, провайдер базы данных) может возвращать их в любом порядке, и конфигурация будет (должна) по-прежнему работать. Иерархия JSON используется только для генерации ключевого пути, не более того.
Спасибо, что указали на это - это был всего лишь пример, и я его изменил.
@Ionix, ответ все тот же. Все - это путь к значениям. Максим объясняет, как это работает. Ваш второй пример переопределяет только MySectionOuter::MySection:1::bar и MySectionOuter::MySection:2::baz, но не другие значения. Использование 1 в названии этого не изменило.
@PanagiotisKanavos Я не уверен, что понимаю вас - я хочу переопределить только те значения, которые я указал в производственном файле, а все остальное осталось прежним.
Конфигурация @Ionix .NET Core не зависит от JSON. Он может использовать любое количество поставщиков, включая файлы ini, XML, YAML и базы данных, если поставщики возвращают их в виде отдельных значений с ключевым путем. Этот путь всегда Section1::Subsection1::Whatever::...::SettingName. Независимо от структуры файла, все настройки сводятся к этой форме. Если вы хотите загрузить разные списки данных для каждой среды, вам, вероятно, следует использовать другой механизм.
@Ionix, в этом случае вам, вероятно, следует опубликовать код, воспроизводящий проблему. Вы отменяете значения MySectionOuter::MySection:1::bar и MySectionOuter::MySection:2::baz. Все остальные должны оставаться такими же - MySectionOuter::MySection:1::foo должен оставаться "1".
@PanagiotisKanavos Хорошо, теперь мы на одной странице. Но ответ Maxims объясняет, почему это не интуитивно, я столкнулся именно с этими проблемами. Придется использовать другой подход. Спасибо.
@PanagiotisKanavos: Я не думаю, что вы имели в виду это таким образом, но ваш комментарий может означать, что порядок конфигурации провайдеры не является детерминированным. На самом деле это так. Провайдеры загружаются в том порядке, в котором они определены. Однако порядок отдельных настроек, загружаемых поставщиком, не всегда может быть одинаковым.
@ChrisPratt вопрос о массивах настроек. Разные поставщики могут возвращать результаты в разном порядке, таким образом создавая другой путь. Например, поставщик базы данных не сможет решить, как упорядочить результаты, подобные тем, которые опубликованы в вопросе.
@PanagiotisKanavos Переопределяя настройки в производственном файле в том же порядке, я получаю желаемый эффект. Вы хотите сказать, что я не могу полагаться на это в будущем?
@Ionix вы можете зависеть от порядка в отношении файловых провайдеров. Если вы добавляете другого провайдера, например базу данных, вам необходимо убедиться, что существует что-то, который можно использовать для восстановления полного ключа. База данных может возвращать результаты в любом порядке. Если же запись в базе данных содержит поле Index, вы можете использовать его для создания того же пути настройки, сгенерированного файлом.





Согласно этому сообщению в блоге: https://www.paraesthesia.com/archive/2018/06/20/microsoft-extensions-configuration-deep-dive/
Невозможно удалить элементы конфигурации с помощью поставщика.
You can add configuration at override time, but you can’t remove things. The best you can do is override a value with an empty string.
Вместо этого вам следует вводить в appsettings.config минимально необходимую информацию и заполнять соответствующие настройки в более специализированном файле настроек. Например. appsettings.Development.config или ваш appsettings.Production.config. Или, как предлагается в сообщении в блоге:
Since you can’t remove things, specify as little configuration as possible and behave correctly using defaults in your code when configuration isn’t there.
Вопрос в замена, а не в удалении. Замена работает нормально, пока ключ такой же. В массивах индекс является частью ключа
@PanagiotisKanavos Вопрос спрашивает, что после применения appsettings.production.config в массиве должно быть меньше элементов. Поскольку каждый элемент массива имеет свой собственный ключ, они должны быть удаленный из конфигурации. Так что я думаю, что ответ все еще актуален.
Массив содержит такое же количество элементов. Но это те элементы, у которых меньше свойств. OP предполагал, что массив или сами элементы будут заменены. Наверное, не понимал, что имеют значение только сами настройки, а все остальное - лишь путь к значениям
Ты прав! Я оставлю ответ, потому что предложение из сообщения в блоге все еще имеет смысл - и после его применения проблема исчезнет.
Это исправило это для меня очень хорошо. Я просто оставляю эти настройки массива пустыми в корневом файле. Идеально!
На самом деле массивов там при построении конфигурации нет. Это просто словарь пар ключ-значение. Таким образом, вы получаете строковые ключи, что-то вроде
"mysectionouter:mysectioninner:0:foo" = 1.
Итак, когда в вашей конфигурации вы определяете массив, происходит следующее:
appsettings.json:
"mysectionouter:mysectioninner:0:foo" = 1
"mysectionouter:mysectioninner:0:bar" = 2
appsettings.production.json:
"mysectionouter:mysectioninner:0:bar" = new1
результат:
foo = 1
bar = new1
Таким образом, он основан на индексе, и следующая конфигурация просто переопределяет ключ. Во втором примере вы ничего не добьетесь, кроме изменения индекса. Представление будет:
"mysectionouter:mysectioninner:1:bar" = new1
Итак, вернемся к вашему вопросу: массивы сложны в настройках приложений и, хотя и поддерживаются, обычно сложны и не интуитивно понятны в использовании.
По индексу вы можете получить странное слияние двух не связанных объектов, если вы определите разные наборы настроек в своих файлах, такие как настройки A и B в первой конфигурации и C во второй, вы получите C и B в результате, и вы, вероятно, совсем не хотите иметь B. Что еще хуже, вы можете получить смесь A и C, если определите только некоторые поля каждого объекта.
Я бы рекомендовал использовать другие файлы для хранения такой информации. Вы также можете заблокировать отладчик там, где загружена конфигурация, и сами посмотреть, как создаются эти ключи, чтобы получить больше информации.
Зачем вообще использовать множество, особенно когда содержимое не связано? Помимо того, что трудно переопределить значения, вы не можете прочитать содержимое в List <T> или любом другом строго типизированном контейнере. Вам нужно будет прочитать отдельные значения.