配置的原子结构就是单纯的键值对,并且键和值都是字符串,但是在真正的项目开发中我们一般不会单纯地以键值对的形式来使用配置。值得推荐的做法就是采用《.NET Core采用的全新配置系统[1]: 读取配置数据》最后演示的方式将相关的配置定义成一个Options类型,并采用与类型定义想匹配的结构来定义原始的配置,这样就能利用它们之间的映射关系将读取的配置数据绑定为Options对象,我们将这种编程模式称为“Options模式”。 [ 本文已经同步到《ASP.NET Core框架揭秘》之中]

目录
一、配置绑定
二、扩展方法AddOptions
三、扩展方法Configure
四、Options对象的创建

一、配置绑定

对于一个Options对象来说,如果我们将其数据成员(这里主要指属性成员)视为其子节点,那么一个Options对象同样具有树形层次化结构,这与通过Configuration对象表示的配置树在结构上并没有本质的区别。如果Options类型的数据成员定义与配置树结构具有匹配的结构,那么将后者绑定为一个对应类型的Options对象是一件很容易的事情,对于这种将一个Configuration对象绑定为对应Options对象的行为简称为“配置绑定”。

配置绑定让我们可以根据得到的Configuration对象生成相应的Options对象,相关的API定义在“Microsoft.Extensions.Configuration.Binder”这个NuGet包中,后者为IConfiguration接口定义了如下一个GetValue方法得到绑定生成的Options对象。在调用这个放过的时候,我们会创建一个空的Options对象并将其作为参数,该方法会将Configuration承载的配置数据绑定到Options对象上。

   1: public static class ConfigurationBinder

   2: {

   3:     public static void Bind(this IConfiguration configuration, object instance);

   4: }

配置绑定的目标类型可以是一个简单的基元类型,也可以是一个自定义数据类型,还可以是一个数组、集合或者字典类型。上述的这个Bind方法在进行配置绑定的过程,针对不同的目标类型,它会采用不同的策略。至于该方法具体的实现原理,我们会在后续的部分予以单独介绍,而目前介绍的重点是Options模式采用的API在背后是如何调用这个方法得到所需的Options对象的。

我们在回顾一下《.NET Core采用的全新配置系统[1]: 读取配置数据》演示的采用Options模式读取配置的例子。Options模式是对依赖注入的应用,我们知道针对依赖注入的编程只涉及两个方面,即注册相应的服务到ServiceCollection对象上,在利用后者创建相应的ServiceProvider来提供我们所需的服务对象。如下面的代码片段所示,Options模式最终的目的是利用ServiceProvider得到一个类型为IOptions<TOptions>的服务对象,后者的Value通过配置绑定生成的Options对象。为了能够得到所需的服务对象,它借助两个扩展方法AddOptions和Configure<TOptions>注册了必要的服务。

   1: IConfiguration config = ...;

   2: FormatOptions options = new ServiceCollection()

   3:     .AddOptions()

   4:     .Configure<FormatOptions>(config.GetSection("Format"))

   5:     .BuildServiceProvider()

   6:     .GetService<IOptions<FormatOptions>>()

   7:     .Value;

二、扩展方法AddOptions

依然Options对象最终是利用依赖注入的方式创建的一个类型为IOptions<TOptions>的服务对象得到的,我们就先来认识一下这个接口。这是一个泛型接口,泛型参数类型TOptions代码的正式Options对象对应的类型。IOptions<TOptions>接口的定义如下,它只有一个唯一的只读属性Value返回我们所需的Options对象。

   1: public interface IOptions<out TOptions> where TOptions: class, new()

   2: {

   3:     TOptions Value { get; }

   4: }

当我们调用ServiceCollection的AddOptions的时候,该方法仅仅是按照如下的方式针对该类型注册了一个服务而已,这个服务的真实类型为OptionsManager <TOptions> ,注册的服务采用的生命周期模式为Singleton。换句话说,配置绑定生成的Options对象最终返回的实际上是通过OptionsManager <TOptions> 创建的。

   1: public static IServiceCollection AddOptions(this IServiceCollection services)

   2: {

   3:     services.TryAdd(ServiceDescriptor.Singleton(typeof(IOptions<>), typeof(OptionsManager<>)));

   4:     return services;

   5: }

如下所示的是 OptionsManager <TOptions> 类型的定义,我们可以看到它的构造函数接受一个元素类型为IConfigureOptions<TOptions>的集合作为参数,我们将实现了该接口的类型以及对应对象统称为ConfigureOptions<TOptions>。IConfigureOptions<TOptions>接口定义了一个唯一的Configure方法,该方法将一个Options对象作为输入参数。从定义可以看出一个ConfigureOptions<TOptions>对象的作用与一个类型为Action<TOptions>的委托对象,所以对于它的实现类型ConfigureOptions<TOptions>来说,对应的对象就直接通过一个Action<TOptions>对象来创建。

   1: public class OptionsManager<TOptions> : IOptions<TOptions> where TOptions: class, new()

   2: {

   3:     public OptionsManager(IEnumerable<IConfigureOptions<TOptions>> setups);

   4:     public virtual TOptions Value { get; }

   5: }

   6:  

   7: public interface IConfigureOptions<in TOptions> where TOptions: class

   8: {

   9:     void Configure(TOptions options);

  10: }

  11:  

  12: public class ConfigureOptions<TOptions>: IConfigureOptions<TOptions> where TOptions : class, new()

  13: {

  14:     public Action<TOptions> Action { get; private set; }

  15:     public ConfigureOptions(Action<TOptions> action)

  16:     {

  17:         this.Action = action;

  18:     }

  19:     public void Configure(TOptions options)

  20:     {

  21:         this.Action(options);

  22:     }

  23: }

Options对象的创建体现在 OptionsManager <TOptions>类型的Value属性上。该属性的实现非常简单,它先调用默认无参构造函数(Options类型必须具有一个默认无参构造函数)创建一个空的Options对象,在返回之前,它会将其递交给初始化时指定的ConfigureOptions<TOptions>对象进行逐个处理。毫无疑问,针对Bind方法的调用肯定是通过某个ConfigureOptions<TOptions>对象参与到整个流程之中的,具体的实现自然与另一个扩展方法Configure有关。

三、扩展方法Configure

Options模式仅仅涉及到针对ServiceCollection的两个扩展方法(AddOptions和Configure<TOptions>),前者将服务IOptions<TOptions>/ OptionsManager <TOptions>注册到ServiceCollection之上,后者又作了怎样的服务注册呢?

   1: public static IServiceCollection Configure<TOptions>(this IServiceCollection services, IConfiguration config) where TOptions: class

   2: {

   3:     return services.AddSingleton<IConfigureOptions<TOptions>>( new ConfigureFromConfigurationOptions<TOptions>(config));

   4: }

   5:  

   6: public class ConfigureFromConfigurationOptions<TOptions> :ConfigureOptions<TOptions> where TOptions : class

   7: {

   8:     public ConfigureFromConfigurationOptions(IConfiguration config) 

   9:      : base(options => config.Bind(options))

  10:     { }

  11: }

从上面的代码片段可以看出,当我们调用ServiceCollection的扩展方法Configure<TOptions>时,该方法会利用指定 的Configuration对象创建一个ConfigureFromConfigurationOptions对象,并以服务类型IConfigureOptions<TOptions>注册到ServiceCollection上,采用的生命周期模式为Singleton。至于类型ConfigureFromConfigurationOptions,它是上面介绍的ConfigureOptions<TOptions>类型的继承者,创建该对象指定的Action<TOptions>委托对象通过调用Configuration对象的扩展方法Bind最终实现了配置绑定。

四、Options对象的创建

Options编程模式的背后以两个注册到ServiceCollection的服务为核心,这两个服务对应的服务接口分别是IOptions<TOptions>和IConfigureOptions<TOptions>,前者直接提供最终绑定了配置数据的Options对象,后者则在Options对象返回之前对它实施相应的初始化工作。这个两个服务分别通过扩展方法AddOptions和Configure方法注册到指定的ServiceCollection之中,服务的真实类型分别是OptionsManager<TOptions>和ConfigureFromConfigurationOptions<TOptions>,后者派生于ConfigureOptions<TOptions>。下图所示的UML体现了Options模型中涉及的这些接口/类型以及它们之间的关系。

.NET Core采用的全新配置系统[3]: “Options模式”下的配置是如何绑定为Options对象的更多相关文章

  1. “Options模式”下的配置是如何绑定为Options对象

    “Options模式”下的配置是如何绑定为Options对象 配置的原子结构就是单纯的键值对,并且键和值都是字符串,但是在真正的项目开发中我们一般不会单纯地以键值对的形式来使用配置.值得推荐的做法就是 ...

  2. .NET Core采用的全新配置系统[10]: 配置的同步机制是如何实现的?

    配置的同步涉及到两个方面:第一,对原始的配置文件实施监控并在其发生变化之后从新加载配置:第二,配置重新加载之后及时通知应用程序进而使后者能够使用最新的配置.要了解配置同步机制的实现原理,先得从认识一个 ...

  3. .NET Core采用的全新配置系统[1]: 读取配置数据

    提到“配置”二字,我想绝大部分.NET开发人员脑海中会立马浮现出两个特殊文件的身影,那就是我们再熟悉不过的app.config和web.config,多年以来我们已经习惯了将结构化的配置定义在这两个文 ...

  4. .NET Core采用的全新配置系统[2]: 配置模型设计详解

    在<.NET Core采用的全新配置系统[1]: 读取配置数据>中,我们通过实例的方式演示了几种典型的配置读取方式,其主要目的在于使读者朋友们从编程的角度对.NET Core的这个全新的配 ...

  5. .NET Core采用的全新配置系统[4]: “Options模式”下各种类型的Options对象是如何绑定的?

    旨在生成Options对象的配置绑定实现在IConfiguration接口的扩展方法Bind上.配置绑定的目标类型可以是一个简单的基元类型,也可以是一个自定义数据类型,还可以是一个数组.集合或者字典类 ...

  6. Azure ARM模式下VNet配置中需要注意的几点事项

    虚拟网络的配置是所有公有云中非常重要的环节.把虚拟网络配置好,对整个系统的管理.维护,以及安全性都非常重要. 本文将介绍Azure在ARM模式下VNet配置中需要特别注意的几点. 一 Azure的VN ...

  7. Vmware在NAT模式下网络配置详解

    Vmware在NAT模式下网络配置详解 Linux中的网络配置对于接触Linux不久的小白菜来说,还是小有难度的,可能是不熟悉这种与windows系列迥然不同的命令行操作,也可能是由于对Linux的结 ...

  8. .NET Core采用的全新配置系统[5]: 聊聊默认支持的各种配置源[内存变量,环境变量和命令行参数]

    较之传统通过App.config和Web.config这两个XML文件承载的配置系统,.NET Core采用的这个全新的配置模型的最大一个优势就是针对多种不同配置源的支持.我们可以将内存变量.命令行参 ...

  9. .NET Core采用的全新配置系统[9]: 为什么针对XML的支持不够好?如何改进?

    物理文件是我们最常用到的原始配置的载体,最佳的配置文件格式主要由三种,它们分别是JSON.XML和INI,对应的配置源类型分别是JsonConfigurationSource.XmlConfigura ...

随机推荐

  1. 【开源】.Net Api开放接口文档网站

    开源地址:http://git.oschina.net/chejiangyi/ApiView 开源QQ群: .net 开源基础服务  238543768 ApiView .net api的接口文档查看 ...

  2. Tesseract-OCR字符识别简介

    OCR(Optical Character Recognition):光学字符识别,是指对图片文件中的文字进行分析识别,获取的过程.Tesseract:开源的OCR识别引擎,初期Tesseract引擎 ...

  3. 微信小程序中利用时间选择器和js无计算实现定时器(将字符串或秒数转换成倒计时)

    转载注明出处 改成了一个单独的js文件,并修改代码增加了通用性,点击这里查看 今天写小程序,有一个需求就是用户选择时间,然后我这边就要开始倒计时. 因为小程序的限制,所以直接选用时间选择器作为选择定时 ...

  4. input标签中button在iPhone中圆角的问题

    1.问题 使用H5编写微信页面时,使用<input type="button"/>时,在Android手机中显示正常,但是在iPhone手机中则显示不正常,显示为圆角样 ...

  5. http status code

    属于转载 http status code:200:成功,服务器已成功处理了请求,通常这表示服务器提供了请求的网页 404:未找到,服务器未找到 201-206都表示服务器成功处理了请求的状态代码,说 ...

  6. Java 中获取类路径 classpath 的方法

    System.out.println("++++++++++++++++++++++++"); String path = System.getProperty("jav ...

  7. 端盘子的服务生到月薪一万五的IT精英,你能相信吗

    一直以来,我都觉得自己不是一个有故事的人. 以前的我,是个乖宝宝,对父母言听计从,特别内向,甚至一度感觉到自卑.不上学之后,我干过送货员,去工地除泥搬砖,当过油漆工,去过工厂,还去饭店当过端盘子的服务 ...

  8. 高性能Javascript--高效的数据访问

    接上一篇,希望能写一个高性能Javascript专题. 第一篇:高性能Javascript--脚本的无阻塞加载策略. 参考摘录<高性能Javascript>. 经典计算机科学的一个问题是, ...

  9. ABP源码分析四十一:ZERO的Audit,Setting,Background Job

    AuditLog: 继承自Entity<long>的实体类.封装AuditLog的信息. AuditingStore: 实现了IAuditingStore接口,实现了将AuditLog的信 ...

  10. VR ( Virtual Reality )、AR(Augmented Reality)、MR(Mix Reality)和CR(Cinematic Reality)是什么鬼?

    整个社会对虚拟现实的研究和开发源于上个世纪六十年代,计算机图形学.人机接口技术.图像处理与模式识别.多传感技术.语音处理与音响技术.高性能计算机系统.人工智能等领域在之后半个世纪取得了长足的发展为虚拟 ...