Я привык хранить свою конфигурацию в Azure в AzureAppConfig и / или AzureKeyVault. Это дает мне центральное место для управления настройками разработки, подготовки / тестирования, производства и не требует от меня усложнять развертывание, манипулируя файлами настроек приложений или сохраняя их в каком-то репозитории развертывания. На самом деле он читается только из azure при запуске приложения (мне не нужно было обновлять sh их, пока мое приложение работало). Тем не менее, это сделало его немного интересным для местной истории разработчиков, потому что я лично хотел, чтобы порядок операций был appsettings.json
, appsettings.{environment}.json
, AzureAppConfig
, KeyVault
, а затем, наконец, secrets.json
. Таким образом, несмотря ни на что, я мог переопределить параметр из azure с помощью моего локального файла секретов (даже если параметр, который я переопределял, технически не был секретом).
В итоге я написал несколько нестандартных код в program.cs
для обработки загрузки источников конфигурации из Azure, затем завершите sh поиском JsonConfigurationSource
с Path
из "secrets.json"
, затем сделайте это последним элементом в моем IConfigurationBuilder.Sources
.
Для меня мои файлы используются следующим образом:
appsettings.json
- Общие настройки, которые необходимо установить для любой среды, и будут вероятно никогда не меняются в зависимости от окружающей среды. appsettings.{environment}.json
- В основном это просто пустые файлы JSON, которые в основном просто называют имена ресурсов AzureAppConfig
и AzuerKeyVault
для подключения к AzureAppConfig
- В основном для всего, что будет отличаться между производством, постановкой / Тестирование или местная разработка, И не является конфиденциальной информацией. Адреса конечных точек API, IP-адреса, различные URL-адреса, информация об ошибках и тому подобное. AzureKeyVault
- все, что важно. Имена пользователей, пароли, ключи для внешних API (авторизация, лицензионные ключи, строки подключения и т. Д. c).
Дело в том, что даже если вы поместите параметр в appsettings.json
, это не так. t означает, что вы не можете переопределить его с помощью appsettings.{enviroment}.json
или где-то еще. Я часто помещаю настройки в файл настроек root со значением NULL
, просто чтобы напомнить мне, что это настройка, используемая в приложении. Так что, возможно, лучший вопрос: хотите ли вы запускать свое приложение (без ошибок) только с базовыми appsettings.json
и secrets.json
? Или содержимое из appsettings.{enviroment}.json
всегда будет необходимо для успешного запуска?
Другая вещь, на которую следует обратить внимание на основе вашего вопроса, - это проверка вашей конфигурации. Более поздние версии Microsoft.Extensions.Options
предлагают различные способы проверки ваших параметров, чтобы вы могли попытаться поймать случаи, когда что-то оставалось пустым / неопределенным. Я обычно украшаю свои классы параметров POCO атрибутами аннотации данных, а затем использую ValidateDataAnnotations()
, чтобы убедиться, что они правильно настроены.
Например,
services.AddOptions<MailOptions>().Bind(configuration.GetSection("MailSettings")).ValidateDataAnnotations();
Стоит отметить, что эта проверка выполняется только тогда, когда вы попробуйте запросить что-то вроде MailOptions
, которое я использую в качестве примера выше, из DI (так, не при запуске). По этой причине я также создал свой собственный IStartupFilter
, чтобы упреждающе запросить один или несколько моих классов параметров из службы провайдер при запуске приложения, чтобы та же проверка запускалась еще до того, как приложение начнет принимать запросы.
public class EagerOptionsValidationStartupFilter : IStartupFilter
{
public readonly ICollection<Type> EagerValidateTypes = new List<Type>();
private readonly IServiceProvider serviceProvider;
public EagerOptionsValidationStartupFilter(IServiceProvider serviceProvider)
{
this.serviceProvider = serviceProvider;
}
public Action<IApplicationBuilder> Configure(Action<IApplicationBuilder> next)
{
foreach (var eagerType in EagerValidateTypes)
{
dynamic test = serviceProvider.GetService(typeof(IOptions<>).MakeGenericType(eagerType));
_ = test.Value;
}
return next;
}
}
startup.cs
public void ConfigureServices(IServiceCollection services)
{
services.AddTransient<IStartupFilter>(x =>
new EagerOptionsValidationStartupFilter(x)
{
EagerValidateTypes = {
typeof(MailOptions),
typeof(OtherOptions),
typeof(MoreImportantOptions)
}
});
}