介绍
ASP.NET Core 提供了一个灵活可扩展,基于键值的配置系统. 但是配置系统独立于ASP.NET Core是Microsoft.Extensions 类库的部分. 它可以用于任何类型的应用程序 .ABP 框架与配置系统百分百兼容.
ASP.NET Core 中的配置是使用一个或多个配置提供程序 (configuration providers)执行的。 配置提供程序使用各种配置源从键值对读取配置数据:
- 设置文件,例如 appsettings.json
- 环境变量
- Azure Key Vault
- Azure 应用程序配置
- 命令行参数
- 已安装或已创建的自定义提供程序
- 目录文件
- 内存中的 .NET 对象
默认配置
public class Program
{
public static void Main(string[] args)
{
CreateHostBuilder(args).Build().Run();
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
});
}
CreateDefaultBuilder 按照以下顺序为应用提供默认配置:
- ChainedConfigurationProvider:添加现有 IConfiguration 作为源。 在默认配置示例中,添加主机配置,并将它设置为应用配置的第一个源。
- 使用 JSON 配置提供程序的 appsettings.json。
- 使用 JSON 配置提供程序通过 appsettings.Environment.json 提供 。 例如,appsettings.Production.json 和 appsettings.Development.json 。
- 应用在 Development 环境中运行时的应用机密。
- 使用环境变量配置提供程序, 通过环境变量提供。
- 使用命令行配置提供程序, 通过命令行参数提供。
后来添加的配置提供程序会替代之前的密钥设置。 例如,如果 appsettings.json 和环境中都设置了 MyKey,则使用环境值。 使用默认配置提供程序,命令行配置提供程序将替代所有其他的提供程序。
默认的 JsonConfigurationProvider 会按以下顺序加载配置:
- appsettings.json
- appsettings.Environment.json :例如,appsettings.Production.json 和 appsettings.Development.json 。 文件的环境版本是根据 IHostingEnvironment.EnvironmentName 加载的。
appsettings.Environment.json 值将替代 appsettings.json 中的键 。 例如,默认情况下:
- 在开发环境中,appsettings.Development.json 配置会覆盖在 appsettings.json 中找到的值。
- 在生产环境中,appsettings.Production.json 配置会覆盖在 appsettings.json 中找到的值。
使用选项模式绑定分层配置数据
读取相关配置值的首选方法是使用选项模式。 例如,若要读取以下配置值,请执行以下操作:
"Position": {
"Title": "Editor",
"Name": "Joe Smith"
}
创建以下 PositionOptions 类作为选项类:
public class PositionOptions
{
public const string Position = "Position";
public string Title { get; set; }
public string Name { get; set; }
}
选项类:
- 必须是包含公共无参数构造函数的非抽象类。
- 类型的所有公共读写属性都已绑定。
- 不会绑定字段。 在上面的代码中,Position 未绑定。 由于使用了 Position 属性,因此在将类绑定到配置提供程序时,不需要在应用中对字符串 "Position" 进行硬编码。
有三种常用的方式读取Position配置数据, 其中前两种默认读取在应用启动后对 JSON 配置文件所做的更改,第三种不会读取在应用启动后对 JSON 配置文件所做的更改.
第一种方式:
- 调用 ConfigurationBinder.Bind 将 PositionOptions 类绑定到 Position 部分。
- 显示 Position 配置数据。
public class TestModel : PageModel
{
private readonly IConfiguration Configuration;
public TestModel(IConfiguration configuration)
{
Configuration = configuration;
}
public ContentResult OnGet()
{
var positionOptions = new PositionOptions();
Configuration.GetSection(PositionOptions.Position).Bind(positionOptions);
return Content(#34;Title: {positionOptions.Title} \n" +
#34;Name: {positionOptions.Name}");
}
}
第二种方式:
- 调用 ConfigurationBinder.Get<T> 绑定并返回指定的类型。
- 显示 Position 配置数据。
public class TestModel : PageModel
{
private readonly IConfiguration Configuration;
public PositionOptions positionOptions { get; private set; }
public TestModel(IConfiguration configuration)
{
Configuration = configuration;
}
public ContentResult OnGet()
{
positionOptions = Configuration.GetSection(PositionOptions.Position).Get<PositionOptions>();
return Content(#34;Title: {positionOptions.Title} \n" +
#34;Name: {positionOptions.Name}");
}
}
第三种方式:
- 绑定 Position 部分并将它添加到依赖项注入服务容器。
- 显示 Position 配置数据。
- 若要读取在应用启动后的更改,请使用 IOptionsSnapshot
public void ConfigureServices(IServiceCollection services)
{
services.Configure<PositionOptions>(Configuration.GetSection(PositionOptions.Position));
services.AddRazorPages();
}
public class TestModel : PageModel
{
private readonly PositionOptions _options;
public TestModel(IOptions<PositionOptions> options)
{
_options = options.Value;
}
public ContentResult OnGet()
{
return Content(#34;Title: {_options.Title} \n" +
#34;Name: {_options.Name}");
}
}
使用默认配置时,会通过 reloadOnChange: true 启用 appsettings.json 和 appsettings.Environment.json 文件 。 应用启动后,对 appsettings.json 和 appsettings.Environment.json 文件所作的更改将由 JSON 配置提供程序读取 。
合并服务集合
使用下面的 ConfigureServices 方法可注册服务并配置选项:
public void ConfigureServices(IServiceCollection services)
{
services.Configure<PositionOptions>(Configuration.GetSection(PositionOptions.Position));
services.Configure<ColorOptions>(Configuration.GetSection(ColorOptions.Color));
services.AddScoped<IMyDependency, MyDependency>();
services.AddScoped<IMyDependency2, MyDependency2>();
services.AddRazorPages();
}
可以将相关的注册组移动到扩展方法以提供注册服务。 例如,配置服务会被添加到以下类中:
using ConfigSample.Options;
using Microsoft.Extensions.Configuration;
namespace Microsoft.Extensions.DependencyInjection
{
public static class MyConfigServiceCollectionExtensions
{
public static IServiceCollection AddConfig(this IServiceCollection services, IConfiguration config)
{
services.Configure<PositionOptions>(config.GetSection(PositionOptions.Position));
services.Configure<ColorOptions>(config.GetSection(ColorOptions.Color));
return services;
}
}
}
再通过ConfigureServices 方法使用新扩展方法来注册服务:
public void ConfigureServices(IServiceCollection services)
{
services.AddConfig(Configuration)
.AddMyDependencyGroup();
services.AddRazorPages();
}
注意: 每个 services.Add{GROUP_NAME} 扩展方法添加并可能配置服务。 例如,AddControllersWithViews 会添加带视图的 MVC 控制器所需的服务,AddRazorPages 会添加 Razor Pages 所需的服务。 我们建议应用遵循此命名约定。 将扩展方法置于 Microsoft.Extensions.DependencyInjection 命名空间中以封装服务注册的组。
安全性和用户机密
请勿在配置提供程序代码或纯文本配置文件中存储密码或其他敏感数据。 机密管理器工具可用于存储开发环境中的机密。
- 不要在开发或测试环境中使用生产机密。
- 请在项目外部指定机密,避免将其意外提交到源代码存储库。
默认情况下,将在 JSON 配置源后注册用户机密配置源。 因此,用户机密密钥优先于 appsettings.json 和 appsettings.Environment.json 中的密钥。
TODO: 关于机密管理器工具的相关描述,我们后面再详细讲解.