较之传统通过App.config和Web.config这两个XML文件承载的配置系统,ASP.NET Core采用的这个全新的配置模型的最大一个优势就是针对多种不同配置源的支持。我们可以将内存变量、命令行参数、环境变量和物理文件作为原始配置数据的来源,如果采用物理文件作为配置源,我们可以选择不同的格式,比如XML、JSON和INI等。如果这些默认支持的配置源形式还不能满足你的需求,我们还可以通过注册自定义ConfigurationProvider的方式将其他形式数据作为我们的配置来源。接下来就让我们来逐个认识一下配置模型原生提供的ConfigurationProvider。

目录
MemoryConfigurationProvider
EnvironmentVariablesConfigurationProvider
CommandLineConfigurationProvider
JsonConfigurationProvider
XmlConfiguationProvider
IniConfigurationProvider
自定义ConfigurationProvider

一、MemoryConfigurationProvider

通过本章第2节对配置模型的介绍,我们知道ConfigurationProvider在配置模型中所起的作用就是读取原始的配置数据并将其转换成基于数据字典的物理结构。在所有的ConfigurationProvider类型中,MemoryConfigurationProvider最为简单直接,因为它对应的配置源就是一个数据字典,根本不需要作任何的结构转换。

MemoryConfigurationProvider定义在“Microsoft.Extensions.Configuration.Memory”命名空间下。。如下面的代码片段所示,派生于基类ConfigurationProvider的MemoryConfigurationProvider同时实现了IEnumerable<KeyValuePair<string, string>>接口,所以它自身可以作为一个字典对象来使用。原始的配置数据可以在创建MemoryConfigurationProvider的时候作为构造函数的参数来指定,也可以通过调用Add方法逐个进行添加。

a
 1: public class MemoryConfigurationProvider : ConfigurationProvider, IEnumerable<KeyValuePair<string, string>>

 2: {

 3:     public MemoryConfigurationProvider();

 4:     public MemoryConfigurationProvider(IEnumerable<KeyValuePair<string, string>> initialData);

 5:  

 6:     public void Add(string key, string value);

 7:     public IEnumerator<KeyValuePair<string, string>> GetEnumerator();

 8: }

在使用的时候,我们需要将MemoryConfigurationProvider对象注册到ConfigurationBuilder之上。具体来说,我们可以像前面演示的实例一样直接调用ConfigurationBuilder的Add方法,也可以调用如下所示的扩展方法AddInMemoryCollection。

 1: public static class MemoryConfigurationExtensions

 2: { 

 3:     public static IConfigurationBuilder AddInMemoryCollection(this IConfigurationBuilder configurationBuilder); 

 4:     public static IConfigurationBuilder AddInMemoryCollection(this IConfigurationBuilder configurationBuilder, IEnumerable<KeyValuePair<string, string>> initialData);

 5: }

二、EnvironmentVariablesConfigurationProvider

顾名思义,环境变量就是描述当前执行环境并影响进程执行行为的变量。按照作用域的不同,我们将环境变量非常三类,它们分别针对当前系统、当前用户和当前进程。系统和用户级别的环境变量保存在注册表中,其路径分别为“HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Control\Session Manager\Environment”和“HKEY_CURRENT_USER\Environment ”。

环境变量提取和维护可以通过静态类型Environment来实现。具体来说,我们可以调用静态方法GetEnvironmentVariable方法获得某个指定名称的环境变量的值,而GetEnvironmentVariables方法则会将返回所有的环境变量,EnvironmentVariableTarget枚举类型的参数代表环境变量作用域决定的存储位置。如果在调用GetEnvironmentVariable或者GetEnvironmentVariables方法师没有显式指定target参数或者将此参数指定为EnvironmentVariableTarget.Process,在进程初始化前存在的所有环境变量(包括针对系统、当前用户和当前进程)将会作为候选列表。

 1: public static class Environment

 2: { 

 3:     public static string GetEnvironmentVariable(string variable);

 4:     public static string GetEnvironmentVariable(string variable, EnvironmentVariableTarget target);

 5:     public static IDictionary GetEnvironmentVariables();

 6:     public static IDictionary GetEnvironmentVariables(EnvironmentVariableTarget target); 

 7: 

 8:     public static void SetEnvironmentVariable(string variable, string value);

 9:     public static void SetEnvironmentVariable(string variable, string value, EnvironmentVariableTarget target);

 10: }

 11:  

 12: public enum EnvironmentVariableTarget

 13: {

 14:     Process,

 15:     User,

 16:     Machine

 17: }

环境变量的添加、修改和删除均由SetEnvironmentVariable方法来实现,如果没有显式指定target参数,默认采用的是EnvironmentVariableTarget.Process。如果希望删除指定名称的环境变量,我们只需要在调用这个方法的时候将value参数设置为Null或者空字符串即可。

借助EnvironmentVariablesConfigurationProvider,我们可以将环境变量作为配置源。该类型定义在“Microsoft.Extensions.Configuration.EnvironmentVariables”程序集中,程序集的名称同时也是所在NuGet包的名称。如下面的代码片段所示,EnvironmentVariablesConfigurationProvider具有两个构造函数重载,如果调用默认无参构造函数,意味着我们会使用所有的环境变量。另一个构造函数提供了一个字符串类型的参数prefix,如果调用这个构造函数来创建一个EnvironmentVariablesConfigurationProvider,意味着我们只会使用名称以此为前缀的环境变量。

 1: public class EnvironmentVariablesConfigurationProvider : ConfigurationProvider

 2: { 

 3:     public EnvironmentVariablesConfigurationProvider();

 4:     public EnvironmentVariablesConfigurationProvider(string prefix);

 5:     public override void Load();

 6: }

由于作为原始配置数据的环境变量本身就是一个Key和Value均为字符串的数据字典,所以EnvironmentVariablesConfigurationProvider无需在进行结构转换,所以当Load方法被执行之后,它只需要将符合条件筛选出来并添加到自己的配置字典中即可。有一点值得一提的是,如果我们在创建EnvironmentVariablesConfigurationProvider对象是指定了用于筛选环境变量的前缀,当符合条件的环境变量被添加到自身的配置字典之后,这个前缀也会从元素的Key中剔除。如下所示的代码片段基本上体现了EnvironmentVariablesConfigurationProvider的实现逻辑。

 1: public class EnvironmentVariablesConfigurationProvider : ConfigurationProvider

 2: {

 3:     private readonly string prefix;

 4:  

 5:     public EnvironmentVariablesConfigurationProvider(string prefix = null)

 6:     {

 7:         this.prefix = prefix ?? string.Empty;

 8:     }

 9:  

 10:     public override void Load()

 11:     {

 12:         var dictionary = Environment.GetEnvironmentVariables()

 13:             .Cast<DictionaryEntry>()

 14:             .Where(it => it.Key.ToString().StartsWith(prefix, StringComparison.OrdinalIgnoreCase))

 15:             .ToDictionary(it => it.Key.ToString().Substring(prefix.Length), it => it.Value.ToString());

 16:         this.Data = new Dictionary<string, string>(dictionary, StringComparer.OrdinalIgnoreCase);

 17:    }

 18: }

也正是因为环境变量自身是数据字典,所以我们可以采用路径化的变量名定义一组相关的环境变量来提供一个复杂对象、集合或者字典对象的配置数据。如下面的代码片段所示,我们采用这样的方式将绑定为一个Profile对象的基本信息定义成一组相关的环境变量。由于这组环境变量名称具有相同的前缀“Profile”,所以我们利用这个前缀来创建一个 EnvironmentVariablesConfigurationProvider对象。在将它添加到ConfigurationBuilder之后,我们是用后者生成的Configuration对象采用配置绑定的方式得到一个Profile对象。

 1: Environment.SetEnvironmentVariable("Profile:Gender", "Male");

 2: Environment.SetEnvironmentVariable("Profile:Age", "18");

 3: Environment.SetEnvironmentVariable("Profile:ContactInfo:Email", "foobar@outlook.com");

 4: Environment.SetEnvironmentVariable("Profile:ContactInfo:PhoneNo", "123456789");

 5:  

 6: Profile profile = new ConfigurationBuilder()

 7:     .Add(new EnvironmentVariablesConfigurationProvider("Profile:"))

 8:     .Build()

 9:     .Get<Profile>();

在使用EnvironmentVariablesConfigurationProvider的时候,我们可以按照上面演示的方式显式地调用Add方法将创建的EnvironmentVariablesConfigurationProvider对象注册到指定的ConfigurationBuilder对象之外,也可以直接调用如下所示的扩展方法AddEnvironmentVariables。

 1: public static class EnvironmentVariablesExtensions

 2: {

 3:     public static IConfigurationBuilder AddEnvironmentVariables(this IConfigurationBuilder configurationBuilder);

 4:     public static IConfigurationBuilder AddEnvironmentVariables(this IConfigurationBuilder configurationBuilder, string prefix);

 5: }

三、CommandLineConfigurationProvider

在很多情况下,我们会采用Self-Host的方式将一个ASP.NET Core应用寄宿一个托管进程中,在这种情况下我们倾向于采用命令行的方式来启动寄宿程序。当以命令行的形式启动一个ASP.NET Core应用时,我们希望直接使用命名行开关(Switch)来控制应用的一些行为,所以命令行开关自然也就成为了配置常用的来源之一。配置模型针对这种配置源的支持是通过CommandLineConfigurationProvider来实现的,该类型定义在“Microsoft.Extensions.Configuration.CommandLine”程序集中,这也是所在NuGet包的名称。

在以命令行的形式执行某个命令的时候,命令行开关(包括名称和值)体现为一个简单的字符串集合,所以CommandLineConfigurationProvider的根本目的在于将命名行开关从字符串集合的形式转换成配置字典的形式。要充分理解这个转换规则,我们先得来了解一下CommandLineConfigurationProvider支持的命令行开关究竟采用怎样的形式来指定。我们通过一个简单的实例来说明命令行开关的集中指定方式。假设我们有一个命令“exec”并采用如下所示的方式执行某个托管程序(app)。

 1: exec app {options} 

在执行这个命令的时候我们通过相应的命令行开关指定两个选项,其中一个表示采用的CPUI架构(X86或者X64),另一个表示运行时类型(CLR或者CoreCLR),我们将这两个命令行开关分别命名为architecture和runtime。在执行命名行的时候,我们可以采用如下三种不同的方式指定这两个命名行开关。

 1: exec app /architecture x64 /runtime coreclr 

 2: exec app --architecture x64 --runtime coreclr 

 3: exec app architecture=x64 architecture=coreclr 

为了执行上的便利,很多命名行开关都具有缩写的形式。以上述的这两个命令行开关为例,我们可以采用首字母“a”和“r”来代表作为全名的“architecture”和“runtime”。如果采用缩写的命令行开关名称,那么我们就可以按照如下两种方式指定CPU架构和运行时类型。

 1: exec app –-a x64 –-r coreclr 

 2: exec app -a x64 -r coreclr 

综上所示,我们一共有五种指定命名行开关的方式,其中三种采用命令行开关的全名,余下的两种则使用命令行开关的缩写形式。这五种命名开关的指定形式所采用的原始参数以及缩写与全名的映射关系。

在对命令行开关的集中指定形式具有基本了解之后,我们来认识一下将它们引入配置模型并作为配置源数据来源的CommandLineConfigurationProvider。如下面的代码片断所示,我们需要以字符串集合的形式指定原始的命令行参数来创建一个CommandLineConfigurationProvider对象,只读属性Args返回的也正是这个集合。

 1: public class CommandLineConfigurationProvider : ConfigurationProvider

 2: {

 3:     public CommandLineConfigurationProvider(IEnumerable<string> args, IDictionary<string, string> switchMappings = null);

 4:     public override void Load();

 5:  

 6:     protected IEnumerable<string> Args { get; }

 7: }

构造函数另一个字典类型的参数switchMappings用于指定命令行开关名称的缩写形式与全名的映射关系。一个命令行开关可以包含多个不同的缩写形式,比如“architecture”可以缩写成“a”,也和缩写成“arch”。如果采用缩写形式,指定的命名行开关名称必须以“-”或者“--”为前缀,那么这个switchMappings参数对应字典对象中的Key也需要采用相应的前缀。

在使用CommandLineConfigurationProvider的时候,我们可以直接创建这个对象并调用Add方法将其添加到指定的ConfigurationBuilder之中。我们可以直接调用ConfigurationBuilder对象具有如下定义的两个扩展方法AddCommandLine达到相同的目的。

 1: public static class CommandLineConfigurationExtensions

 2: {

 3:     public static IConfigurationBuilder AddCommandLine(this IConfigurationBuilder configurationBuilder, string[] args);

 4:     public static IConfigurationBuilder AddCommandLine(this IConfigurationBuilder configurationBuilder, string[] args,IDictionary<string, string> switchMappings);

 5: }

我们照例通过通过一个简单的实例来演示如何利用CommandLineConfigurationProvider将命令行开关作为配置的原始来源。如下面的代码片断所示,在静态方法GetConfigurations中,我们按照上面表格所示的五种方式创建了以命名行参数作为来源的Configuration对象。为了验证这五种命名行开关指定形式的等效性,我们从中提取配置项“architecture”和“runtime”并验证它们的值。

   1: public class Program

   2: {

   3:     public static void Main(string[] args)

   4:     {

   5:         foreach (IConfiguration configuration in GetConfigurations())

   6:         {

   7:             Debug.Assert(configuration["architecture"] == "x64");

   8:             Debug.Assert(configuration["runtime"] == "coreclr");

   9:         }

  10:     }

  11:  

  12:     private static IEnumerable<IConfiguration> GetConfigurations()

  13:     {

  14:         yield return new ConfigurationBuilder()

  15:          .AddCommandLine(new string[] { "/architecture", "x64", "/runtime", "coreclr" })

  16:          .Build();

  17:  

  18:         yield return new ConfigurationBuilder()

  19:         .AddCommandLine(new string[] { "--architecture", "x64", "--runtime", "coreclr" })

  20:         .Build();

  21:  

  22:         yield return new ConfigurationBuilder()

  23:         .AddCommandLine(new string[] { "architecture=x64", "runtime=coreclr" })

  24:         .Build();

  25:  

  26:         yield return new ConfigurationBuilder()

  27:         .AddCommandLine(new string[] { "--a", "x64", "--r", "coreclr" }, new Dictionary<string, string>

  28:         {

  29:             ["--a"] = "architecture",

  30:             ["--r"] = "runtime"

  31:         }).Build();

  32:  

  33:         yield return new ConfigurationBuilder()

  34:         .AddCommandLine(new string[] { "-a", "x64", "-r", "coreclr" }, new Dictionary<string, string>

  35:         {

  36:             ["-a"] = "architecture",

  37:             ["-r"] = "runtime"

  38:         }).Build();

  39:     }

  40: }

考虑到命名行的使用场景,我们一般情况下只利用命令行开关来提供单一的配置项,很少将其邦定为一个结构化的Options对象。不过命名行开关虽然以字符串集合的形式体现,但是它们可以直接映射为配置字典,所以我们完全可以通过采用路径化的命令行开关(比如“/foo:bar:baz abc”)来提供最终绑定为复杂对象设置集合和字典的配置源。

ASP.NET Core的配置(1):读取配置信息
ASP.NET Core的配置(2):配置模型详解
ASP.NET Core的配置(3): 将配置绑定为对象[上篇]
ASP.NET Core的配置(3): 将配置绑定为对象[下篇]
ASP.NET Core的配置(4):多样性的配置源[上篇]
ASP.NET Core的配置(4):多样性的配置源[中篇]
ASP.NET Core的配置(4):多样性的配置源[下篇]
ASP.NET Core的配置(5):配置的同步[上篇]
ASP.NET Core的配置(5):配置的同步[下篇]

ASP.NET Core的配置(4):多样性的配置来源[上篇]的更多相关文章

  1. ASP.NET Core 2.2 基础知识(六) 配置(内含MySql+EF)

    先上一段代码,了解一下 .NET Core 配置数据的结构. 新建一个 控制台项目,添加一个文件 json.json ,文件内容如下: { "country": "cn& ...

  2. asp.net core 3.0 MVC JSON 全局配置

    asp.net core 3.0 MVC JSON 全局配置 System.Text.Json(default) startup配置代码如下: using System.Text.Encodings. ...

  3. [ASP.NET Core 3框架揭秘] Options[1]: 配置选项的正确使用方式[上篇]

    依赖注入不仅是支撑整个ASP.NET Core框架的基石,也是开发ASP.NET Core应用采用的基本编程模式,所以依赖注入十分重要.依赖注入使我们可以将依赖的功能定义成服务,最终以一种松耦合的形式 ...

  4. [ASP.NET Core 3框架揭秘] Options[2]: 配置选项的正确使用方式[下篇]

    四.直接初始化Options对象 前面演示的几个实例具有一个共同的特征,即都采用配置系统来提供绑定Options对象的原始数据,实际上,Options框架具有一个完全独立的模型,可以称为Options ...

  5. [ASP.NET Core开发实战]基础篇06 配置

    配置,是应用程序很重要的组成部分,常常用于提供信息,像第三方应用登录钥匙.上传格式与大小限制等等. ASP.NET Core提供一系列配置提供程序读取配置文件或配置项信息. ASP.NET Core项 ...

  6. [ASP.NET Core 3框架揭秘] 跨平台开发体验: Windows [上篇]

    微软在千禧年推出 .NET战略,并在两年后推出第一个版本的.NET Framework和IDE(Visual Studio.NET 2002,后来改名为Visual Studio),如果你是一个资深的 ...

  7. [转][ASP.NET Core 3框架揭秘] 跨平台开发体验: Windows [上篇]

    微软在千禧年推出 .NET战略,并在两年后推出第一个版本的.NET Framework和IDE(Visual Studio.NET 2002,后来改名为Visual Studio),如果你是一个资深的 ...

  8. ASP.NET Core 缓存技术 及 Nginx 缓存配置

    前言 在Asp.Net Core Nginx部署一文中,主要是讲述的如何利用Nginx来实现应用程序的部署,使用Nginx来部署主要有两大好处,第一是利用Nginx的负载均衡功能,第二是使用Nginx ...

  9. Asp.Net Core轻松入门之WebHost的配置

    在本篇文章中,我来讲一讲如何利用WebHost来加载配置文件和设置启动的Url 在前面的文章中讲过,ASP.Net Core应用程序会自动加载appsettings.json中的配置文件,那么如果配置 ...

  10. ASP.NET Core 从 gitlab-ci 环境变量读取配置

    最近在加强持续集成,遇到一个场景需要通过 gitlab-ci 环境变量(Settings -> Settings -> CI/CD -> Variables )在持续集成时向 ASP ...

随机推荐

  1. BZOJ2908: 又是nand

    Description 首先知道A nand B=not(A and B) (运算操作限制了数位位数为K)比如2 nand 3,K=3,则2 nand 3=not (2 and 3)=not 2=5. ...

  2. Docker Volume 之权限管理(转)

    Volume数据卷是Docker的一个重要概念.数据卷是可供一个或多个容器使用的特殊目录,可以为容器应用存储提供有价值的特性: 持久化数据与容器的生命周期解耦:在容器删除之后数据卷中的内容可以保持.D ...

  3. Windows下使用doxygen阅读和分析C/C++代码

    Windows下使用doxygen阅读和分析C/C++代码 转自:http://blog.sina.com.cn/s/blog_63d902570100gwk6.html 虽然使用各种IDE或者Sou ...

  4. sql 更新列表中最老的一条数据

    今天组长给个任务说要给摄像头触发一个列表.让缓存5条数据,每次摄像头触发更新一条,丢掉最老的一条数据.原来的update是直接更新掉一条,没带缓存的.然后搞了个sql语句,是这样的: UPDATE C ...

  5. oracle遍历表更新另一个表(一对多)

    declare cursor cur_test is select t.txt_desig, m.segment_id, s.code_type_direct, case when s.uom_dis ...

  6. apache rewrite_mod 经典疑问解答

    1.RewriteRule ^(com\/.*)$ index.php?do=$1 问:上面的规则匹配表达式 "^(.*)$" 匹配的内容是什么 答:匹配内容是URI站点目录:/d ...

  7. 浏览器地址栏输入一个URL后回车,将会发生的事情

    浏览器向DNS服务器查找输入URL对应的IP地址. DNS服务器返回网站的IP地址. 浏览器根据IP地址与目标web服务器在80端口上建立TCP连接 浏览器获取请求页面的html代码. 浏览器在显示窗 ...

  8. 浅谈Js对象的概念、创建、调用、删除、修改!

    一.我们经常困惑,对象究竟是什么,其实这是一种思维,一种意识上的东西,就像我们都说    世界是有物质组成的道理一样,理解了下面的几句话!对象也不是那么抽象!    1.javascript中的所有事 ...

  9. Window.focus()让页面成为当前窗体

    Window.focus()让页面成为当前窗体 最近在弄在线客服的时候,想在收到信息时候让窗体自动弹出到最前,最小化的时候也是弹出到最前.本来以为很麻烦,问了好多人,都不知道,在网上查资料也没有查到. ...

  10. CYQ.Data V5 分布式缓存MemCached应用开发介绍

    前言 今天大伙还在热议关于.NET Core的东西,我只想说一句:在.NET 跨平台叫了这么多年间,其实人们期待的是一个知名的跨平台案例,而不是一堆能跨平台的消息. 好,回头说说框架: 在框架完成数据 ...