·您现在的位置: 云翼网络 >> 文章中心 >> 网站建设 >> 网站建设开发 >> ASP.NET网站开发 >> [Asp.net 5] Configuration-新一代的配置文件(接口定义与基础实现)
关于配置文件的目录:[Asp.net 5] Configuration-新一代的配置文件
本系列文章讲的是asp.net 5(Asp.net VNext)中的配置文件部分,工程下载地址为:https://github.com/aspnet/Configuration
本节讲的是Configuration解决方案中的Microsoft.Framework.Configuration和Microsoft.Framework.Configuration.Abstractions俩个工程。
Abstractions
首先我们看下Configuration.Abstractions这个工程的详情:
该工程中只定义了三个接口:IConfiguration、IConfigurationBuilder、IConfigurationSource,是完全为了抽象而设计的工程。
我们在依赖注入(DependencyInjection)篇中也接触过名字为“Abstractions”的工程(链接地址:http://www.cnblogs.com/watermoon2/p/4511269.html),也是只包含必须的接口定义,我们可以推测,微软的命名规则是对于XXXX类工程:
配置文件中,肯定少不了配置文件类的基础接口定义:IConfiguration;我们知道新的配置文件实现,支持配置文件有多个来源,可以来自xml、可以来自json、也可以既有部分来自xml,又有部分来自json,所以接口中定义了“IConfigurationSource”接口,用于标示配置文件的来源;而IConfigurationBuilder是IConfiguration的构造器。
这个工程代码比较少,下面我就将接口定义罗列如下:
public interface IConfigurationSource { bool TryGet(string key, out string value); void Set(string key, string value); void Load(); IEnumerable<string> PRoduceConfigurationSections( IEnumerable<string> earlierKeys, string prefix, string delimiter); } public interface IConfigurationBuilder { string BasePath { get; } IEnumerable<IConfigurationSource> Sources { get; } IConfigurationBuilder Add(IConfigurationSource configurationSource); IConfiguration Build(); }public interface IConfiguration { string this[string key] { get; set; } string Get(string key); bool TryGet(string key, out string value); IConfiguration GetConfigurationSection(string key); IEnumerable<KeyValuePair<string, IConfiguration>> GetConfigurationSections(); IEnumerable<KeyValuePair<string, IConfiguration>> GetConfigurationSections(string key); void Set(string key, string value); void Reload(); }接口定义
Configuration
我们还是将工程的详情列出:
工程中一共八个cs文件:
1,IConfigurationSource实现类:ConfigurationSource、MemoryConfigurationSource
2,IConfigurationBuilder实现类:ConfigurationBuilder;IConfigurationBuilder扩展方法:ConfigurationHelper
3,IConfiguration实现类:ConfigurationSection、ConfigurationFocus
4,帮助辅助类:ConfigurationKeyComparer、Constants。
一个约定:":"
我们知道配置文件不都是线性的,可能有层次结构(比如传统的配置文件、json的、xml的)。我们读取配置文件的key值就需要有一定的逻辑。现在的逻辑是:
所以对于如下的json格式{"root1":"r1","root2":{"sub1":"s2"}},想要获取值是“s2”,所使用的key值是“root2:sub1”;“root2”是父节点的key,“:”是分隔符,“sub1”是当前key。
在这里的分隔符,其实就是定义在Constants类中,public static readonly string KeyDelimiter = ":"; 不过源文件中其他部分并未都直接使用该处定义,在IConfigurationSource的派生类也都是自己定义的“:”;所以想修改分隔符,在现有代码中不是能够只修改Constants中这个全局变量就可以的。所以在源码还有问题的时候,我们还是把分隔符=“:”,作为一个约定(不要试图把分隔符该城其他字符串)。
特殊的排序方式
由于当前key值得字符串可能是由存数字组成,我们希望key值为“1”,“2”,“10”的顺序是“1”,“2”,“10” 而不是“1”,“10”,“2”(字符串默认排序的顺序),所以系统在排序的时候使用了IComparer<string>接口。而IComparer<string>接口的实现类就是ConfigurationKeyComparer。
public class ConfigurationKeyComparer : IComparer<string> { private const char Separator = ':'; public static ConfigurationKeyComparer Instance { get; } = new ConfigurationKeyComparer(); public int Compare(string x, string y) { var xParts = x?.Split(Separator) ?? new string[0]; var yParts = y?.Split(Separator) ?? new string[0]; // Compare each part until we get two parts that are not equal for (int i = 0; i < Math.Min(xParts.Length, yParts.Length); i++) { x = xParts[i]; y = yParts[i]; var value1 = 0; var value2 = 0; var xIsInt = x != null && int.TryParse(x, out value1); var yIsInt = y != null && int.TryParse(y, out value2); int result = 0; if (!xIsInt && !yIsInt) { // Both are strings result = string.Compare(x, y, StringComparison.OrdinalIgnoreCase); } else if (xIsInt && yIsInt) { // Both are int result = value1 - value2; } else { // Only one of them is int result = xIsInt ? -1 : 1; } if (result != 0) { // One of them is different return result; } } // If we get here, the common parts are equal. // If they are of the same length, then they are totally identical return xParts.Length - yParts.Length; } }ConfigurationKeyComparer
前面的铺垫已经讲完,下面我们进入正文:ConfigurationBuilder以及ConfigurationHelper
ConfigurationBuilder的功能主要有四点:
代码中需要注意的也就只有一点:添加新的IConfigurationSource时,首先加载,之后再将IConfigurationSource对象添加到内部IConfigurationSource列表中。
ConfigurationHelper是ConfigurationBuilder的扩展,作用只有一个:
ConfigurationBuilder以及ConfigurationHelper源码如下:
public class ConfigurationBuilder : IConfigurationBuilder { private readonly IList<IConfigurationSource> _sources = new List<IConfigurationSource>(); public ConfigurationBuilder(params IConfigurationSource[] sources) : this(null, sources) { } public ConfigurationBuilder(string basePath, params IConfigurationSource[] sources) { if (sources != null) { foreach (var singleSource in sources) { Add(singleSource); } } BasePath = basePath; } public IEnumerable<IConfigurationSource> Sources { ge