Referring to the word "configuration", I think most of it. NET developers will immediately appear in the mind of two special files, that we are familiar with the app.config and web.config, over the years we have been accustomed to the structure of the configuration information defined in these two files. By the time we got to. NET core, many of the things we used to have changed, including the way we defined configurations. Overall, the new configuration system is lighter and more scalable, and its biggest feature is its support for diverse data sources. We can use memory variables as configuration data sources, or directly configure definitions in persisted files or even databases.
Since a lot of people have never been in touch with this new design configuration system, in order to let people have a sense of this, we first from the point of view of the programming of the initial experience. The API for configuration involves three objects, respectively configuration, Configurationbuilder, and Configurationprovider, which are represented by the corresponding interfaces in the configuration model. The relationship between these three objects is clear, the configuration object hosts the configuration information that is used during the programming process, and Configurationprovider is the provider of the original data source for the configuration information. Communication between the two is done by Configurationbuilder, which uses Configurationprovider to extract the source data and convert it to configuration objects.
Read the configuration as a key-value pair
Although in most cases the configuration information has a structured hierarchical relationship on the whole, but "atomic" configuration items are represented in the simplest form of "key-value pairs", and the keys and values are strings, and then we'll show you how to read the configuration in the form of key-value pairs, using a simple example. We created a console application for ASP.net core and added a dependency to the NuGet package for "Microsoft.Extensions.Configuration" in Project.json as follows. The configuration model is implemented in this package.
{
...
" Dependencies ": {" Microsoft.Extensions.Configuration ":"
1.0.0-rc1-final "
},
}
Suppose our application needs to be configured to set the date/time display format, for which we define a Datetimeformatsettings class whose four properties reflect the four display formats for DateTime objects (long date/time and short Date/time, respectively).
public class Datetimeformatsettings
{public
string Longdatepattern {get; set;}
public string Longtimepattern {get; set;}
public string ShortDatePattern {get; set;}
public string Shorttimepattern {get; set;}
Other members
}
We want to control the date/time display format represented by the four attributes of datetimeformatsettings by configuration, so we define a constructor for it. As shown in the following code fragment, the constructor has a IConfiguration interface type parameter that formally hosts the configuration object for the related configuration information. We call the index of the configuration object and specify the key of the corresponding configuration item to get its value.
public class Datetimeformatsettings
{
//other member public
datetimeformatsettings (iconfiguration Configuration)
{this
. Longdatepattern = configuration["Longdatepattern"];
This. Longtimepattern = configuration["Longtimepattern"];
This. ShortDatePattern = configuration["ShortDatePattern"];
This. Shorttimepattern = configuration["Shorttimepattern"];
}
To create a Datetimeformatsettings object that embodies the current configuration, we have to get the configuration object that hosts the relevant configuration information. As we said above, the configuration object is created by Configurationbuilder, and the original configuration information is read by the corresponding configurationprovider. So the correct way to programmatically create a configuration object is to create a Configurationbuilder object and then add one or more Configurationprovider objects to it. Finally, we use Configurationbuilder to create the configuration object we need.
In accordance with the above programming pattern, we have written the following program in a console application. We created an object of type Configurationbuilder, and the Configurationprovider called by its Add method is an object of type Memoryconfigurationprovider. As the name suggests, Memoryconfigurationprovider uses objects in memory to provide the raw configuration information, specifically these raw configuration information is stored in an element type of keyvaluepair<string, string> In the collection. We end up calling the Configurationbuilder build method to get the configuration needed to create the Datetimeformatsettings object.
public class Program {public static void Main (string[] args) {diction ary<string, string> Source = new dictionary<string, string> {["longdatepattern"] = "dddd, MMM M d, yyyy ", [" longtimepattern "] =" H:mm:ss tt ", [" shortdatepattern "] =" m/d/yyyy ", [" SHORTTIMEP
Attern "] =" h:mm tt "}; IConfiguration configuration = new Configurationbuilder (). ADD (new Memoryconfigurationprovider (source)).
Build ();
Datetimeformatsettings settings = new datetimeformatsettings (configuration); Console.WriteLine ("{0,-16}: {1}", "Longdatepattern", settings.)
Longdatepattern); Console.WriteLine ("{0,-16}: {1}", "Longtimepattern", settings.)
Longtimepattern); Console.WriteLine ("{0,-16}: {1}", "ShortDatePattern", settings.)
ShortDatePattern); Console.WriteLine ("{0,-16}: {1}", "Shorttimepattern", settings.)
Shorttimepattern); }
}
To verify the relationship between the Datetimeformatsettings object created from the configuration and the configuration raw data, we export its four properties to the console. When this program is executed, the output shown below will be generated on the console, which shows that it is the true reflection of the configuration we provide.
LONGDATEPATTERN:DDDD, MMMM D, yyyy
LONGTIMEPATTERN:H:MM:SS TT
Shortdatepattern:m/d/yyyy
SHORTTIMEPATTERN:H:MM TT
Second, read the structured configuration
most of the configurations involved in a real project have a structured hierarchy, so the configuration object in the configuration model has the same structure. A structured configuration has a tree hierarchy, and a configuration object represents a node that makes up the configuration tree, which can be represented by the configuration object as the root node. The atomic configuration items that are embodied as key-value pairs generally go to the configuration object that exists as a leaf node, and the configuration of the non-leaf node contains a set of child nodes, each of which is also a configuration object.
Next, we also illustrate how to define and read configurations that have a hierarchical structure, in the same way as examples. We're still using the previous scenario, and now we need to not only format the date/time, but also format other data types, such as the decimal type that represents the currency. For this we have defined a currencydecimalformatsettings class whose properties digits and symbol represent decimal digits and currency symbols, respectively. A Currencydecimalformatsettings object is still created using a configuration object that represents the configuration.
{public
int Digits {get; set;}
public string Symbol {get; set;}
Public currencydecimalformatsettings (iconfiguration configuration)
{this
. Digits = Int. Parse (configuration["Digits"]);
This. Symbol = configuration["symbol"]
We have defined another type named Formatsettings to represent formatting for different data types. As shown in the following code fragment, its two property datetime and currencydecimal represent formatting for date/time and currency numbers, respectively. Formatsettings still has a constructor with a parameter type of IConfiguration interface, and its two properties are initialized in this constructor. It is noteworthy that the initialization of these two properties takes the current configuration "Child configuration section", which is obtained by calling the GetSection method by specifying the configuration section name.
public class Formatsettings
{public
datetimeformatsettings DateTime {get; set;}
Public currencydecimalformatsettings Currencydecimal {get; set;}
Public formatsettings (iconfiguration configuration)
{this
. DateTime = new Datetimeformatsettings (configuration. GetSection ("DateTime"));
This. Currencydecimal = new Currencydecimalformatsettings (configuration. GetSection ("Currencydecimal"));
}
In the example we demonstrated above, we provide the original configuration information by using a Memoryconfigurationprovider object. Because the raw configuration information is hosted by a collection of element types Keyvaluepair<string and string>, the original configuration does not have a tree-structured hierarchy on physical storage. So how can it ultimately provide a structured configuration object? In fact, although the Memoryconfigurationprovider object can only store configuration information as a simple "data dictionary", if the path represented by the configuration object in the configuration tree is a key, The data dictionary logically actually has the structure of a tree. This is actually what Memoryconfigurationprovider is doing, which is embodied in the procedure we see below.
Class Program {static void Main (string[] args) {dictionary<string, string> Source = new Dictionary< ; string, string> {["Format:DateTime:LongDatePattern"] = "dddd, MMMM D, yyyy", [format:datetime:l Ongtimepattern "] =" H:mm:ss tt ", [" Format:DateTime:ShortDatePattern "] =" m/d/yyyy ", [" Format:DateTime:Sh Orttimepattern "] =" h:mm tt ", [" Format:CurrencyDecimal:Digits "] =" 2 ", [" Format:CurrencyDecimal:Symbol
"] = "$",
}; IConfiguration configuration = new Configurationbuilder (). ADD (new Memoryconfigurationprovider (source)).
Build (); Formatsettings settings = new Formatsettings (configuration.
GetSection ("Format"));
Console.WriteLine ("DateTime:"); Console.WriteLine ("\t{0,-16}: {1}", "Longdatepattern", settings.
Datetime.longdatepattern); Console.WriteLine ("\t{0,-16}: {1}", "Longtimepattern", settings.
Datetime.longtimepattern); Console.WriteLine ("\t{0,-16}: {1} "," ShortDatePattern ", settings.
Datetime.shortdatepattern); Console.WriteLine ("\t{0,-16}: {1}\n", "Shorttimepattern", settings.
Datetime.shorttimepattern);
Console.WriteLine ("Currencydecimal:"); Console.WriteLine ("\t{0,-16}: {1}", "Digits", settings.
Currencydecimal.digits); Console.WriteLine ("\t{0,-16}: {1}", "Symbol", settings.
Currencydecimal.symbol); }
}
As shown in the preceding code fragment, the Dictionary object used to create the Memoryconfigurationprovider object contains 6 basic configuration items, so that they logically have a tree-structured hierarchy. So the key actually represents the path of the configuration section in the configuration tree where each configuration item resides, and the path is split by a colon (":"). After the program is executed, the output shown below will be rendered on the console.
DateTime:
longdatepattern:dddd, MMMM D, yyyy
LONGTIMEPATTERN:H:MM:SS tt
shortdatepattern:m/d/yyyy
shorttimepattern:h:mm tt
currencydecimal:
Digits : 2
Symbol : $
To bind a structured configuration directly to an object
in the real project development process, we will not directly use the direct read configuration, and are inclined to like the two examples we demonstrated by creating the appropriate type (such as Datetimeformatsettings, Currencydecimalsettings and Formatsettings) to define a set of related configuration options (option), we will define these types of configuration options (option) as option types. In the example shown above, in order to create the objects of these encapsulated configurations, we are all in the form of manual read configuration, and if too many of the configuration items are defined, it is a tedious task to read the configuration items.
For an object, if we treat its properties as its child nodes, an object also has a tree-like hierarchical structure similar to the configuration object. If we define the configuration according to the structure of an option type, or in turn define the option type according to the configuration structure, then the property member of the option type will have a one by one correspondence with a configuration section. So in principle we can automatically bind the configuration information to a specific option object.
The asp.net core option model for configuration (Optionmodel) helps us implement bindings from configuration to option objects, and we'll do a simple demo of that. Option model implementation in the "Microsoft.Extensions.OptionModel" NuGet package, in addition, we need to rely on injection method to use the option model, so we need to follow the following way to add to the application for the appropriate dependencies.
{
...
" Dependencies ": {"
Microsoft.Extensions.OptionsModel " :" 1.0.0-rc1-final ",
" Microsoft.Extensions.DependencyInjection " :" 1.0.0-rc1-final "
},
}
With the automatic binding mechanism of the option model, we do not need to manually read the configuration information, so we remove the formatsettings, datetimeformatsettings, and currencydecimalsettings constructors. Only its property members are retained. In the main method as a program entry, we create this Formatsettings object that represents the formatting in the following way.
Class Program {static void Main (string[] args) {dictionary<string, string> Source = new Dictionary< ; string, string> {["Format:DateTime:LongDatePattern"] = "dddd, MMMM D, yyyy", [Format:DateTime:LongT Imepattern "] =" H:mm:ss tt ", [" Format:DateTime:ShortDatePattern "] =" m/d/yyyy ", [" Format:DateTime:ShortTimePa
Ttern "] =" h:mm tt ", [" Format:CurrencyDecimal:Digits "] =" 2 ", [" Format:CurrencyDecimal:Symbol "] =" $ ",
}; IConfiguration configuration = new Configurationbuilder (). ADD (new Memoryconfigurationprovider (source)). Build ().
GetSection ("Format")); ioptions<formatsettings> optionsaccessor = new Servicecollection (). AddOptions (). Configure<formatsettings> (Configuration). Buildserviceprovider ().
Getservice<ioptions<formatsettings>> ();
formatsettings settings = Optionsaccessor.value;
Console.WriteLine ("DateTime:"); Console.WriteLine ("\t{0,-16}: {1}", "Longdatepattern", settings.
Datetime.longdatepattern); Console.WriteLine ("\t{0,-16}: {1}", "Longtimepattern", settings.
Datetime.longtimepattern); Console.WriteLine ("\t{0,-16}: {1}", "ShortDatePattern", settings.
Datetime.shortdatepattern); Console.WriteLine ("\t{0,-16}: {1}\n", "Shorttimepattern", settings.
Datetime.shorttimepattern);
Console.WriteLine ("Currencydecimal:"); Console.WriteLine ("\t{0,-16}: {1}", "Digits", settings.
Currencydecimal.digits); Console.WriteLine ("\t{0,-16}: {1}", "Symbol", settings.
Currencydecimal.symbol);
}
}
As shown in the code snippet above, we create a Servicecollection object and invoke the extension method AddOptions register the service for the option model. Next we call the Configure method to map the option type formatsettings with the corresponding configuration object. We end up using this Servicecollection object to generate a serviceprovider and call its GetService method to get an object of type ioptions<formatsettings>, The Value property of the latter returns the Formatsettings object that is bound to the associated configuration.
The above is the entire content of this article, I hope to help you learn.