到“配置”二字,我想绝大部分.NET开发人员脑海中会立即浮现出两个特殊文件的身影,那就是我们再熟悉不过的app.config和web.config,多年以来我们已经习惯了将结构化的配置定义在这两个XML格式的文件之中。到了.NET Core的时代,很多我们习以为常的东西都发生了改变,其中就包括定义配置的方式。总的来说,新的配置系统显得更加轻量级,并且具有更好的扩展性,其最大的特点就是支持多样化的数据源。我们可以采用内存的变量作为配置的数据源,也可以将配置定义在持久化的文件甚至数据库中。在对配置系统进行系统介绍之前,我们先从编程的角度来体验一下全新的配置读取方式。

一、配置编程模型三要素

就编程层面来讲,.NET Core的配置系统由如下图所示的三个核心对象构成。读取出来的配置信息最终会转换成一个IConfiguration对象供应用程序使用。IConfigurationBuilder是IConfiguration对象的构建者,而IConfigurationSource则代表配置数据最原始的来源。

6-1

在读取配置的时候,我们根据配置的定义方式(数据源)创建相应的IConfigurationSource对象,并将其注册到IConfigurationBuilder对象上。提供配置的最初来源可能不止一个,我们可以注册多个相同或者不同类型的IConfigurationSource对象到同一个IConfigurationBuilder对象上。IConfigurationBuilder对象正是利用注册的这些IConfigurationSource对象提供的数据构建出我们在程序中使用的IConfiguration对象。

这里介绍的IConfiguration、IConfigurationSource和IConfigurationBuilder接口以及其他一些基础类型均定义在NuGet包“Microsoft.Extensions.Configuration.Abstractions”中。对这些接口的默认实现,则大多定义在“Microsoft.Extensions.Configuration”这个NuGet包中。

二、以键值对的形式读取配置

虽然大部分情况下的配置从整体来说都具有结构化层次关系,但是“原子”配置项都以体现为最简单的“键值对”形式,并且键和值通常都是字符串。接下来我们会通过一个简单的实例来演示如何以键值对的形式来读取配置。

假设我们的应用程序需要通过配置来设定日期/时间的显示格式,为此我们将相关的配置信息定义在如下所示的这个DateTimeFormatOptions类中,它的四个属性体现了针对DateTime对象的四种显示格式(分别为长日期/时间和短日期/时间)。

public class DateTimeFormatOptions {     ...     public string LongDatePattern { get; set; }     public string LongTimePattern { get; set; }     public string ShortDatePattern { get; set; }     public string ShortTimePattern { get; set; } }

我们希望通过配置的形式来控制由DateTimeFormatOptions的四个属性所体现的显示格式,所以我们为它定义了一个构造函数。如下面的代码片段所示,该构造函数具有一个IConfiguration接口类型的参数。键值对是配置的基本表现形式,所以IConfiguration对象提供了索引使我们可以根据配置项的Key得到配置项的值,下面的代码正是以索引的方式得到对应配置信息的。

public class DateTimeFormatOptions {     ...     public DateTimeFormatOptions (IConfiguration config)     {         LongDatePattern = config["LongDatePattern"];         LongTimePattern = config["LongTimePattern"];         ShortDatePattern = config["ShortDatePattern"];         ShortTimePattern = config ["ShortTimePattern"];     } }

要创建一个体现当前配置的DateTimeFormatOptions对象,我们必须提供这个承载相关配置信息的IConfiguration对象。正如我们前面所说,IConfiguration对象是由IConfigurationBuilder对象创建的,而原始的配置信息则是通过相应的IConfigurationSource对象来提供,所以创建一个IConfiguration对象的正确编程方式是:创建一个ConfigurationBuilder(IConfigurationBuilder接口的默认实现类型)对象并为之注册一个或者多个IConfigurationSource对象,最后利用它来创建我们需要的IConfiguration对象

我们通过如下的程序来读取配置并将其转换成一个DateTimeFormatOptions对象。简单起见,我们采用的IConfigurationSource实现类型为MemoryConfigurationSource,它直接利用一个保存在内存中的字典对象作为最初的配置来源。如下面的代码片段所示,我们在为MemoryConfigurationSource提供的字典对象中设置了四种类型的日期/时间显示格式。

public class Program {     public