提到“配置”二字,我想绝大部分.NET开发人员脑海中会立马浮现出两个特殊文件的身影,那就是我们再熟悉不过的app.config和web.config,多年以来我们已经习惯了将结构化的配置定义在这两个文件之中。到了.NET Core的时代,很多我们习以为常的东西都发生了改变,其中也包括定义配置的方式。总的来说,新的配置系统显得更加轻量级,并且具有更好的扩展性,其最大的特点就是支持多样化的数据源。我们可以采用内存的变量作为配置的数据源,也可以直接配置定义在持久化的文件甚至数据库中。由于很多人都不曾接触过这个采用全新设计的配置系统,为了让大家对它有一个大体的认识,我们先从编程的角度来体验一下全新的配置读取方式。这个全新的配置系统为配置的读取定义了非常简单的API,这些API涉及到三个核心的对象,我们不妨称之为“配置编程模型三要素”。 [ 本文已经同步到《ASP.NET Core框架揭秘》之中]
目录
一、配置编程模型三要素
二、以键-值对的形式读取配置
三、读取结构化的配置
四、将结构化配置直接绑定为对象
就编程层面来讲,.NET Core的这个配置系统由如下图所示的三个核心对象构成。读取出来的配置信息最终会转换成一个Configuration对象供我们的程序使用。ConfigurationBuilder是Configuration对象的构建者,而ConfigurationSource则代表配置最原始的来源。
在读取配置的时候,我们根据配置的定义方式创建相应的ConfigurationSource,并将其注册到创建的ConfigurationBuilder对象上。由于提供配置的最初来源可能不止一个,所以我们可以注册多个相同或者不同类型的ConfigurationSource对象到ConfigurationBuilder上。ConfigurationBuilder这是利用注册的这些ConfigurationSource提供的原始数据最终构建出我们在程序中使用的Configuration对象。
根据本系列文章一贯采用的命名方式,我们应该知道上面介绍的Configuration、ConfigurationSource和ConfigurationBuilder均是对一类对象的统称,它们在API层面都通过相应的接口(IConfiguration、IConfigurationSource和IConfigurationBuilder)来表示,这些接口均义在NuGet包“Microsoft.Extensions.Configuration.Abstractions”中。如果我们的程序中只需要使用到这些接口,我们只需要添加针对这个NuGet包的依赖。至于这些接口的默认实现类型,则大多定义在“Microsoft.Extensions.Configuration”这个NuGet包中。
二、以键-值对的形式读取配置虽然在大部分情况下的配置从整体来说都具有结构化的次关系,但是“原子”配置项都以最简单的“键-值对”的形式来体现,并且键和值通常都是字符串,接下来我们会通过一个简单的实例来演示如何以键值对的形式来读取配置。我们创建一个针对ASP.NET Core的控制台应用,并在project.json中按照如下的方式添加针对“Microsoft.Extensions.Configuration”这个NuGet包的依赖,配置模型就实现在这个包中。
: "1.0.0 " 5: }, 6: }
假设我们的应用程序需要通过配置来设定日期/时间的显示格式,为此我们将相关的配置信息定义在如下所示的这个DateTimeFormatOptions类,它的四个属性体现针对DateTime对象的四种显示格式(分别为长日期/时间和短日期/时间)。
DateTimeFormatOptionsLongDatePattern { get; set; }LongTimePattern { get; set; }ShortDatePattern { get; set; }ShortTimePattern { get; set; } 7: //其他成员 8: }
我们希望通过配置的形式来控制由DateTimeFormatOptions的四个属性体现的日期/时间显示格式,所以我们为它定义了一个构造函数。如下面的代码片段所示,该构造函数具有一个IConfiguration接口类型的参数,通过上面的介绍我们知道它是配置在应用程序中体现。键值对是配置的基本表现形式,所以Configuration对象提供了索引使我们可以根据配置项的Key得到配置项的值,下面的代码正式调用索引的方式得到对应配置信息的。
DateTimeFormatOptionsDateTimeFormatOptions (IConfiguration config).LongTimePattern = config [.ShortTimePattern = config ["ShortTimePattern"]; 10: } 11: }
要创建一个体现当前配置的DateTimeFormatOptions对象,我们必须向得到这个承载相关配置信息的Configuration对象。正如我们上面所说,Configuration对象是由ConfigurationBuilder创建的,而原始的配置信息则是通过相应的ConfigurationSource来提取的,所以创建一个Configuration对象的正确编程方式是先创建一个ConfigurationBuilder对象,然后为之注册一个或者多个ConfigurationSource对象,最后利用ConfigurationBuilder来创建我们需要的Configuration对象。
我们通过如下的程序来读取配置并将其转换成一个DateTimeFormatOptions对象。简单起见,我们采用一中类型为MemoryConfigurationSource的ConfigurationSource,它直接利用一个保存在内存中的字典对象作为最初的配置来源。如下面的代码片段所示,我们在为MemoryConfigurationSource提供的字典对象中设置了四种类型的日期/时间显示格式。
1: Dictionary<string, string> source = new Dictionary<string, string> 2: { 3: ["longDatePattern"] = "dddd, MMMM d, yyyy", 4: ["longTimePattern"] = "h:mm:ss tt", 5: ["shortDatePattern"] = "M/d/yyyy", 6: ["shortTimePattern"] = "h:mm tt" 7: }; 8: 9: IConfiguration config = new ConfigurationBuilder() 10: .Add(new MemoryConfigurationSource { InitialData = source }) 11: .Build(); 12: 13: DateTimeFormatOptions options = new DateTimeFormatOptions(config); 14: Console.WriteLine($"LongDatePattern: {options.LongDatePattern}"); 15: Console.WriteLine($"LongTimePattern: {options.LongTimePattern}"); 16: Console.WriteLine($"ShortDatePattern: {options.ShortDatePattern}"); 17: Console.WriteLine($"ShortTimePattern: {options.ShortTimePattern}");