Как стать автором
Обновить

Комментарии 19

Во время разработки часто возникает потребность для вынесения параметров в конфигурационные файлы. [...] Но главная сложность, на мой взгляд, состоит в том, что у нас имеются аж 3 разные интерфейса для работы с конфигурациями.

IOptions и его друзья

Стоп. Зачем вы путаете IOptions, который нужен для работы с настройками, и работу с конфигурацией, для которой есть IConfiguration? Они даже в пакетах разных лежат.


Вцелом, из описания все сразу становится ясно: загружает данные из конфигурационного файла при старте приложения, не подтягивает никаких изменений.

Нет, неправильно. Никакого конфигурационного файла. Просто результат применения Configure.


И потом, вероятно далеко не сразу, человек выяснит, что то все работает совсем не так, как он задумывал.

… а как он задумывал и почему?


Я привык, что довольно большая часть конфигураций в моих проектах может довольно часто меняться. И лично мне хотелось бы, что бы интерфейс, который буквально кричит о том, что его надо использовать для конфигурации вел себя более очевидно. (Хотя конечно я могу быть не прав, и это только мои придирки. А большая часть людей использует файлы конфигураций по-другому)

Именно так. "Многие люди" привыкли к тому, что изменения файла конфигурации приводит к перезагрузке приложения (скажем, asp.net себя так вел и ведет). Поэтому для них неизменность настроек — более-менее ожидаема.


MSDN нам говорит, что не может быть заинжекчен в Singletone — на самом деле может

… если валидацию скоупов не делать. А если делать — то не может.


.UseDefaultServiceProvider(options => options.ValidateScopes = false);

Вот поэтому и "можно".


Обновляет информацию о конфигурации при каждом запросе. И что немаловажно, не изменяет ее во время запроса.

Какого такого запроса?


И, что характерно, нет, он не "обновляет информацию о конфигурации". Он просто заново выполняет Configure.


А имеем то, что IOptionsMonitor — не такой шустрый, как нам говорит документация.

А документация ничего не говорит о скорости. Про реальное время — это ваши собственные домыслы. А в реальности там стоит change token, который зависит от файловой системы, и который никогда особо быстрым не был.


Но, он [IOptionsSnapshot] работает быстрее, чем IOptionsMonitor.

Не "быстрее". Он возвращает вам актуальные значения на момент первого создания в scope.


Честное слово, лучше бы вы рассказали, как, собственно, IOptions-что-нибудь настраиваются. И как именно обрабатываются изменения. Тогда было бы понятно, что конкретно происходит.

Чем настройки отличаются от конфигурации?

В данном случае, конфигурация (IConfiguration) — это нечто внешнее по отношению к приложению, а настройки (IOptions) — внутреннее.

Спасибо за классификацию) давно задаюсь вопросом как различить эти «синонимы».
но что насчет Settings?

К счастью, settings в этой системе терминов нет.

Что-то, что настраивает сам пользователь через интерфейс приложения.
а в чем разница с опциями тогда?

Опции (которые IOptions) могут быть просто захардкожены.

может кто подскажет если уж это тема затронута.
есть возможность переписать значения некоторых полей в своей конфигурацию в appsettings.json через интерфейс IOptions…?

допустим в ConfigureServices сделал запись:

services.Configure<ModelSettingsForMachine>(_configuration.GetSection("SettingsForMachine"));

и чтобы переписать какое либо значение пришлось сделать такой обходной метод с обращением самому файлу:

public static void AddOrUpdateAppSetting<T>(string key, T value)
        {
            try
            {
                var filePath = Path.Combine(AppContext.BaseDirectory, "appsettings.json");

                Console.WriteLine("appSettings.json filePath " + filePath);
                string json = File.ReadAllText(filePath);
                dynamic jsonObj = Newtonsoft.Json.JsonConvert.DeserializeObject(json);

                string path = key.Split(":").Aggregate((i, j) => i + "." + j);
                dynamic acme = jsonObj.SelectToken(path);
                acme.Value = value;
                
                string output = Newtonsoft.Json.JsonConvert.SerializeObject(jsonObj, Newtonsoft.Json.Formatting.Indented);
                File.WriteAllText(filePath, output);

            }
            catch (ConfigurationErrorsException)
            {
                Console.WriteLine("Error writing app settings");
            }
        }


есть более правильные варианты?
есть возможность переписать значения некоторых полей в своей конфигурацию в appsettings.json через интерфейс IOptions…?

Нет. Во-первых, IOptions вообще не про конфигурационные файлы. Во-вторых, у IConfigurationProvider есть метод Load, но нет метода Save, как и у FileConfigurationProvider. Вся эта инфраструктура — только для чтения:


Configuration providers read configuration data from key-value pairs using a variety of configuration sources
Да и вообще — хранить разные конфигурационный константы в коде является признаком дурного тона.

Сильное заявление ©
Принцип YAGNI говорит нам о том, что задачу надо решать наиболее простым способом, удовлетворяющим критерии.
Если константы достаточно, используйте её.
Вынося её в конфиг, вы


  1. Пишите лишний код, ведь теперь вам теперь нужна проверка валидности значения, юнит тесты для разных значений.
  2. Усложняете разработку, т.к. вам теперь надо держать в уме и проверять, что код работает с разными значениями.
  3. Тратите время коллег. Им нужно будет понять: зачем это настраивается, т.к. "константа является признаком дурного тона" не самое очевидное правило.
  4. Делаете ваш софт менее предсказуемым, ведь значения в конфиге могут меняться. (забыли обновить конфиг на продакшене, "но на моей машине работает!" ©)
  5. Делаете некоторые типы рефакторинга более трудными.
  6. "Замусориваете" конфиг, усложняя жизнь тем, кто будет разверывать и сопровождать ваш софт

Да просто само понятие "конфигурационная константа" — оксюморон. Либо константа, либо конфигурация.

А это вообще реальный кейс, изменение appsettings.json во время работы приложения? Любой мало-мальски серьёзный проект деплоится не руками, cicd и так далее, если это прод — нельзя просто так и подправить конфиг. Ну цикл же! Тикет, ветка, MR, ревью, мерж, qa и вот это всё. Совершенно точно приложение передеплоится, нет же реальной необходимости читать конфиг без перезапуска.

ну допустим у меня проект на asp.net core хостится на малинке, к ней подключены по последовательному порту несколько девайсов, в добавок используются штатные пины для управления другими девайсами. настроку портов и пинов увел в appsettings.json, ну не создавать же отдельный файл когда есть тот который подходит по философии использования.

и если так случилось что наименование порта или использование пина (или второстепенных настроек) изменилось то надо менять настройку в файле руками ( за исключением если нет админской панели, что делает по сути тоже самое)

И вам обязательно нужно, чтобы приложение не перестартовалось в это время?

в моем случаи это добавляет удобства что с приложеним можно работать без необходимости его перезапускать. то что я описал это делается один раз перед тем как комплекс уходит в эксплуатацию, за исключением тех моментов когда надо разбираться на месте с вопросами «а что случилось и почему нет связи с инструментами».

и есть нюансы когда даешь инструкцию заказчику по настройке, а там пункт: «после настройки перезапустите приложение» — человек может это воспринять как то, что приложение криво работает и совет из ряда «перегрузите роутер»
Если конфиг хранится во внешней системе. Один из вариантов, что именно подменяется settings.json
В вашем случае — вы совершенно правы
Если вам нужно передавать конфигурацию, которые никогда в процессе жизни вашего приложения не будут меняться используете IOptions.

… только сейчас обратил внимание. А то, что IOptions не умеет именованные экземпляры — типа, не важно?

"Пока не особо понятно откуда берется это пустое значение. И самое интересное, что подобное поведение проявляется не всегда."

Скорее всего это баг в .net core/ 5

https://github.com/dotnet/runtime/issues/37860

Меня такое поведение очень сильно озадачило и хорошо что до продакшена не дошло а отловили на тестовом окружении.

Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации

Истории