此为系列文章,对MSDN ASP.NET Core 的官方文档进行系统学习与翻译。其中或许会添加本人对 ASP.NET Core 的浅显理解。
ASP.NET Core中的应用程序配置是基于配置提供器建立的键值对的。配置提供器从各种配置源中读取配置数据到键值对中。配置源包含如下:
- Azure密钥库
- Azure应用程序配置
- 命令行参数
- 自定义提供器(装载的或者新建的)
- 字典文件
- 环境变量
- 内存中.NET对象
- 设置文件
通用配置提供器场景的配置Pakages隐式的包含在框架中。
接下来以及在示例中的代码使用了Microsoft.Extensions.Configuration 命名空间。
using Microsoft.Extensions.Configuration;
选项模式是本章描述的配置概念的一个扩展。选项模式使用类来代表一组相关的配置。更多信息,请参考Options pattern in ASP.NET Core。
View or download sample code (how to download)
宿主与App 配置
在app被配置以及启动之前,一个宿主会被配置和加载。宿主负责app的启动以及生命周期管理。app以及宿主都会使用本章描述的配置提供器进行配置。宿主配置键值对会包含在app配置中。关于在宿主被建立时,配置提供器如何使用以及配置源如何影响宿主配置的更多信息,请参考ASP.NET Core fundamentals。
其他配置
本章主题仅仅适用于app.configration。运行以及寄宿ASP.NET Core apps的其他方面将使用其他配置文件进行配置,其不包含在本章主题之中。
- launch.json/launchSettings.json 是用于开发环境的工具配置文件,其在如下主题中会有所描述:
- 在Use multiple environments in ASP.NET Core中。
- 在被用来配置开发环境的ASP.NET Core文档集合中。
- web.config是一个服务器配置文件,其在如下主题中会有所描述:
关于从早期版本的ASP.NET 中迁移配置文件的更多信息,请参考:Migrate from ASP.NET to ASP.NET Core。
默认配置
基于ASP.NET Core dotnet new 模板创建的web app在建立一个宿主的时候会调用CreateDefaultBuilder。CreateDefaultBuilder
按照如下顺序为app 提供默认的配置:
以下内容适用于使用了Generic Host 的app。当使用Web Host时,关于默认配置的更多信息,请参考ASP.NET Core 2.2 version of this topic。
- 宿主配置从如下位置被提供:
- 带有
DOTNET_
前缀的环境变量(比如DOTNET_ENVIRONMENT
),其使用Environment Variables Configuration Provider。当配置键值对被加载的时候,前缀DOTNET_
会被移除。 - 命令行参数,其使用Command-line Configuration Provider。
- 带有
- Web宿主默认配置会被键立(
ConfigureWebHostDefaults
):- Kestrel 被用作web 服务器并使用app的配置提供器进行配置。
- 添加宿主过滤中间件。
- 如果
ASPNETCORE_FORWARDEDHEADERS_ENABLED
环境变量被设置为true,那么会添加Forwarded Headers中间件。 - 启用IIS整合。
- 从如下位置提供app配置:
- appsettings.json,其使用 File Configuration Provider。
- appsettings.{Environment}.json,其使用File Configuration Provider。
- Secret Manager,当app运行在开发环境中时,其使用入口点程序集。
- 环境变量,其使用Environment Variables Configuration Provider。
- 命令行参数,其使用the Command-line Configuration Provider。
安全
对于安全敏感的配置数据采取以下实践:
- 绝对不要将密码以及其他敏感数据存储在配置提供器代码中,或者在纯文本配置文件中。
- 在开发环境以及测试环境中,不要使用生产环境的密钥。
- 将密钥在项目工程之外指定,这样它们便不会被自动提交给源码库。
更多信息,请参考如下主题:
- 在ASP.NET Core使用多个环境。
- ASP.NET Core开发环境中密钥的安全存储 —— 包括使用环境变量来存储敏感数据的建议。密钥管理器(Secret Manager)使用文件配置提供器来将用户密钥存储在本地系统的Json文件中。文件配置提供器在本章后续会进行描述。
Azure密钥库 为ASP.NET Core app安全的存储app密钥。更多信息,请参考Azure Key Vault Configuration Provider in ASP.NET Core。
层次化的配置数据
配置API可用维护层次化的配置数据,器通过使用配置键中的分号(;)来将层次化的数据扁平化。
在如下的Json文件中,四个键值存在于两部分组成的结构化的等级制度中。
{ "section0": { "key0": "value", "key1": "value" }, "section1": { "key0": "value", "key1": "value" } }
当文件被读入到配置中,会创建唯一的键值来维护原始的来自于配置源的层次化数据结构。我们使用一个冒号来将部分以及键值进行扁平化处理,以维护原始的数据结构:
- section0:key0
- section0:key1
- section1:key0
- section1:key1
GetSection 以及 GetChildren 方法可用来分离开各个部分以及它们的子节点。这些方法在GetSection, GetChildren, and Exists 中会有描述。
惯例
源以及提供器
在app启动时,配置源被按照器配置提供器被指定的顺序被读取。
实现了更新检测的提供器当底层的设置被更新时可以重加载配置。举个例子,文件配置提供器(本章后续会有描述)以及Azure Key Vault Configuration Provider 都实现了更改探测。
IConfiguration 在app 的DI容器中是可用的。IConfiguration 可以被注入到一个Razor页面的 PageModel 中 或者是 MVC的Controller 中,从而为这个类获取配置数据。
在如下的示例中,_config
字段被用来访问配置值:
public class IndexModel : PageModel { private readonly IConfiguration _config; public IndexModel(IConfiguration config) { _config = config; } }
public class HomeController : Controller { private readonly IConfiguration _config; public HomeController(IConfiguration config) { _config = config; } }
配置提供器不能使用DI,因为当它们被宿主建立的时候DI还是不可用的。
键
配置键值采取了如下约定:
- 键是大小写不敏感的。举个例子,
ConnectionString和
connectionstring
被当作相等的键。 - 如果一个相同键的值被相同或者不同的配置提供器所设置,那么最后一个设置的值将会被使用。
- 层次化的键值
- 在配置API之内,冒号分隔符在所有的平台都能工作。
- 在环境变量中,冒号分隔符可能不能在所有的平台下都能工作。但双下划线(__)会被所有的平台支持,并自动转换为一个冒号。
- 在Azure密钥库中,层次化的键值使用 (--) 作为一个分隔符。当密钥被加载到app的配置中的时候,需要些代码来使用冒号将(-)替换掉。
- ConfigurationBinder 支持将数组绑定到对象,数组绑定在Bind an array to a class 章节会有相应的介绍。
值
配置值采取如下的约定:
- 值都是字符串。
- 空值不能被存储在配置中或者绑定给对象。
提供器
下列表格展示了ASP.NET Core app中可用的配置提供器:
Provider | Provides configuration from… |
---|---|
Azure Key Vault Configuration Provider (Security topics) | Azure Key Vault |
Azure App Configuration Provider (Azure documentation) | Azure App Configuration |
Command-line Configuration Provider | Command-line parameters |
Custom configuration provider | Custom source |
Environment Variables Configuration Provider | Environment variables |
File Configuration Provider | Files (INI, JSON, XML) |
Key-per-file Configuration Provider | Directory files |
Memory Configuration Provider | In-memory collections |
User secrets (Secret Manager) (Security topics) | File in the user profile directory |
在app启动时,配置源按照其配置提供器指定的顺序被读取。本章描述的配置提供器是按照字符顺序,而不是代码安排它们的顺序来描述的。在代码中对配置提供器进行排序以匹配app所需要的底层配置源的优先级。
一个典型的配置提供器序列是:
- 文件(appsettings.json, appsettings.{Environment}.json,
其中{Environment}
是应用程序的当前寄宿环境) - Azure密钥库
- 用户密钥(Secret Manager)(仅针对开发环境)
- 环境变量
- 命令行参数
一个通用的实践是将命令行配置提供器放置在一系列提供器的最后,以允许命令行参数重载被其他提供器设置的配置。
当一个新的宿主被使用CreateDefaultBuilder
来初始化的时候,上面的提供器序列会被使用。更多 信息,请参考Default configuration 章节。
使用ConfigureHostConfiguration来配置宿主构造器
为了配置宿主构造器,可以调用ConfigureHostConfiguration 并提供配置数据。ConfigureHostConfiguration
用来初始化IHostEnvironment 以供后续构造进程使用。ConfigureHostConfiguration
可以被调用多次以产生额外的结果。
public static IHostBuilder CreateHostBuilder(string[] args) => Host.CreateDefaultBuilder(args) .ConfigureHostConfiguration(config => { var dict = new Dictionary<string, string> { {"MemoryCollectionKey1", "value1"}, {"MemoryCollectionKey2", "value2"} }; config.AddInMemoryCollection(dict); }) .ConfigureWebHostDefaults(webBuilder => { webBuilder.UseStartup<Startup>(); });
ConfigureAppConfiguration
当构造宿主时候可以调用ConfigureAppConfiguration
以指定除了被CreateDefaultBuilder
自动添加的之外其他的app的配置提供器。
public class Program { public static Dictionary<string, string> arrayDict = new Dictionary<string, string> { {"array:entries:0", "value0"}, {"array:entries:1", "value1"}, {"array:entries:2", "value2"}, {"array:entries:4", "value4"}, {"array:entries:5", "value5"} }; public static void Main(string[] args) { CreateHostBuilder(args).Build().Run(); } public static IHostBuilder CreateHostBuilder(string[] args) => Host.CreateDefaultBuilder(args) .ConfigureAppConfiguration((hostingContext, config) => { config.AddInMemoryCollection(arrayDict); config.AddJsonFile( "json_array.json", optional: false, reloadOnChange: false); config.AddJsonFile( "starship.json", optional: false, reloadOnChange: false); config.AddXmlFile( "tvshow.xml", optional: false, reloadOnChange: false); config.AddEFConfiguration( options => options.UseInMemoryDatabase("InMemoryDb")); config.AddCommandLine(args); }) .ConfigureWebHostDefaults(webBuilder => { webBuilder.UseStartup<Startup>(); }); }
使用命令行参数重载之前的配置
为了提供可被命令行参数重载的配置,可以在最后调用AddCommandLine:
.ConfigureAppConfiguration((hostingContext, config) => { // Call other providers here config.AddCommandLine(args); })
移除被CreateDefaultBuilder
添加的提供器
为了移除被CreateDefaultBuilder
添加的提供器,可以首先在IConfigurationBuilder.Sources 上调用Clear。
.ConfigureAppConfiguration((hostingContext, config) => { config.Sources.Clear(); // Add providers here })
在app启动时消费配置
在ConfigureAppConfiguration中提供给app的配置在app的启动阶段是可用的,包括
Startup.ConfigureServices
方法。更多信息,请参考Access configuration during startup 章节。
命令行配置提供器
CommandLineConfigurationProvider 在运行时从命令行参数键值对加载配置数据。
为了激活命令行配置,可以在ConfigurationBuilder的实例上调用AddCommandLine 扩展方法。
当调用CreateDefaultBuilder
方法时,AddCommandLine
方法会被自动调用。更多信息,请参考Default configuration 章节。
CreateDefaultBuilder
也会加载:
- appsettings.json and appsettings.{Environment}.json 文件中可选的配置。
- 在开发环境中的User secrets (Secret Manager)。
- 环境变量。
CreateDefaultBuilder
最后会添加命令行配置提供器。运行时传递的命令行参数会重载被其他提供器设置的配置。
当宿主被构造时,CreateDefaultBuilder
便会行动起来。因此,被CreateDefaultBuilder
激活的命令行配置可以影响宿主如何被配置。
对于基于ASP.NET Core模板的app来说,AddCommandLine
已经被CreateDefaultBuilder
所调用。为了添加额外的配置提供器,并且维护使用命令行参数重载配置的能力,可以在ConfigureAppConfiguration
中调用额外的提供器并最后调用AddCommandLine
。
.ConfigureAppConfiguration((hostingContext, config) => { // Call other providers here config.AddCommandLine(args); })
示例
示例app使用静态约定方法CreateDefaultBuilder来构建宿主,其包含了一个对AddCommandLine的调用。
- 在工程目录中打开一个命令提示符。
- 为
dotnet run
命令提供命令行参数:dotnet run CommandLineKey=CommandLineValue
。 - app运行之后,打开浏览器:
http://localhost:5000
。 - 可以观察到,输出包含了提供给dotnet run命令的键值对。
参数
参数值必须跟着一个=,或者当值跟随一个空格时,键值必须有一个前缀(--
或 /
),如果使用一个=号时,那么值不是必须的(比如 CommandLineKey=
)。
Key prefix | Example |
---|---|
No prefix | CommandLineKey1=value1 |
Two dashes (-- ) |
--CommandLineKey2=value2 , --CommandLineKey2 value2 |
Forward slash (/ ) |
/CommandLineKey3=value3 , /CommandLineKey3 value3 |
但是在一个命令行内,最好不要混合使用两种形式的参数。示例命令:
dotnet run CommandLineKey1=value1 --CommandLineKey2=value2 /CommandLineKey3=value3 dotnet run --CommandLineKey1 value1 /CommandLineKey2 value2 dotnet run CommandLineKey1= CommandLineKey2=value2
交换映射
交换映射运行键名称替换逻辑。当使用ConfigurationBuilder 手动构建一个配置时,为AddCommandLine 方法提供一个交互替换的字典。
当交互映射字典被使用时,字典便会检查以寻找与命令行参数提供的键匹配的键。如果命令行键在字典中被 找到,那么字典的值便会回传给app配置以设置键值对。对于任何具有前缀(-
)的命令行键,都会需要一个交互映射。
交互映射字典键的规则:
- 必须以一个 - 或者 两个 -- 开始。
- 交互映射字典不能包含重复的键。
创建一个交互映射字典。在下列示例中,两个交互映射被创建:
public static readonly Dictionary<string, string> _switchMappings = new Dictionary<string, string> { { "-CLKey1", "CommandLineKey1" }, { "-CLKey2", "CommandLineKey2" } };
当宿主被构造时,使用交互映射字典为参数来调用AddCommandLine:
.ConfigureAppConfiguration((hostingContext, config) =>
{
config.AddCommandLine(args, _switchMappings);
})
对于使用交互映射的app来说,对CreateDefaultBuilder
的调用不应该传递参数。CreateDefaultBuilder
方法的AddCommandLine
调用不包含映射的交互。并且没有方法来给CreateDefaultBuilder
传递交互映射字典。我们的解决方案并不是给CreateDefaultBuilder
传递参数,而是允许ConfigurationBuilder
方法的AddCommandLine
方法来处理参数以及交互映射字典。
在交互映射字典被创建之后,其包含了下表所示的数据:
Key | Value |
---|---|
-CLKey1 |
CommandLineKey1 |
-CLKey2 |
CommandLineKey2 |
在app启动时,如果使用了交互映射字典,配置便会在字典提供的键值上接受配置值:
dotnet run -CLKey1=value1 -CLKey2=value2
运行上面的命令后,配置会包含下表所示的配置值:
Key Value
CommandLineKey1 value1
CommandLineKey2 value2