The new configuration system uses .NET Core [5]: support all kinds of talk about the default configuration source [memory variables, environment variables, and command-line arguments]

Compared with the traditional configuration of the system by Web.config and App.config two XML documents carried by a maximum advantage of this new model of .NET Core configuration is used for a variety of different configurations sources of support. We can be memory variables, command-line arguments, environment variables, and physical file as the source of the original configuration data, if configured as a source physical file, we can choose a different format (such as XML, JSON and INI, etc.). If the default configuration source in the form of support can not meet your needs, we can also register a custom ConfigurationSource way to other forms of data as the source of our configuration. [This article has been synchronized to the " ASP.NET Framework Core Secret " among]

Catalog
a memory variable
Second, the environment variable
three command-line arguments

First, the memory variable

From the first article of this series is to start now, all our example demonstrates been using this type of ConfigurationSource MemoryConfigurationSource to provide original configuration. We know MemoryConfigurationSource using a dictionary object (a particular element should be of type KeyValuePair <string, string> set) is stored as configuration data of the original container. As a ConfigurationSource, it is always engaged in the specific configuration data read work by creating a corresponding ConfigurationProvider, then MemoryConfigurationSource will provide a kind of ConfigurationProvider it?

   1: public class MemoryConfigurationSource : IConfigurationSource
   2: {
   3:     public IEnumerable<KeyValuePair<string, string>> InitialData { get; set; }
   4:  
   5: Build public IConfigurationProvider (IConfigurationBuilder builder)
   6:     {
   7:         return new MemoryConfigurationProvider(this);
   8:     }
   9: }

Snippet given above embodies MemoryConfigurationSource complete definition, we can see that it has a IEnumerable <KeyValuePair <string, string >> InitialData type attribute to store the initial configuration data. As can be seen from the implementation Build method, which was actually used to read the original configuration data objects is a MemoryConfigurationProvider type, the type as defined in the following code fragment.

   1: public class MemoryConfigurationProvider : ConfigurationProvider, IEnumerable<KeyValuePair<string, string>>
   2: {
   3:     public MemoryConfigurationProvider(MemoryConfigurationSource source);
   4:     public void Add(string key, string value);
   5:     public IEnumerator<KeyValuePair<string, string>> GetEnumerator();
   6:     IEnumerator IEnumerable.GetEnumerator();
   7: }

As can be seen from the above code fragment, MemoryConfigurationProvider derived from the abstract class ConfigurationProvider, while also achieving a IEnumerable <KeyValuePair <string, string >> interface. We know ConfigurationProvider directly using a Dictionary <string, string> to save the configuration data, when we call the constructor to create an object based on a MemoryConfigurationSource MemoryConfigurationProvider, it only needs to be transferred to this dictionary through the configuration data can be saved InitiateData property. Add MemoryConfigurationProvider also defines a method is that we can can add a new configuration to configure the dictionary at any time.

By earlier description of the configuration model, we know ConfigurationProvider in the configuration model role is to read the original configuration data and convert it into a configured dictionary. In all of the predefined ConfigurationProvider types, MemoryConfigurationProvider the most simple and direct, because it corresponds to the configuration of the source configuration is a dictionary, so there is no need to make any structural transformation.

When using the MemoryConfigurationSource build configuration, we need to register it onto ConfigurationBuilder. Specifically, we can be like the previous examples demonstrate, like ConfigurationBuilder directly call the Add method, you can also call the extension method as shown below AddInMemoryCollection two overloaded.

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


Second, the environment variable

As the name suggests, it is to describe the current environment variables affect the execution environment and execution behavior of process variables. According to different scopes, we set the environment variable is divided into three categories, namely for the current system, the current user environment variables and the current process. System and user-level environment variable is stored in the registry, its path are " HKEY_LOCAL_MACHINE \ the SYSTEM \ ControlSet001 \ Control \ the Session Manager \ Environment " and " HKEY_CURRENT_USER \ Environment  ."

Environment variable extraction and maintenance can be achieved by static type Environment. Specifically, we can call its static method GetEnvironmentVariable way to get the value of a specified environment variable name, and GetEnvironmentVariables method will return all of the environment variables, memory EnvironmentVariableTarget enumeration type parameter represents the environment variable scoping decisions position. If you do not call GetEnvironmentVariable or GetEnvironmentVariables division method explicitly specify the target parameter or specify parameters for EnvironmentVariableTarget.Process, all environment variables exist before the initialization process (including the system for the current user and the current process) will serve as the candidate list.

   1: public static class Environment
   2: {
   3:     public static string GetEnvironmentVariable(string variable);
   4:     public static string GetEnvironmentVariable(string variable, EnvironmentVariableTarget target);
   5:  
   6:     public static IDictionary GetEnvironmentVariables();
   7:     public static IDictionary GetEnvironmentVariables(EnvironmentVariableTarget target);
   8:  
   9:     public static void SetEnvironmentVariable(string variable, string value);
  10:     public static void SetEnvironmentVariable(string variable, string value, EnvironmentVariableTarget target);
  11: }
  12:  
  13: public enum EnvironmentVariableTarget
  14: {
  15:     Process,
  16:     User,
  17:     Machine
  18: }

Add environment variables, modify, and delete methods by SetEnvironmentVariable to complete, if not explicitly specified target parameters, the default is used in EnvironmentVariableTarget.Process. If you want to remove an environment variable to specify the name, we only need to call this method when the value of the parameter is set to Null or empty string can be.

In addition to using static type Environment in the program, we can also execute the command line to view and set the environment variable. In addition, we can also use the "System Properties (System Properties)" View Settings tool to visualize the way and set up the system and user-level environment variable ( "This PC"> "Properties"> "Change Settings"> "Advanced ">" Environment Variables "). If using Visual Studio 2015 to debug applications we write, we can set the way the project properties to set process-level environment variables ( "Properties"> "Debug"> "Environment Variables").

11

Source configured for environment variables is represented by a EnvironmentVariablesConfigurationSource type that is defined in NuGet package " Microsoft.Extensions.Configuration.EnvironmentVariables " being. This type refers to the definition of a string type of property Prefix, which represents a prefix screening using environment variables, which means that if we set the Prefix property will only select the name as a prefix environment variable.

   1: public class EnvironmentVariablesConfigurationSource : IConfigurationSource
   2: {
   3:     public string Prefix { get; set; }
   4: Build public IConfigurationProvider (IConfigurationBuilder builder)
   5:     {
   6:         return new EnvironmentVariablesConfigurationProvider(this.Prefix);
   7:     }
   8: }

Through code segment given above, we can see EnvironmentVariablesConfigurationSource will be done by the corresponding read operation EnvironmentVariablesConfigurationProvider environmental variables. Substantially reflects the code shown below in the definition EnvironmentVariablesConfigurationProvider. Since the original configuration data as an environment variable is itself a Key and Value data dictionary are strings, so no need to EnvironmentVariablesConfigurationProvider structure during the conversion, so when the Load method is executed, it only needs to meet the criteria to filter out and add to your own the dictionary can be configured. It is worth mentioning that, if we create EnvironmentVariablesConfigurationProvider target is the prefix for screening environment variable specifies, when qualifying environment variables are added to the configuration of the dictionary itself, this prefix will be removed from the Key elements. This detail is also reflected in the Load method defined above.

   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: }

When using EnvironmentVariablesConfigurationSource, we can call the Add method to register it to the specified ConfigurationBuilder object. Extension methods AddEnvironmentVariables In addition, EnvironmentVariablesConfigurationSource of registration may also call directly IConfigurationBuilder interface follows two overloaded to complete.

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

As usual we write a simple example to demonstrate how to use the environment variable as the source. As shown in the following code fragment, the method we call the static method SetEnvironment Environment environment is provided four variables having the same variable name prefix "TEST_". We call the method AddEnvironmentVariables create a EnvironmentVariablesConfigurationSource object and register it on ConfigurationBuilder created. We will call AddEnvironmentVariables method is the environment variable name prefix "TEST_" as a parameter. Subsequent code that we are very familiar with, namely the use of Options mode read environment variables and bind to a Profile object.

   1: Environment.SetEnvironmentVariable("TEST_gender", "Male");
   2: Environment.SetEnvironmentVariable("TEST_age", "18");
   3: Environment.SetEnvironmentVariable("TEST_contactInfo:emailAddress", "[email protected]");
   4: Environment.SetEnvironmentVariable("TEST_contactInfo:PhoneNo", "123456789");
   5:  
   6: IConfiguration config = new ConfigurationBuilder()
   7:     .AddEnvironmentVariables("TEST_")
   8:     .Build();
   9:  
  10: Profile profile = new ServiceCollection()
  11:     .AddOptions()
  12:     .Configure<Profile>(config)
  13:     .BuildServiceProvider()
  14:     .GetService<IOptions<Profile>>()
  15:     .Value;


Third, the command-line arguments

In many cases, we will use the Self-Host a way ASP.NET Core boarding a hosted application process, in which case we tend to use the command line to start boarding procedures. When starting a ASP.NET Core command-line application form, we hope to directly use the named line switches (Switch) to control the behavior of some applications, the command-line switches naturally became one of the commonly used configuration source. Configuration model supports this configuration for the source is achieved by CommandLineConfigurationSource, of the type defined in the NuGet package "Microsoft.Extensions.Configuration.CommandLine" in.

When a command to execute the command line options, command-line switches (including the name and value) is embodied as a simple string collection, the fundamental purpose is to CommandLineConfigurationSource named switching from row to a string array configuration dictionary. To fully understand this transformation rules, we come to find out CommandLineConfigurationSource support the use of command-line switches exactly what form to specify. Through a simple example, a concentrated manner specified command-line switches. Suppose we have a command "exec" and by way of the following execution of a managed program (app).

   1: exec app {options} 

When we execute the command specified by command-line switches corresponding to two options, one of which represents the CPU architecture used (X86 or X64), the other represents a type of runtime (CLR or CoreCLR), we have the two command line switch architecture and named runtime. When performing naming row, we can specify two different naming line switches in three ways.

   1: exec app /architecture x64 /runtime coreclr
   2: exec app --architecture x64 --runtime coreclr
   3: exec app architecture=x64 architecture=coreclr

In order to facilitate the implementation of many named line switches have abbreviated form, has a mapping relationship (Switch Mapping) between the full name and acronym command-line switches. Both of the above command line switches, for example, we can use the first letter "a" and "r" is represented as the full name of the "architecture" and "runtime". If the abbreviated name of the command-line switch, then we can assign CPU architecture and run-time type in the following two ways.

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

Fully illustrated, we are named a total of five designated line switches, three of which uses the full name of the command-line switches, and the remaining two use the abbreviated form of the command-line switches. The following table summarizes the parameters specified in the form of the five original name switch employed full name and acronym mapping relationship. Therein lies an important detail, the character "-" can only refer to the specified command-line switches in abbreviated form, but "-" is supported by the full name and abbreviation.

 

Arguments

Switch Mapping

/architecture x64 /runtime coreclr

-

--architecture x64 --runtime coreclr

-

architecture=x64 runtime=coreclr

-

--a x64 --r coreclr

--a: architecture, --r: runtime

-a x64 -r coreclr

-a: architecture, -r: runtime

 

The original command line parameters always embodied as an array of strings, CommandLineConfigurationSource string array to configure the source, and using the corresponding configuration ConfigurationProvider convert it to the dictionary. As shown in the following code snippet, CommandLineConfigurationSource having Args and SwitchMappings, the former carrying the official representative of the original command string array parameter, which is stored a mapping between the command-line switches and abbreviated designation. Build the method implementation, it creates an object based on these two properties CommandLineConfigurationProvider.

   1: public class CommandLineConfigurationSource : IConfigurationSource
   2: {
   3:     public IEnumerable<string>         Args { get; set; }
   4:     public IDictionary<string, string>     SwitchMappings { get; set; }
   5:  
   6: Build public IConfigurationProvider (IConfigurationBuilder builder)
   7:     {
   8:         return new CommandLineConfigurationProvider(this.Args, this.SwitchMappings);
   9:     }   
  10: }

CommandLineConfigurationProvider has the following definition is still an abstract class ConfigurationProvider successor. Its purpose is very clear, that is reflected in an array of strings of the original command-line arguments to parse and parse out the parameter name and value added to the configuration dictionary. All this is in the Load method of rewriting of completion.

   1: public class CommandLineConfigurationProvider : ConfigurationProvider
   2: {
   3:     protected IEnumerable<string> Args { get; }
   4:     public CommandLineConfigurationProvider(IEnumerable<string> args, IDictionary<string, string> switchMappings = null);
   5:     public override void Load();
   6: }

When using command-line parameters based on a configuration source, we can create a CommandLineConfigurationSource and register it on ConfigurationBuilder. The following two extension methods we can call IConfigurationBuilder interface AddCommandLine two steps into one.

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

In order to give readers and friends of CommandLineConfigurationProvider Resolution Policy command-line parameters used have a deep understanding, we demonstrate a simple example. We create a console application, and add a dependency for "Microsoft.Extensions.Configuration.CommandLine" NuGet this package. In the Main method, we write the following simple example program period.

   1: while (true)
   2: {
   3:     try
   4:     {
   5:         Console.Write("Enter command line switches:");
   6:         string arguments = Console.ReadLine();
   7:         Dictionary<string, string> mapping = new Dictionary<string, string>
   8:         {
   9:             ["--a"]     = "architecture ",
  10:             ["-a"]     = "architecture ",
  11:             ["--r"]     = "runtime",
  12:             ["-r"]     = "runtime",
  13:         };
  14:         IConfiguration config = new ConfigurationBuilder()
  15:             .AddCommandLine(arguments.Split(' '), mapping)
  16:             .Build();
  17:  
  18:         foreach (var section in config.GetChildren())
  19:         {
  20:             Console.WriteLine($"{section.Key}: {section.Value}");
  21:         }
  22:     }
  23:     catch(Exception ex)
  24:     {
  25:         Console.WriteLine(ex.Message);
  26:     }
  27: }

As shown in the above code fragment, we have an infinite loop receiving user-specified command line parameters, and accordingly creates a CommandLineConfigurationSource object and register it on ConfigurationBuilder. We created this CommandLineConfigurationSource object when the dictionary also specifies a mapping between command line switch. Next we use this ConfigurationBuilder generate a Configuration object and print out all of its sub-configuration sections of Key and Value. We run the program described above were used in five ways a command line parameter based on the output results, shown below, parses the command line will find resulting configuration parameters are equivalent.

image

 

Compared with the traditional configuration of the system by Web.config and App.config two XML documents carried by a maximum advantage of this new model of .NET Core configuration is used for a variety of different configurations sources of support. We can be memory variables, command-line arguments, environment variables, and physical file as the source of the original configuration data, if configured as a source physical file, we can choose a different format (such as XML, JSON and INI, etc.). If the default configuration source in the form of support can not meet your needs, we can also register a custom ConfigurationSource way to other forms of data as the source of our configuration. [This article has been synchronized to the " ASP.NET Framework Core Secret " among]

Catalog
a memory variable
Second, the environment variable
three command-line arguments

First, the memory variable

从本被系列第一篇开始到现在,我们所有的实例演示一直都在使用MemoryConfigurationSource这种类型的ConfigurationSource来提供原始的配置。我们知道MemoryConfigurationSource采用一个字典对象(具体来说应该是一个元素类型为KeyValuePair<string, string>的集合)作为存放原始配置数据的容器。作为一个ConfigurationSource,它总是通过创建某个对应的ConfigurationProvider来从事具体的配置数据读取工作,那么MemoryConfigurationSource会提供一个怎样的ConfigurationProvider呢?

   1: public class MemoryConfigurationSource : IConfigurationSource
   2: {
   3:     public IEnumerable<KeyValuePair<string, string>> InitialData { get; set; }
   4:  
   5:     public IConfigurationProvider Build(IConfigurationBuilder builder)
   6:     {
   7:         return new MemoryConfigurationProvider(this);
   8:     }
   9: }

上面给出的代码片段体现了MemoryConfigurationSource的完整定义,我们可以看到它具有一个IEnumerable<KeyValuePair<string, string>>类型的属性InitialData来存放初始的配置数据。从Build方法的实现可以看出,真正被它用来读取原始配置数据的是一个MemoryConfigurationProvider类型的对象,该类型的定义如下面的代码片段所示。

   1: public class MemoryConfigurationProvider : ConfigurationProvider, IEnumerable<KeyValuePair<string, string>>
   2: {
   3:     public MemoryConfigurationProvider(MemoryConfigurationSource source);
   4:     public void Add(string key, string value);
   5:     public IEnumerator<KeyValuePair<string, string>> GetEnumerator();
   6:     IEnumerator IEnumerable.GetEnumerator();
   7: }

从上面的代码片段可以看出,MemoryConfigurationProvider派生于抽象类ConfigurationProvider,同时还实现了IEnumerable<KeyValuePair<string, string>>接口。我们知道ConfigurationProvider直接使用一个Dictionary<string, string>来保存配置数据,当我们根据一个MemoryConfigurationSource对象调用构造函数创建MemoryConfigurationProvider的时候,它只需要将通过InitiateData属性保存的配置数据转移到这个字典中即可。MemoryConfigurationProvider还定义了一个Add方法是我们可以在任何时候都可以向配置字典中添加一个新的配置项。

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

在利用MemoryConfigurationSource生成配置的时候,我们需要将它注册到ConfigurationBuilder之上。具体来说,我们可以像前面演示的实例一样直接调用ConfigurationBuilder的Add方法,也可以调用如下所示的了两个重载的扩展方法AddInMemoryCollection。

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


二、环境变量

顾名思义,环境变量就是描述当前执行环境并影响进程执行行为的变量。按照作用域的不同,我们将环境变量划分成三类,即分别针对当前系统、当前用户和当前进程的环境变量。系统和用户级别的环境变量保存在注册表中,其路径分别为“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:  
   6:     public static IDictionary GetEnvironmentVariables();
   7:     public static IDictionary GetEnvironmentVariables(EnvironmentVariableTarget target);
   8:  
   9:     public static void SetEnvironmentVariable(string variable, string value);
  10:     public static void SetEnvironmentVariable(string variable, string value, EnvironmentVariableTarget target);
  11: }
  12:  
  13: public enum EnvironmentVariableTarget
  14: {
  15:     Process,
  16:     User,
  17:     Machine
  18: }

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

除了在程序中利用静态类型Environment,我们还可以执行命令行的方式查看和设置环境变量。除此之外,我们还可以利用“系统属性(System Properties)”设置工具以可视化的方式查看和设置系统和用户级别的环境变量(“This PC”>“Properties”>“Change Settings”>“Advanced”>“Environment Variables”)。如果采用Visual Studio 2015来调试我们编写的应用,我们可以设置项目属性的方式来设置进程级别的环境变量( “Properties” > “Debug”> “Environment Variables” )。

11

针对环境变量的配置源通过如下一个 EnvironmentVariablesConfigurationSource类型来表示,该类型定义在NuGet包“Microsoft.Extensions.Configuration.EnvironmentVariables”之中。该类型指定义了一个字符串类型的属性Prefix,它表示用于筛选环境变量采用的前缀,也就是说如果我们设置了这个Prefix属性,只会选择名称以此作为前缀的环境变量。

   1: public class EnvironmentVariablesConfigurationSource : IConfigurationSource
   2: {
   3:     public string Prefix { get; set; }
   4:     public IConfigurationProvider Build(IConfigurationBuilder builder)
   5:     {
   6:         return new EnvironmentVariablesConfigurationProvider(this.Prefix);
   7:     }
   8: }

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

   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: }

在使用EnvironmentVariablesConfigurationSource的时候,我们可以调用Add方法将它注册到指定的ConfigurationBuilder对象上。除此之外,EnvironmentVariablesConfigurationSource的中注册还可以直接调用IConfigurationBuilder接口的如下两个重载的扩展方法AddEnvironmentVariables来完成。

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

我们照例编写一个简单的实例来演示如何采用环境变量作为配置源。如下面的代码片段所示,我们调用Environment的静态方法SetEnvironment方法设置了四个环境变量,变量名称具有相同的前缀“TEST_”。我们调用方法AddEnvironmentVariables创建一个EnvironmentVariablesConfigurationSource对象并将其注册到创建的ConfigurationBuilder之上。调用AddEnvironmentVariables方法是我们将环境变量名称前缀“TEST_” 作为参数。后续的代码我们已经很熟悉了,即采用Options模式读取环境变量并绑定为一个Profile对象。

   1: Environment.SetEnvironmentVariable("TEST_gender", "Male");
   2: Environment.SetEnvironmentVariable("TEST_age", "18");
   3: Environment.SetEnvironmentVariable("TEST_contactInfo:emailAddress", "[email protected]");
   4: Environment.SetEnvironmentVariable("TEST_contactInfo:PhoneNo", "123456789");
   5:  
   6: IConfiguration config = new ConfigurationBuilder()
   7:     .AddEnvironmentVariables("TEST_")
   8:     .Build();
   9:  
  10: Profile profile = new ServiceCollection()
  11:     .AddOptions()
  12:     .Configure<Profile>(config)
  13:     .BuildServiceProvider()
  14:     .GetService<IOptions<Profile>>()
  15:     .Value;


三、命令行参数

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

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

   1: exec app {options} 

在执行这个命令的时候我们通过相应的命令行开关指定两个选项,其中一个表示采用的CPU架构(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

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

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

综上所示,我们一共有五种指定命名行开关的方式,其中三种采用命令行开关的全名,余下的两种则使用命令行开关的缩写形式。下表总结了这五种命名开关的指定形式所采用的原始参数以及缩写与全名的映射关系。这里隐藏着一个重要的细节,字符 “-” 只能以缩写的形式指定命令行开关的指,但是 “--” 则支持全称和缩写形式。

 

Arguments

Switch Mapping

/architecture x64 /runtime coreclr

-

--architecture x64 --runtime coreclr

-

architecture=x64 runtime=coreclr

-

--a x64 --r coreclr

--a: architecture, --r: runtime

-a x64 -r coreclr

-a: architecture, -r: runtime

 

原始的命令行参数总是体现为一个字符串数组, CommandLineConfigurationSource以字符串数组作为配置源,并利用对应的ConfigurationProvider将它转换成配置字典。如下面的代码片断所示,CommandLineConfigurationSource具有Args和SwitchMappings,前者正式代表承载着原始命令行参数的字符串数组,后者则保存了命令行开关的缩写与全称之间的映射关系。在实现的Build方法中,它根据这两个属性创建出一个CommandLineConfigurationProvider对象。

   1: public class CommandLineConfigurationSource : IConfigurationSource
   2: {
   3:     public IEnumerable<string>         Args { get; set; }
   4:     public IDictionary<string, string>     SwitchMappings { get; set; }
   5:  
   6:     public IConfigurationProvider Build(IConfigurationBuilder builder)
   7:     {
   8:         return new CommandLineConfigurationProvider(this.Args, this.SwitchMappings);
   9:     }   
  10: }

具有如下定义的CommandLineConfigurationProvider依然是抽象类ConfigurationProvider的继承者。它的目的很明确,就是对体现为字符串数组的原始命令行参数进行解析,并将解析出来参数名称和值添加到配置字典中 。这一切都是在重写的Load方法中完成的。

   1: public class CommandLineConfigurationProvider : ConfigurationProvider
   2: {
   3:     protected IEnumerable<string> Args { get; }
   4:     public CommandLineConfigurationProvider(IEnumerable<string> args, IDictionary<string, string> switchMappings = null);
   5:     public override void Load();
   6: }

在采用基于命令行参数作为配置源的时候,我们可以创建一个CommandLineConfigurationSource并将其注册到ConfigurationBuilder之上。我们也可以调用IConfigurationBuilder接口的如下两个扩展方法AddCommandLine将两个步骤合二为一。

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

为了让读者朋友们对CommandLineConfigurationProvider解析命令行参数采用的策略具有一个深刻的认识,我们来演示一个简单的实例。我们创建一个控制台应用,并添加针对 “Microsoft.Extensions.Configuration.CommandLine”这个NuGet包的依赖。在Main方法中,我们编写了如下一段简单的实例程序。

   1: while (true)
   2: {
   3:     try
   4:     {
   5:         Console.Write("Enter command line switches:");
   6:         string arguments = Console.ReadLine();
   7:         Dictionary<string, string> mapping = new Dictionary<string, string>
   8:         {
   9:             ["--a"]     = "architecture ",
  10:             ["-a"]     = "architecture ",
  11:             ["--r"]     = "runtime",
  12:             ["-r"]     = "runtime",
  13:         };
  14:         IConfiguration config = new ConfigurationBuilder()
  15:             .AddCommandLine(arguments.Split(' '), mapping)
  16:             .Build();
  17:  
  18:         foreach (var section in config.GetChildren())
  19:         {
  20:             Console.WriteLine($"{section.Key}: {section.Value}");
  21:         }
  22:     }
  23:     catch(Exception ex)
  24:     {
  25:         Console.WriteLine(ex.Message);
  26:     }
  27: }

As shown in the above code fragment, we have an infinite loop receiving user-specified command line parameters, and accordingly creates a CommandLineConfigurationSource object and register it on ConfigurationBuilder. We created this CommandLineConfigurationSource object when the dictionary also specifies a mapping between command line switch. Next we use this ConfigurationBuilder generate a Configuration object and print out all of its sub-configuration sections of Key and Value. We run the program described above were used in five ways a command line parameter based on the output results, shown below, parses the command line will find resulting configuration parameters are equivalent.

image

 

Guess you like

Origin www.cnblogs.com/webenh/p/11589943.html