Talk about the various configuration sources supported by default [memory variables, environment variables, and command-line parameters]
Compared to the traditional configuration system hosted by the two XML files of app. Config and Web. config, the most important advantage of this new configuration model for. NET Core is support for a variety of different configuration sources. We can use memory variables, command line arguments, environment variables, and physical files as sources of raw configuration data, and if we use physical files as configuration sources, we can choose different formats (such as XML, JSON, INI, etc.). If these default supported configuration sources do not meet your needs, we can also use other forms of data as our source of configuration by registering a custom configurationsource. [This article has been synced to the "ASP. NET Core Framework"]
Directory
One, memory variables
Second, environment variables
Three, command-line parameters
One, memory variables
All of our example demos have been using Memoryconfigurationsource this type of Configurationsource to provide the original configuration from the beginning of the first chapter of the series to the present. We know that Memoryconfigurationsource takes a Dictionary object (specifically a collection of element types Keyvaluepair<string, string>) as a container for storing the original configuration data. As a configurationsource, it always works by creating a corresponding configurationprovider to perform specific reading of the configuration data. So what kind of configurationprovider would memoryconfigurationsource offer?
1:public class Memoryconfigurationsource:iconfigurationsource
2: {
3: Public ienumerable<keyvaluepair<string, string>> initialdata {get; set;}
5: Public iconfigurationprovider Build (iconfigurationbuilder builder)
6: {
7: return new Memoryconfigurationprovider (this);
8: }
9:}
The code snippet given above embodies the complete definition of memoryconfigurationsource, and we can see that it has a ienumerable<keyvaluepair<string, string>> The Initialdata property of the type to hold the initial configuration data. From the implementation of the build method, it can be seen that the object that is actually used to read the original configuration data is a Memoryconfigurationprovider type, which is defined as shown 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 you can see from the code snippet above, Memoryconfigurationprovider derives from the abstract class Configurationprovider and also implements the ienumerable<keyvaluepair< String, string>> interface. We know that Configurationprovider directly uses a dictionary<string, string> to save the configuration data, When we create a memoryconfigurationprovider based on a Memoryconfigurationsource object call constructor, It only needs to transfer the configuration data saved through the Initiatedata property to this dictionary. Memoryconfigurationprovider also defines an Add method that allows us to add a new configuration item to the configuration dictionary at any time.
With the introduction of the front-facing configuration model, we know that the role of Configurationprovider in the configuration model is to read the original configuration data and convert it into a configuration dictionary. Of all the predefined configurationprovider types, Memoryconfigurationprovider is the simplest and most straightforward, because its corresponding configuration source is a configuration dictionary, so there is no need for any structural transformations at all.
When using Memoryconfigurationsource to build the configuration, we need to register it on Configurationbuilder. Specifically, we can call Configurationbuilder's Add method directly, as in the example shown earlier, or call the extension method Addinmemorycollection, which is two overloads, like the one below.
1:public static Iconfigurationbuilder addinmemorycollection (this iconfigurationbuilder configurationbuilder);
2:public static Iconfigurationbuilder addinmemorycollection (this iconfigurationbuilder configurationbuilder, Ienumerable<keyvaluepair<string, string>> initialdata);
Second, environment variables
As the name implies, an environment variable is a variable that describes the current execution environment and affects the execution behavior of the process. Depending on the scope, we divide the environment variables into three categories, that is, the environment variables for the current system, the current user, and the current process, respectively. System and user-level environment variables are saved in the registry with the path "hkey_local_machine\system\controlset001\control\session manager\environment "and"hkey_current_user\environment".
environment variable extraction and maintenance can be implemented by static type environment. Specifically, we can call its static method GetEnvironmentVariable method to get the value of an environment variable of a given name, and the Getenvironmentvariables method will return all environment variables, The parameters of the EnvironmentVariableTarget enumeration type represent the storage location determined by the scope of the environment variable. If you call getenvironmentvariable or if the Getenvironmentvariables method does not explicitly specify the target parameter or specify the parameter as environmentvariabletarget.process, it exists before the process is initialized. All environment variables, including for the system, current user, and current process, will be used as a candidate list.
1:public Static class environment
2: {
3: Public static string getenvironmentvariable (string variable);
4: Public static string getenvironmentvariable (string variable, environmentvariabletarget target);
6: Public static IDictionary getenvironmentvariables ();
7: Public static IDictionary Getenvironmentvariables (EnvironmentVariableTarget target);
9: Public static void setenvironmentvariable (string variable, string value);
Ten: public static void setenvironmentvariable (string variable, string value, EnvironmentVariableTarget target);
11:}
13:public enum EnvironmentVariableTarget
14: {
: Process,
: User,
: Machine
18:}
The addition, modification, and deletion of environment variables are done by the Setenvironmentvariable method, and by default if the target parameter is not explicitly specified, environmentvariabletarget.process is used. If you want to delete an environment variable of the specified name, we only need to set the value parameter to null or an empty string when calling this method.
In addition to using static type environment in your program, we can also execute the command line to view and set environment variables. In addition, we can also use the System Properties Settings tool to visually view and set the system and user level environment variables ("This PC" > "Properties" > "Change Settings" > "Advanced" > "Environment Variables"). If you use Visual Studio 2015来 to debug an app we've written, we can set the project properties to set the process-level environment variables ("Properties" > "Debug" > "Environment Variables").
The configuration source for the environment variable is represented by the following Environmentvariablesconfigurationsource type defined in the NuGet package " Microsoft.Extensions.Configuration.EnvironmentVariables". This type refers to the attribute prefix, which defines a string type, which represents the prefix used to filter the environment variables, that is, if we set this prefix property, only the environment variable with the name as the prefix is selected.
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:}
With the code snippet given above, we can see that Environmentvariablesconfigurationsource will use the corresponding Environmentvariablesconfigurationprovider to complete the reading of the environment variable. 。 The code shown below basically embodies the definition of environmentvariablesconfigurationprovider. Since the environment variable that is the original configuration data itself is a data dictionary with both key and value as a string, Environmentvariablesconfigurationprovider does not need to be in the process of structural transformation, so when the load method is executed, It only needs to filter the criteria and add them to its own configuration dictionary. It is worth mentioning that if we are creating a Environmentvariablesconfigurationprovider object that specifies the prefix that is used to filter the environment variables, when the qualifying environment variable is added to its own configuration dictionary, This prefix is also removed from the key of the element. This detail is also reflected in the Load method defined above.
1:public class Environmentvariablesconfigurationprovider:configurationprovider
2: {
3: private readonly string prefix;
5: Public environmentvariablesconfigurationprovider (string prefix = null)
6: {
7: this.prefix = prefix?? string. Empty;
8: }
Ten: Public override void Load ()
One: {
: var dictionary = environment.getenvironmentvariables ()
: . Cast<dictionaryentry> ()
: . Where (IT and it. Key.tostring (). StartsWith (prefix, stringcomparison.ordinalignorecase))
: . ToDictionary (IT and it). Key.tostring (). Substring (prefix. Length), it and it. Value.tostring ());
: This . Data = new dictionary<string, string> (Dictionary, stringcomparer.ordinalignorecase);
: }
18:}
When using Environmentvariablesconfigurationsource, we can call the Add method to register it on the specified Configurationbuilder object. Besides Environmentvariablesconfigurationsource registration can also directly call the Iconfigurationbuilder interface of the following two overloaded extension method addenvironmentvariables to complete 。
1:public static Iconfigurationbuilder addenvironmentvariables (this iconfigurationbuilder configurationbuilder);
2:public static Iconfigurationbuilder addenvironmentvariables (this iconfigurationbuilder configurationbuilder, string prefix);
We routinely write a simple example that demonstrates how to use environment variables as a configuration source. As shown in the following code snippet, we call environment's static method Setenvironment method to set four environment variables, and the variable names have the same prefix "Test_". We call the method addenvironmentvariables to create a Environmentvariablesconfigurationsource object and register it on top of the created Configurationbuilder. The call to the Addenvironmentvariables method is that we use the environment variable name prefix "Test_" as the parameter. We are already familiar with the following code, which is to use the options mode to read the environment variable and bind it 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");
6:iconfiguration config = new Configurationbuilder ()
7: . Addenvironmentvariables ("Test_")
8: . Build ();
10:profile profile = new Servicecollection ()
One: . AddOptions ()
A: . configure<profile> (config)
: . Buildserviceprovider ()
: . Getservice<ioptions<profile>> ()
: . Value;
Three, command-line parameters
In many cases, we will host an ASP. NET core application in a managed process, in which case we tend to use the command line to launch the boarding program in a self-host way. When an ASP. NET Core application is launched as a command line, we want to use a named row switch to control some of the behavior of the application, so command-line switches are naturally one of the most common sources of configuration. The configuration model's support for this configuration source is implemented through Commandlineconfigurationsource, which is defined in the NuGet package " Microsoft.Extensions.Configuration.CommandLine "in.
When a command is executed as a command line, command-line switches (including names and values) are represented as a simple collection of strings, so the fundamental purpose of commandlineconfigurationsource is to convert the named row switches from a string array into a configuration dictionary. To fully understand this conversion rule, let's start by knowing exactly what form of command-line switch Commandlineconfigurationsource supports. We use a simple example to illustrate how the command-line switches are centrally specified. Suppose we have a command "exec" and execute a Managed program (APP) in the way shown below.
In executing this command we specify two options with the corresponding command-line switch, one representing the CPU architecture (X86 or X64), and the other representing the runtime type (CLR or coreclr). We named the two command-line switches architecture and runtime respectively. We can specify these two named row switches in the following three different ways when executing a named row.
1:exec app/architecture x64/runtime CoreCLR
2:exec app--architecture x64--runtime coreclr
3:exec app Architecture=x64 ARCHITECTURE=CORECLR
For convenience, many named line switches have an abbreviated form, and the full name and initials of the command-line switch have a mapping relationship (switch Mapping). For the above two command-line switches, for example, we can use the initials "a" and "R" to represent the "architecture" and "runtime" as the full name. If you use the abbreviated command-line switch name, then we can specify the CPU architecture and runtime type in the following two ways.
1:exec app–-a x64–-r CoreCLR
2:exec app-a x64-r CoreCLR
As shown, we have five different ways to specify named line switches, three of which use the full name of the command-line switch, and the remaining two using the abbreviated form of the command-line switch. The following table summarizes the original parameters used for the specified form of the five named switches and the mapping of the abbreviation to the full name. Here is an important detail, the character "-" can only be abbreviated to specify the command-line switch, but "-" support full and abbreviated form.
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 arguments are always represented as an array of strings, Commandlineconfigurationsource a string array as the configuration source, and using the corresponding configurationprovider to convert it into a configuration dictionary. As shown in the following code snippet, Commandlineconfigurationsource has args and switchmappings, which formally represent an array of strings that carry the original command-line arguments, while the latter preserves the mapping between the abbreviation and the full name of the command-line switch. In the implemented build method, it creates a Commandlineconfigurationprovider object based on these two properties.
1:public class Commandlineconfigurationsource:iconfigurationsource
2: {
3: Public ienumerable<string> Args {get; set;}
4: Public idictionary<string, string> switchmappings {get; set;}
6: Public iconfigurationprovider Build (iconfigurationbuilder builder)
7: {
8: return new Commandlineconfigurationprovider (this. Args, this. Switchmappings);
9: }
10:}
Commandlineconfigurationprovider, which has the following definition, remains the successor of the abstract class Configurationprovider. It is very clear that the original command-line arguments that are represented as string arrays are parsed, and the parameter names and values that are parsed are added to the configuration dictionary. All of this is done in the overridden load method.
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 as a configuration source, we can create a commandlineconfigurationsource and register it on Configurationbuilder. We can also call the following two extension methods of the 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);
To give readers a deep understanding of the strategy used by Commandlineconfigurationprovider to parse command-line arguments, let's demonstrate a simple example. We created a console app and added a dependency on this NuGet package for "Microsoft.Extensions.Configuration.CommandLine". In the main method, we have written the following simple example program.
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",
Ten: ["-a"] = "Architecture",
One: ["--r"] = "Runtime",
: ["-r"] = "Runtime",
: };
: iconfiguration config = new Configurationbuilder ()
: . Addcommandline (arguments. Split ("), mapping)
A: . Build ();
: foreach (var section in config.) GetChildren ())
: {
: Console.WriteLine ($ "{section. Key}: {section. Value} ");
: }
: }
At: catch (Exception ex)
: {
: Console.WriteLine (ex. Message);
: }
27:}
As shown in the code snippet above, we receive user-specified command-line arguments in an infinite loop, creating a Commandlineconfigurationsource object and registering it with Configurationbuilder. When we create this Commandlineconfigurationsource object, we also specify a dictionary that represents the command-line switch mapping relationship. Next we use this configurationbuilder to generate a configuration object and print out the key and value of all its child configuration sections. After we run the program, we provide the command line parameters in the above five ways, according to the output results shown below, it is found that parsing command line parameters generated by the configuration is completely equivalent.
Talk about the various configuration sources supported by default [memory variables, environment variables, and command-line parameters]