在前面的章节中,我们知道新版的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文件,而且甚至可以为不同的环境(开发、测试、生产)设置不同的配置信息。整个配置机制的各个重要实体见下图:

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

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

添加EnvironmentVariablesConfigurationSource

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

取值方式如下:

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;

注意事项:

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

参考1:https://github.com/aspnet/Configuration

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

同步与推荐

本文已同步至目录索引:解读ASP.NET 5 & MVC6系列

解读ASP.NET 5 & MVC6系列(5):Configuration配置信息管理的更多相关文章

  1. 解读ASP.NET 5 & MVC6系列(8):Session与Caching

    在之前的版本中,Session存在于System.Web中,新版ASP.NET 5中由于不在依赖于System.Web.dll库了,所以相应的,Session也就成了ASP.NET 5中一个可配置的模 ...

  2. 解读ASP.NET 5 & MVC6系列(4):核心技术与环境配置

    asp.net 5是下一代的asp.net,该版本进行了全部重写以适用于跨平台,新新版本中,微软引入了如下工具与命令:DNVM.DNX.DNU. DNVM(.NET Version Manager): ...

  3. 解读ASP.NET 5 & MVC6系列

    本系列的大部分内容来自于微软源码的阅读和网络,大部分测试代码都是基于VS RC版本进行测试的. 解读ASP.NET 5 & MVC6系列(1):ASP.NET 5简介 解读ASP.NET 5 ...

  4. 解读ASP.NET 5 & MVC6系列(2):初识项目

    初识项目 打开VS2015,创建Web项目,选择ASP.NET Web Application,在弹出的窗口里选择ASP.NET 5 Website模板创建项目,图示如下: 我们可以看到,此时Web ...

  5. 解读ASP.NET 5 & MVC6系列(3):项目发布与部署

    本章我们将讲解ASP.NET5项目发布部署相关的内容,示例项目以我们前一章创建的BookStore项目为例. 发布前的设置 由于新版ASP.NET5支持多版本DNX运行环境的发布和部署,所以在部署之前 ...

  6. 解读ASP.NET 5 & MVC6 ---- 系列文章

    本系列的大部分内容来自于微软源码的阅读和网络,大部分测试代码都是基于VS RC版本进行测试的. 解读ASP.NET 5 & MVC6系列(1):ASP.NET 5简介 解读ASP.NET 5 ...

  7. [转]解读ASP.NET 5 & MVC6系列(8):Session与Caching

    本文转自:http://www.cnblogs.com/TomXu/p/4496445.html 在之前的版本中,Session存在于System.Web中,新版ASP.NET 5中由于不在依赖于Sy ...

  8. 解读ASP.NET 5 & MVC6系列(17):MVC中的其他新特性

    (GlobalImport全局导入功能) 默认新建立的MVC程序中,在Views目录下,新增加了一个_GlobalImport.cshtml文件和_ViewStart.cshtml平级,该文件的功能类 ...

  9. 解读ASP.NET 5 & MVC6系列(16):自定义View视图文件查找逻辑

    之前MVC5和之前的版本中,我们要想对View文件的路径进行控制的话,则必须要对IViewEngine接口的FindPartialView或FindView方法进行重写,所有的视图引擎都继承于该IVi ...

随机推荐

  1. thinkphp 3.2.3 session 丟失問題

    之前做的几个 站session在跨页时也不会丢失(都在同一台服务器,所以我排除了服务器配置问题),这次居然很奇怪的发生的,在火狐上有,在ie, 谷哥上没有session,看了很多网上的贴子 其中有一个 ...

  2. Docker和Docker-compose安装教程以及docker-elk,docker-storm安装教程

    此安装教程仅供我自己安装配置时查看,其他的人不可以偷看!!! 安装Docker 1. Update package information, ensure that APT works with th ...

  3. 【Python装饰者】在函数测试的作用

    [引言] 我们经常需要多函数进行耗时测试,测试方法有许多,这里介绍装饰者的方法,提高耗时测试代码的可复用性,在其他方面的应用也是如此. [设计原则] 类应该对扩展开放,对修改关闭. [代码] (1)定 ...

  4. BAT 技术团队博客

    1. 美团技术团队博客:  地址: http://tech.meituan.com/ 2. 腾讯社交用户体验设计(ISUX) 地址:http://isux.tencent.com/ 3. 京东设计中心 ...

  5. The method setPositiveButton(int, DialogInterface.OnClickListener) in the type AlertDialog.Builder is not applicable for the arguments

    The method setPositiveButton(int, DialogInterface.OnClickListener) in the type AlertDialog.Builder i ...

  6. js学习笔记之标准库

    在全局函数中,this等于window  在函数被作为某个对象的方法调用时,this等于那个对象. 数组的函数: 检测:Array.isArray() 转换:toString(),toLocalStr ...

  7. 懒加载lazyload

    什么是懒加载 懒加载就是当你做滚动到页面某个位置,然后再显示当前位置的图片,这样做可以减少页面请求. 懒加载:主要目的是作为服务器前端的优化,减少请求数或延迟请求数,一些图片非常多的网站中非常有用,在 ...

  8. nginx的日常应用

    nginx的配置文件nginx.conf配置详解如下: user nginx nginx ; Nginx用户及组:用户 组.window下不指定 worker_processes ; 工作进程:数目. ...

  9. 对Hibernate的理解

    ---恢复内容开始--- 一.面向对象设计的软件内部运行过程可以理解成就是不断创建各种新对象,建立对象之间的关系,调用对象的方法来改变各个对象的状态和对象消亡的过程.不管程序运行的过程和操作怎么样,本 ...

  10. debian下Apache和tomcat整合(使用apt工具)

    最近部署web系统,需要使用tomcat处理和Apache整合使用,tomcat处理JSP,Apache处理静态资源.开始不知道怎么操作,在网上查阅资料走了很多弯路.完成时候,发现其实很简单,现将配置 ...