当前位置: 移动技术网 > IT编程>开发语言>.net > 解读ASP.NET 5 & MVC6系列教程(5):Configuration配置信息管理

解读ASP.NET 5 & MVC6系列教程(5):Configuration配置信息管理

2017年12月12日  | 移动技术网IT编程  | 我要评论

b站网址,坦克油箱内藏金条,mimiqing

在前面的章节中,我们知道新版的mvc程序抛弃了原来的web.config文件机制,取而代替的是config.json,今天我们就来深入研究一下配置文件的相关内容。

基本用法

新版的配置信息机制在microsoft.framework.configurationmodel命名空间下进行了重写,重写以后不仅支持xml格式,还支持json、ini、环境变量等。在模板示例程序中startup类的构造函数内如,有如下语句:

// setup configuration sources.
configuration = new configuration()
 .addjsonfile("config.json")
 .addenvironmentvariables();

该语句的作用是将config.json文件以及环境变量信息加入到配置信息容器里,以便进行读取。而读取的时候则可以通过集合索引的形式或get方法进行读取,示例如下:

var path = configuration["path"];
var path = configuration.get("path");

其中,多层级key键的读取,需要在多个层级名称之间用冒号分割即可,示例如下:

var connstring = configuration.get("data:defaultconnection:connectionstring");

通过上述几段代码可以看出,该配置示例并不是全局实例,所以要想在别的地方也读取这些信息,就需要将该实例保存在一个全局静态变量上。

架构设计

新的配置信息处理机制,在重写以后,更加轻量级,而且是进行跨平台使用,可以从多个数据源获取配置信息,而不必在拘泥于.config文件,而且甚至可以为不同的环境(开发、测试、生产)设置不同的配置信息。整个配置机制的各个重要实体见下图:

http://www.lhsxpumps.com/_images/10qianwan/20171212/b_1_201712121906192116.jpg

我们来一一讲述一下,这些类的具体作用:

1.iconfiguration - 配置信息的实例接口,该接口上的indexergettrygetset以及其它一些像reload这样的方法一起用于获取基于key/value的配置信息。

2.iconfigurationsource - 该接口统一了各个配置源使用时的接口方法,比如trygetset以及最重要的读取配置信息的load方法,以便将信息加载到配置子系统里。

3.iconfigurationsourcecontainer - 所有配置源信息的一个容器,该容器使得可以在一个单独的configuration实例上加载各种配置源的配置信息。该接口只有一个add方法用于添加基于iconfigurationsource的配置源信息。

4.configuration - 该类实现了iconfiguration接口和iconfigurationsourcecontainer接口,不保存基于key/value的所有类型的配置信息。

5.configurationextensions - 扩展方法,用于快速加载配置信息,如addcommandlineaddinifile等。

在microsoft.framework.configurationmodel命名空间下,目前有6种不同类型的配置源类型可以使用,分别如下:

1.memoryconfigurationsource - 该配置源目前没有内置的add/load扩展方法(比如addmemoryconfiguration),但你可以加载key/value类型的集合来实现此目的(如ienumerable<keyvaluepair<string, string>>类型)。

2.inifileconfigurationsource - 该配置源,可以将基于key/value格式的ini文件配置信息加载到配置系统中。

3.commandlineconfigurationsource - 将程序启动时的命令行参数信息加载到配置系统中。

4.environmentvariablesconfigurationsource - 将操作系统的环境变量信息加载到配置系统中,在azure website中,环境变量可以通过web界面进行设置,管理相当方便。

5.jsonconfigurationsource - 将json文件的信息加载配置系统。

6.xmlconfigurationsource - 将xml文件的信息加载到配置系统。

详细用法

首先,由于配置系统是多实例型的,所以每次使用之前都要先声明一个示例,代码如下:

iconfiguration configuration = new configuration();

添加memoryconfigurationsource

由于在iconfigurationsourcecontainer上没有为memoryconfigurationsource定义快速加载配置信息的扩展方法,所以如果想加载这种类型的配置信息,则需要按照如下形式进行添加:

((iconfigurationsourcecontainer)configuration)
 .add(new memoryconfigurationsource(
  new list<keyvaluepair<string, string>> {
  new keyvaluepair<string, string>("mem-key1", "mem-value1"),
  new keyvaluepair<string, string>("mem-key2", "mem-value2")
  }));
//取值方式
var someconfiguration1 = configuration["mem-key1"];
var someconfiguration2 = configuration.get("mem-key2");

添加inifileconfigurationsource

inifileconfigurationsource类型的配置信息可以通过扩展方法进行加载,代码如下:

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

其中ini文件的格式模板如下:

[ini-sec]
ini-key1=value-a
ini-key2=value-b
[ini-sec2]
ini-key1=value-c
ini-key2=value-d

这里的[ini-sec]是自定义的配置节名称,每个配置节下面可以配置多个key/value项。取值方式和基本示例中的一样,层级之间(本例是配置节和key之间)要用冒号分割,示例如下:

var someconfiguration1 = configuration["ini-sec:ini-key1"];
var someconfiguration2 = configuration.get("ini-sec2:ini-key2");

添加commandlineconfigurationsource

在程序使用k run命名进行时传入的参数,可以通过该配置源进行读取,或者你也可以通过addcommandline扩展方法手工添加,示例如下:

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

上述示例中的每个字符串都要是key/value格式,可以使用少于的特殊符号比如$、/等。 针对这些key值,你也可以使用带有switchmappings参数构造函数的commandlineconfigurationsource类来映射某些key,switchmappings参数的数据类型和示例如下:

var mappings = new dictionary<string, string>(stringcomparer.ordinalignorecase)
{
 { "key1", "tom1" },
 { "key2", "tom2" },
};

由于当前没有针对commandlineconfigurationsource类的扩展方法,所以我们还是需要自己实例化该类,并添加到配置容器中,代码如下:

((iconfigurationsourcecontainer)configuration).add(new commandlineconfigurationsource(commandlinearguments, switchmappings: mappings));

执行上述代码以后,在获取配置值的时候,如下两个key的值是一样的:

var value1 = configuration.get("key1");
var value2 = configuration["tom1"]; // tom1这个key的值其实就key1的值,因为tom1是key1的映射

在映射的时候,新的映射key字符串里不能包括“/”字符,否则会报异常同样的key不能传入两次,否则也会报异常加载配置信息时,如果有重复key,则后一个key的值会覆盖前一个key的值。加载commandline配置信息时,如果一个key字符串以-作为前缀,那么就必须利用switchmapping将一个新key映射到旧key上,否则就会出错。

添加environmentvariablesconfigurationsource

ironmentvariablesconfigurationsource可以将操作系统的环境变量添加到配置系统中,同时你也可以对这些环境变量进行自定义,比如在vs开发调试的时候,可以在如下界面添加一些key/value:

http://www.lhsxpumps.com/_images/10qianwan/20171212/b_1_201712121906195157.jpg

取值方式如下:

var someconfiguration1 = configuration["env_var_key1"];
var someconfiguration2 = configuration["env_var_key2"];

另外,该配置源也支持azure环境变量和连接字符串,所以你也可以在azure界面里设置mssql、mysql、以及自定义链接字符串等等,但这些链接字符串需要以如下字符串开头:

1.mysql => mysqlconnstr_

2.ms sql => sqlconnstr_

3.sql azure db => sqlazureconnstr_

4.custom db => customconnstr_

举例来说,定义一个开发环境的key/value如下:

key => sqlconnstr_devlocal
value => server=localhost;database=test_db;trusted_connection=true;

通过addenvironmentvariables()的形式load完信息以后,我们则可以通过如下方式来访问这项信息:

var connstring = configuration["data:devlocal:connectionstring"];

也就是说,在azure里,环境变量的key会转换成data:自定义标识符:connectionstring这样的格式。如果你的key不是自定义key(以customconnstr_开头)的话,你可以用如下方式获取连接字符串的provider名称,示例如下:

var providername = configuration["data:devlocal:providername"];
/// 返回:system.data.sqlclient

environmentvariablesconfigurationsource另外还提供一种前缀过滤的方式加载部分信息,比如:

((iconfigurationsourcecontainer)configuration).add(new environmentvariablesconfigurationsource("data:"));

这样,再获取信息的时候,key值里的data:就可以省略了,示例如下:

var conn1 = configuration["devlocal:connectionstring"];
var conn2 = configuration["devlocal:providername"];

添加jsonconfigurationsource

在文章的开头,我们看到了json配置文件的加载,加载该文件只需要使用.addjsonfile("test.json")扩展方法即可,但不要忘记,要先在project.json的dependencies里引用microsoft.framework.configurationmodel.json程序集才行。

比如,如果你的config.json文件内容如下:

{
 "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"
 }
 }
}

那你就可以利用如下方式来访问链接字符串:

var conn = configuration["data:defaultconnection:connectionstring"];

添加xmlconfigurationsource

xmlconfigurationsource配置源和jsonconfigurationsource配置源类似,首先引用microsoft.framework.configurationmodel.xml程序集,然后调用.addxmlfile("test.xml")

如果你的配置文件test.xml的内容如下:

<root>
 <key1>jsinh</key1>
 <key2 subkey2="hello world" />
</root>

获取形式,则稍有有些区别(会忽略根节点root):

var s1 = configuration["key1"]; // 返回jsinh
var s2 = configuration["key2:subkey2"]; // 返回 hello world

但是要注意,通用的key不能重复声明,下面的文件在读取的时候就会出错。

<root>
 <key1>jsinh</key1>
 <key2 subkey2="hello world" />
 <key2 subkey2="hello world again" />
</root>

敏感信息配置(rc版新增功能)

在rc版发布以后,微软又新增了一种敏感信息配置实现,程序集为microsoft.framework.configurationmodel.usersecrets,通过该程序集的管理,我们可以将敏感的配置信息放在计算机的特殊目录下的secrets.json文件,其目录定义规则如下:

windows: %appdata%\microsoft\usersecrets\<applicationid>\secrets.json
linux: ~/.microsoft/usersecrets/<applicationid>\secrets.json
mac: ~/.microsoft/usersecrets/<applicationid>\secrets.json

我们来举例操作一下,首先,右键解决方案选择manage user secret,vs会自动给该程序创建一个applicationid,并保持在·project.json·文件中,示例如下:

{
 "usersecretsid": "aspnet5-webdemo01-20150430014447",
 "webroot": "wwwroot",
 "version": "1.0.0-*",
}

接着会自动打开%appdata%\microsoft\usersecrets\aspnet5-webdemo01-20150430014447\secrets.json文件,我们输入一个示例配置:

{
 "aa": {
 "bb": "cc"
 }
}

然后,我们在project.json文件里引用了上述程序集,再通过配置文件的统一方式进行注册,代码如下:

configuration = new configuration()
  .addjsonfile("config.json")
  .addenvironmentvariables()
  .addusersecrets(); // addusersecrets是添加敏感信息的扩展方法

然后就可以想普通的调用方法一下调用了,示例如下:

var data = configuration["aa:bb"]; // 结果:cc

通过这种方式,我们就可以将生产环境的配置信息放在隐私的位置了。

自定义配置源

通过以上示例以及查看其架构设计机制,我们可以发现,其实我们还可以自定义自己的配置源,比如我想从数据库中读取响应的配置信息,那我们只要定义一个dbconfigurationsource,并继承于configurationsource即可,实现响应的load重载即可。

public class dbconfigurationsource : baseconfigurationsource
{
 public override void load()
 {
 // 读取数据库所有的key/value,并将其赋值给idictionary<string, string>类型的data数据
 }
}

如果你不把数据保存在data属性里,那么你还要实现如下几个重载,以便从自己的私有数据集合里获取响应的值,比如从缓存中获取,示例如下:

public class dbconfigurationsource : baseconfigurationsource
{
 public override void load()
 {
 // 读取数据库所有的key/value,保存在私有变量_data中
 }

 public override void set(string key, string value)
 {
 // 更新数据库key对应的值
 // base.set(key, value);
 }

 public override bool tryget(string key, out string value)
 {
 // 从私有变量_data中获取key对应的value
 // return base.tryget(key, out value);
 }

 public override ienumerable<string> producesubkeys(ienumerable<string> earlierkeys, string prefix, string delimiter)
 {
 // 私有变量_data中,根据自己的机制返回响应的subkeys
 // return base.producesubkeys(earlierkeys, prefix, delimiter);
 }
}

实现完上述类以后,再为自己创建一个扩展方法用于添加db配置信息,代码如下:

public static class catsconfigurationextensions
{
 public static iconfigurationsourcecontainer adddbconfiguration(this iconfigurationsourcecontainer configuration)
 {
 configuration.add(new dbconfigurationsource());
 return configuration;
 }
}

就可以通过.adddbconfiguration()来添加db配置源了。

注意,db配置源需要使用数据库连接字符串,这一点需要注意(获取可以先从json配置文件获取连接字符串,然后再添加该配置源)。

配置信息遍历

在默认的配置源实现中,所有的类都继承于configurationsource,并且将信息数据保存在data属性中,所以如果要遍历这些数据,则需要将其转换为configurationsource类型才能使用,示例代码如下:

foreach (var o in configuration as configuration)
{
 var source = o as configurationsource;
 foreach (var key in source.data.keys)
 {
 console.writeline(key + ":" + source.data[key]);
 }
}

配置信息直接转换为实体类

iservicecollection接口上还有一个扩展方法.configure<t>可以将类型iconfiguration的数据转换为一个实体类,该扩展方法的定义如下:

public static iservicecollection configure<toptions>(this iservicecollection services, iconfiguration config, int order = -1000, string optionsname = "");

举个例子,如果我们定义如下一个实体:

public class appsettings
{
 public string sitetitle { get; set; }
}

然后在config.json里定义一个相同结构的配置信息,示例如下:

{
 "appsettings": {
 "sitetitle": "webdemo01"
 }
}

那么通过在startup的构造函数将配置信息加载以后,我们就可以将该信息赋值给appsettings实例,代码如下:

services.configure<appsettings>(configuration.getsubkey("appsettings"));

用的时候,使用applicationservicesgetrequiredservice方法即可,示例如下:

var appsettings = app.applicationservices.getrequiredservice<ioptions<appsettings>>().options;

注意事项:

在配置信息里,所有的key都是不区分大小写的,即key和key是一样的。如果多个配置源有重复的key,则以后最后添加的配置源中的key所对应的值为准。iconfiguration下的getsubkeysgetsubkey可以获取某个层级(或以某个层级开头的)的所有key列表。由于configuration是多实例的,所以按照示例中的代码,该实例在startup里初始化以后,其它类就无法访问了,所以如果要做全局性的访问,最好在初始化之后将其保存到一个静态变量中。

参考1:https://github.com/aspnet/configuration
参考2:

如对本文有疑问,请在下面进行留言讨论,广大热心网友会与你互动!! 点击进行留言回复

相关文章:

验证码:
移动技术网