ASP.NET 5 & MVC6 Series (5): Configuration Information Management

ASP.NET 5 & MVC6 Series (5): Configuration Information Management

In the previous chapter, we know that the new version of the MVC program abandoned the original web.config file mechanism and replaced it with config.json. Today we will take a deep look at the relevant contents of the configuration file.

Basic Usage

The new version of the configuration information mechanism has been rewritten in the Microsoft.Framework.ConfigurationModel namespace. After the rewrite, it not only supports XML format, but also supports json, ini, environment variables, etc. In the constructor of the Startup class in the template sample program, there are the following statements:

  1. // Setup configuration sources.  
  2. Configuration = new Configuration()
  3. .AddJsonFile( "config.json" )
  4. .AddEnvironmentVariables();

The purpose of this statement is to add the config.json file and environment variable information to the configuration information container for reading. When reading, you can use the collection index or Get method to read, as shown below:

  1. var path = Configuration ["Path"];
  2. var path = Configuration .Get("Path");

To read multi-level keys, you need to separate the multiple level names with colons, as shown below:

  1. var connString = Configuration.Get( "Data:DefaultConnection:ConnectionString" );

From the above code snippets, we can see that this configuration example is not a global instance, so if we want to read this information elsewhere, we need to save the instance in a global static variable.

Architecture Design

The new configuration information processing mechanism, after being rewritten, is more lightweight and cross-platform. It can obtain configuration information from multiple data sources without being restricted to .config files, and can even set different configuration information for different environments (development, testing, production). The important entities of the entire configuration mechanism are shown in the figure below:

Let's talk about the specific functions of these classes one by one:

1.IConfiguration - instance interface of configuration information. The indexer, Get, TryGet, Set and other methods like Reload on this interface are used together to obtain key/value based configuration information.

2.IConfigurationSource - This interface unifies the interface methods used by various configuration sources, such as TryGet, Set, and the most important load method for reading configuration information, so as to load the information into the configuration subsystem.

3.IConfigurationSourceContainer - a container for all configuration source information, which enables configuration information from various configuration sources to be loaded on a single Configuration instance. This interface has only one Add method for adding configuration source information based on IConfigurationSource.

4.Configuration - This class implements the IConfiguration interface and the IConfigurationSourceContainer interface and does not save all types of configuration information based on key/value.

5.ConfigurationExtensions - Extension methods used to quickly load configuration information, such as AddCommandLine, AddIniFile, etc.

In the Microsoft.Framework.ConfigurationModel namespace, there are currently 6 different types of configuration source types available, as follows:

1.MemoryConfigurationSource - This configuration source currently has no built-in add/load extension methods (such as AddMemoryConfiguration), but you can load key/value type collections for this purpose (such as IEnumerable

2.IniFileConfigurationSource - This configuration source can load INI file configuration information based on key/value format into the configuration system.

3. CommandLineConfigurationSource - loads the command line parameter information when the program is started into the configuration system.

4. EnvironmentVariablesConfigurationSource - Loads the operating system's environment variable information into the configuration system. In Azure Website, environment variables can be set through the web interface, which makes management quite convenient.

5.JsonConfigurationSource - loads the information of the json file into the configuration system.

6.XmlconfigurationSource - loads information from xml files into the configuration system.

Detailed usage

First, since the configuration system is multi-instance, you must declare an instance before each use. The code is as follows:

  1. IConfiguration configuration = new Configuration();
  2.  
  3. Add MemoryConfigurationSource
  4.  
  5. Since there is no extension method for quickly loading configuration information for MemoryConfigurationSource defined on IConfigurationSourceContainer, if you want to load this type of configuration information, you need to add it in the following form:
  6.  
  7. ((IConfigurationSourceContainer)Configuration)
  8. .Add( new MemoryConfigurationSource(
  9. new List

Add IniFileConfigurationSource

The configuration information of the IniFileConfigurationSource type can be loaded through the extension method. The code is as follows:

  1. var configuration = new Configuration().AddIniFile( "path\\to\\your\\configuration-ini-file.ini" );

The format template of the ini file is as follows:

  1. [ini-sec]
  2. ini-key1=value-a
  3. ini-key2=value-b
  4. [ini-sec2]
  5. ini-key1=value-c
  6. ini-key2=value-d

Here [ini-sec] is a custom configuration section name. Multiple key/value items can be configured under each configuration section. The value selection method is the same as in the basic example. The levels (in this case, between the configuration section and the key) should be separated by colons. The example is as follows:

  1. var someConfiguration1 = Configuration[ "ini-sec:ini-key1" ];
  2. var someConfiguration2 = Configuration.Get( "ini-sec2:ini-key2" );

Add CommandLineConfigurationSource

The parameters passed in when the program uses the k run command can be read through the configuration source, or you can add them manually through the AddCommandLine extension method, as shown below:

  1. var configuration = new Configuration().AddCommandLine( new string[] { "key1=value1" , "key2=value2" , "@key3=value3" });

Each string in the above example must be in key/value format, and special symbols such as $, /, etc. can be used. For these key values, you can also use the CommandLineConfigurationSource class with a switchMappings parameter constructor to map certain keys. The data type and example of the switchMappings parameter are as follows:

  1. var mappings = new Dictionary

Since there is currently no extension method for the CommandLineConfigurationSource class, we still need to instantiate the class ourselves and add it to the configuration container. The code is as follows:

  1. ((IConfigurationSourceContainer)Configuration).Add( new CommandLineConfigurationSource(commandLineArguments, switchMappings: mappings));

After executing the above code, when getting the configuration value, the values ​​of the following two keys are the same:

  1. var value1 = Configuration.Get( "key1" );
  2. var value2 = Configuration[ "tom1" ]; // The value of the key tom1 is actually the value of key1, because tom1 is a mapping of key1  

When mapping, the new mapping key string cannot contain the "/" character, otherwise an exception will be reported.

The same key cannot be passed twice, otherwise an exception will be reported.

When loading configuration information, if there is a duplicate key, the value of the latter key will overwrite the value of the previous key.

When loading CommandLine configuration information, if a key string is prefixed with -, then switchMapping must be used to map a new key to the old key, otherwise an error will occur.

Add EnvironmentVariablesConfigurationSource

IronmentVariablesConfigurationSource can add operating system environment variables to the configuration system. You can also customize these environment variables. For example, when developing and debugging in VS, you can add some key/value in the following interface:

The value is as follows:

  1. var someConfiguration1 = Configuration[ "env_var_key1" ];
  2. var someConfiguration2 = Configuration[ "env_var_key2" ];

In addition, the configuration source also supports Azure environment variables and connection strings, so you can also set MSSQL, MYSQL, and custom connection strings in the Azure interface, but these connection strings need to start with the following strings:

  1. 1.MySQL => MYSQLCONNSTR_
  2.  
  3. 2. MS SQL => SQLCONNSTR_
  4.  
  5. 3.SQL Azure DB => SQLAZURECONNSTR_
  6.  
  7. 4.Custom DB => CUSTOMCONNSTR_

For example, the key/value pairs for defining a development environment are as follows:

  1. Key => SQLCONNSTR_devlocal
  2. Value => Server=localhost;Database=test_db;Trusted_Connection=True;

After loading the information through AddEnvirnmentVariables(), we can access this information in the following way:

  1. var connString = Configuration[ "Data:devlocal:ConnectionString" ];

That is to say, in Azure, the environment variable key will be converted into the format of Data: custom identifier: ConnectionString. If your key is not a custom key (starting with CUSTOMCONNSTR_), you can get the provider name of the connection string as follows:

  1. var providerName = Configuration[ "Data:devlocal:ProviderName" ];
  2. /// Returns: System.Data.SqlClient  
  3.  
  4. EnvironmentVariablesConfigurationSource

In addition, a prefix filtering method is provided to load some information, such as:

  1. ((IConfigurationSourceContainer)Configuration).Add( new EnvironmentVariablesConfigurationSource( "Data:" ));

In this way, when getting information again, the Data: in the key value can be omitted, as shown in the following example:

  1. var conn1 = Configuration[ "devlocal:ConnectionString" ];
  2. var conn2 = Configuration[ "devlocal:ProviderName" ];

Add JsonConfigurationSource

At the beginning of the article, we saw the loading of the json configuration file. To load the file, you only need to use the .AddJsonFile("test.json") extension method, but don't forget to reference the Microsoft.Framework.ConfigurationModel.Json assembly in the dependencies of project.json first.

For example, if your config.json file contains the following:

{
    "Data": {
        "DefaultConnection": {
            "ConnectionString": "Server=(localdb)\\mssqllocaldb;Database=aspnet5-WebApplication1-64357659-de50-4b1e-b005-30310e7ee1ef;Trusted_Connection=True;MultipleActiveResultSets=true"
        }
    },
    "EntityFramework": {
        "ApplicationDbContext": {
            "ConnectionString": "Data:DefaultConnection:ConnectionString"
        }
    }
}

Then you can access the connection string as follows:

  1. var conn = Configuration[ "Data:DefaultConnection:ConnectionString" ];

Adding XmlConfigurationSource

The XmlconfigurationSource configuration source is similar to the JsonConfigurationSource configuration source. First, reference the Microsoft.Framework.ConfigurationModel.Xml assembly, and then call .AddXmlFile("test.xml").

If the content of your configuration file test.xml is as follows:

  1. < root >  
  2. < key1 > Jsinh </ key1 >  
  3. < key2   subkey2 = "Hello world"   />  
  4. </ root >  

The acquisition form is slightly different (the root node will be ignored):

  1. var s1 = Configuration[ "key1" ]; // Returns Jsinh  
  2. var s2 = Configuration[ "key2:subkey2" ]; // Return Hello world  

However, please note that common keys cannot be declared repeatedly, otherwise errors will occur when reading the following files.

  1. < root >  
  2. < key1 > Jsinh </ key1 >  
  3. < key2   subkey2 = "Hello world"   />  
  4. < key2   subkey2 = "Hello world again"   />  
  5. </ root >  

Sensitive information configuration (new feature in RC version)

After the release of the RC version, Microsoft has added a new sensitive information configuration implementation, the assembly is Microsoft.Framework.ConfigurationModel.UserSecrets. Through the management of this assembly, we can put sensitive configuration information in the secrets.json file in a special directory of the computer. The directory definition rules are as follows:

Windows: %APPDATA%\microsoft\UserSecrets\\secrets.json Linux: ~/.microsoft/usersecrets/\secrets.json Mac: ~/.microsoft/usersecrets/\secrets.json

Let's take an example. First, right-click the solution and select Manage User Secret. VS will automatically create an applicationId for the program and save it in the project.json file. The example is as follows:

  1. {
  2. "userSecretsId" : "aspnet5-WebDemo01-20150430014447" ,
  3. "webroot" : "wwwroot" ,
  4. "version" : "1.0.0-*" ,
  5. }
  6.  
  7.   

Then the %APPDATA%\Microsoft\UserSecrets\aspnet5-WebDemo01-20150430014447\secrets.json file will be automatically opened. We enter a sample configuration:

  1. {
  2. "AA": {
  3. "BB": "CC"
  4. }
  5. }

Then, we referenced the above assembly in the project.json file, and registered it in a unified way through the configuration file. The code is as follows:

  1. Configuration = new Configuration()
  2. .AddJsonFile( "config.json" )
  3. .AddEnvironmentVariables()
  4. .AddUserSecrets(); // AddUserSecrets is an extension method for adding sensitive information  

Then you can call it like a normal calling method, as shown below:

  1. var data = Configuration[ "AA:BB" ]; // Result: CC  

In this way, we can keep the configuration information of the production environment in a private location.

Custom configuration source

Through the above examples and looking at its architectural design mechanism, we can find that we can actually customize our own configuration source. For example, if I want to read the corresponding configuration information from the database, we only need to define a DBConfigurationSource and inherit from ConfigurationSource to implement the corresponding Load overload.

  1.      public   class DBConfigurationSource : BaseConfigurationSource
  2.       
  3. public   class DBConfigurationSource : BaseConfigurationSource
  4. {
  5. public override void Load()
  6. {
  7. // Read all key/value pairs from the database and assign them to IDictionary  
  8.  
  9. If you do not store the data in the Data property, you must also implement the following overloads to get the response value from your own private data collection, such as from the cache. The example is as follows:
  10.  
  11. public   class DBConfigurationSource : BaseConfigurationSource
  12. {
  13. public override void Load()
  14. {
  15. // Read all key/value pairs from the database and save them in the private variable _data  
  16. }
  17.       
  18. public override void Set(string key, string value)
  19. {
  20. // Update the value corresponding to the database key  
  21. // base.Set(key, value);  
  22. }
  23.       
  24. public override bool TryGet(string key, out string value)
  25. {
  26. // Get the value corresponding to the key from the private variable _data  
  27. // return base.TryGet(key, out value);  
  28. }
  29.       
  30. public override IEnumerable ProduceSubKeys(IEnumerable earlierKeys, string prefix, string delimiter) { // In the private variable _data, return the corresponding SubKeys according to its own mechanism  
  31.  
  32. // return base.ProduceSubKeys(earlierKeys, prefix, delimiter); } }  

After implementing the above class, create an extension method for yourself to add DB configuration information. The code is as follows

  1. public   static   class CatsConfigurationExtensions
  2. {
  3. public   static IConfigurationSourceContainer AddDBConfiguration( this IConfigurationSourceContainer configuration)
  4. {
  5. configuration.Add( new DBConfigurationSource());
  6. return configuration;
  7. }
  8. }

You can add the DB configuration source through .AddDBConfiguration().

Note that the DB configuration source needs to use the database connection string. This needs attention (you can first obtain the connection string from the json configuration file and then add the configuration source).

Configuration information traversal

In the default configuration source implementation, all classes inherit from ConfigurationSource and store information data in the Data property. Therefore, if you want to traverse this data, you need to convert it to the ConfigurationSource type before you can use it. The sample code is as follows:

  1. foreach (var o in Configuration as Configuration)
  2. {
  3. var source = o as ConfigurationSource;
  4. foreach (var key in source.Data.Keys)
  5. {
  6. Console.WriteLine(key + ":" + source.Data[key]);
  7. }
  8. }

Configuration information is directly converted into entity classes

There is also an extension method on the IServiceCollection interface.Configure The data of type IConfiguration can be converted into an entity class. The definition of the extension method is as follows:

public static IServiceCollection Configure (this IServiceCollection services, IConfiguration config, int order = -1000, string optionsName = "");

For example, if we define the following entity:


  1. public class AppSettings
  2. {
  3. public string SiteTitle { get; set; }
  4. }
  5.  
  6.   
  7.  
  8. Then define a configuration information with the same structure in config.json, as shown below:
  9.  
  10. {
  11. "AppSettings" : {
  12. "SiteTitle" : "WebDemo01"  
  13. }
  14. }

Then, after loading the configuration information in the Startup constructor, we can assign the information to the AppSettings instance. The code is as follows:

  1. services.Configure(Configuration.GetSubKey( "AppSettings" ));

When using, use the GetRequiredService method of ApplicationServices, as shown below:

  1. var appSettings = app.ApplicationServices.GetRequiredService

Note:

In the configuration information, all keys are case-insensitive, that is, key and KEY are the same.

If multiple configuration sources have duplicate keys, the value corresponding to the key in the configuration source added later will prevail.

GetSubKeys and GetSubKey under IConfiguration can get a list of all keys at a certain level (or starting with a certain level).

Since Configuration is multi-instance, according to the code in the example, after the instance is initialized in Startup, other classes cannot access it. Therefore, if you want to access it globally, you should save it to a static variable after initialization.

Reference 1: https://github.com/aspnet/Configuration

Reference 2: http://blog.jsinh.in/asp-net-5-configuration-microsoft-framework-configurationmodel/#.VSdjUpOxxzw

<<:  Interpreting ASP.NET 5 & MVC6 Series (4): Core Technology and Environment Configuration

>>:  Interpreting ASP.NET 5 & MVC6 Series (8): Session and Caching

Recommend

I have a runny nose and tears in spring. Is it a cold or allergic rhinitis?

In spring, flowers bloom in abundance, bringing p...

Can ordinary people go into space and see the universe?

With a deafening roar, the rocket took off, and t...

TalkingData's third anniversary brand strategy conference was held in Beijing

Mobility changes tradition, data changes the futu...

How early was the earliest hot pot? Much earlier than Yao, Shun and Yu!

Frost has passed, is the beginning of winter far ...

Introduction to Guangdiantong advertising features and backend operations!

Because the background operations are too complic...

The stock market is falling. Are you, a startup, ready for the winter?

[[146861]] As global stock markets tumble, shareh...

A must-read for APP promotion, complete promotion data analysis in 3 steps!

When I was reporting business dynamics to the bos...

How to motivate users to participate in activities?

I believe that many friends will be troubled by t...

Hamburger button transition animation implemented in Swift

Source code introduction: A beautiful hamburger b...