更新:我想补充一下,我不再使用Azure App Configuration,只使用KeyVault。我很失望的是,定价允许每个订阅1个免费的AppConfig,然后似乎对第一个之外的每个AppConfig每天收取超过1.20$ CDN的费用。对我来说,这意味着每月额外36美元的费用,而这个东西每天只会被使用一次(假设我让Web应用程序在晚上关闭)。价格点根本没有任何意义。我宁愿使用多个KeyVault,因为它们的成本纯粹基于使用量,并且每千次交易只需支付微不足道的费用。我不明白AppConfig的预期用例是什么,以证明其价格点的合理性。
我已经养成了将配置存储在AzureAppConfig和/或AzureKeyVault下的习惯。这为我提供了一个集中管理开发、暂存/测试、生产设置的位置,不需要我通过操作appsettings文件来复杂化部署,也不需要将它们存储在某种部署仓库中。它只在应用程序启动时从Azure中读取(我不需要在我的应用程序运行时刷新它们)。话虽如此,对于本地开发故事来说,这使得它有点有趣,因为我个人希望操作顺序是
appsettings.json
、
appsettings.{environment}.json
、
AzureAppConfig
、
KeyVault
,最后是
secrets.json
。这样,无论如何,我都可以用我的本地secrets文件覆盖来自Azure的设置(即使我要覆盖的设置并不是技术上的机密)。
基本上,我最终在
program.cs
中编写了一些自定义代码来处理从Azure加载配置源,然后查找具有
Path
为
"secrets.json"
的
JsonConfigurationSource
,最后将其提升为
IConfigurationBuilder.Sources
中的最后一项。
对我来说,我的文件用法如下
appsettings.json
- 通用设置,需要为任何环境设置,并且根据环境可能永远不会更改。
appsettings.{environment}.json
- 主要是空的JSON文件,基本上只命名了AzureAppConfig
和AzuerKeyVault
资源名称以连接到
AzureAppConfig
- 基本上适用于在生产、暂存/测试或本地开发之间有所不同的任何内容,并且不是敏感信息。API端点地址、IP地址、各种URL、错误日志信息等。
AzureKeyVault
- 任何敏感信息。用户名、密码、外部API的密钥(身份验证、许可证密钥、连接字符串等)。
事实是,即使您在
appsettings.json
中设置了一个设置,也并不意味着您不能使用
appsettings.{enviroment}.json
或其他地方覆盖它。我经常在根设置文件中放置一个值为
NULL
的设置,只是为了提醒自己它是应用程序中使用的设置。因此,更好的问题可能是,您想能够仅使用基本的
appsettings.json
和
secrets.json
运行应用程序(例如无错误)吗?还是始终需要来自
appsettings.{enviroment}.json
的内容才能成功启动?
基于您的问题,另一件要看的事情是配置验证。较新版本的
Microsoft.Extensions.Options
提供了各种方式来验证您的选项,以便您可以尝试并捕获留空/未定义某些内容的情况。我通常使用数据注释属性装饰我的POCO选项类,然后使用
ValidateDataAnnotations()
来验证它们是否正确设置。
例如:
services.AddOptions<MailOptions>().Bind(configuration.GetSection("MailSettings")).ValidateDataAnnotations()
值得注意的是,此验证仅在尝试从 DI 请求像上面我使用的
MailOptions
这样的东西时运行(因此不是在启动时)。
出于这个原因,我还创建了自己的
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)
}
});
}
appsettings.json
作为开发活动基础的最佳方式的争论。请更多地关注你的问题,而不是询问处理appsettings.json
时应该选择哪种策略。因此,在SO上一个好的问题应该避免将意见作为答案。 - Eriawan Kusumawardhono