博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
ASP.NET Core的配置(3): 将配置绑定为对象[下篇]
阅读量:6600 次
发布时间:2019-06-24

本文共 5046 字,大约阅读时间需要 16 分钟。

我们在《》通过实例的形式演示了如何利用Options模型以依赖注入的方式直接获取由指定配置节绑定生成的Options对象,我们再次回顾一下当初我们编写的程序。如下面的代码片段所示,基于Options模型的配置绑定的编程基本采用这样的模式:先后调用ServiceCollection的扩展方法AddOption和Configure注册Options模型相关的服务并完成Options类型与指定配置节之间的映射,然后利用由此生成ServiceProvider获得一个类型为IOptions<TOptions>的服务示例,后者的Value就是配置绑定生成的Options对象。

1: FormatSettings settings = new ServiceCollection()
2:     .AddOptions()
3:     .Configure
(configuration)
4:     .BuildServiceProvider()
5:     .GetService
>()
6:     .Value;

一、IOptions <TOptions>

由于Options模型的编程仅仅涉及到上述几个方法的调用,所以只要搞清楚这几个方法背后的实现逻辑,我们也就彻底了解了Options模型的实现原理。首先当我们调用ServiceCollection的扩展方法时,实际上仅仅是按照如下的方式注册了一个针对IOptions <TOptions>接口类型的服务而已。服务接口IOptions<TOptions>仅仅定义了一个只读属性Value,该属性返回的正是绑定了指定配置数据的Options对象。

1: public static class ServiceCollectionExtensions
2: {
3:     public static IServiceCollection AddOptions(this IServiceCollection services)
4:     {
5:         return services.AddSingleton(typeof(IOptions<>), typeof(OptionsManager<>));
6:     }
7: }
8: 
9: public interface IOptions
where TOptions:class, new()
10: {
11:     TOptions Value { get; }
12: }

通过上面的给出的代码片段我们不难看出,AddOptions方法实际上是以Singleton模式注册了一个类型为OptionsManager<TOptions>的服务,如下所示的代码片段基本反映了该类型的实现逻辑。如下面的代码片段所示,OptionsManager<TOptions>的只读属性Value返回的Options对象是以“延迟加载(Lazy Loading)”的形式被提供。Options对象创建的逻辑也很简单,我们直接调用其默认构造函数创建一个空的Options对象,然后将其递交给在构造函数中指定的一系列IConfigureOptions<TOptions>进行设置,配置绑定就这这个过程中完成。

1: public class OptionsManager
: IOptions
where TOptions : class, new()
2: {
3:     private Lazy
optionsAccessor;
4:     public OptionsManager(IEnumerable
> setups)
5:     {
6:         optionsAccessor = new Lazy
(() =>
7:         {
8:             TOptions options = new TOptions();
9:             setups.ForEach(it => it.Configure(options));
10:             return options;
11:         });
12:     }
13:     public TOptions Value
14:     {
15:         get { return optionsAccessor.Value; }
16:     }
17: }

二、IConfigureOptions<TOptions>

IConfigureOptions<TOptions>接口抽象了针对Options对象的配置行为,这个行为体现在定义其中的Configure方法。ConfigureOptions<TOptions>实现了这个接口,它采用在构造函数提供的Action<TOptions>完成对Options对象的配置。

1: public interface IConfigureOptions
where TOptions : class, new()
2: {
3:     void Configure(TOptions options);
4: }
5: 
6: public class ConfigureOptions
: IConfigureOptions
where TOptions : class, new()
7: {
8:     public Action
Action { get; private set; }
9:     public ConfigureOptions(Action
action)
10:     {
11:         this.Action = action;
12:     }
13:     public void Configure(TOptions options)
14:     {
15:         this.Action(options);
16:     }
17: }

针对Options对象的配置绑定工作实现在一个名为ConfigureFromConfigurationOptions<TOptions>的类中。如下面的代码片段所示,这个类型直接继承ConfigureOptions<TOptions>,在构造函数中指定的Configuration对象承载了最终需要绑定到Options对象上的配置数据,它直接调用Configuration对象的扩展方法Bind完成了针对Options对象的配置绑定。

1: public class ConfigureFromConfigurationOptions
: ConfigureOptions
where TOptions : class, new()
2: {
3:     public ConfigureFromConfigurationOptions(IConfiguration configuration) : base(options => configuration.Bind(options))
4:     { }
5: }

在Options模型中,ConfigureFromConfigurationOptions<TOptions>对象通过扩展方法Configure方法被注册到指定的ServiceCollection对象中。如下面的代码片段所示,Configure方法直接利用作为参数传入的Configuration对象创建一个ConfigureFromConfigurationOptions<TOptions>对象,并将这个对象注册到ServiceCollection之中。

1: public static class ServiceCollectionExtensions
2: {
3:     public static IServiceCollection Configure
(this IServiceCollection services, IConfiguration configuration)
4:     where TOptions : class, new()
5:     {
6:         return services.AddInstance
>(new ConfigureFromConfigurationOptions
(configuration));
7:     }
8: }

三、Options对象的提供

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

对于一个包含服务注册描述信息的ServiceCollection,当我们分别调用其扩展方法AddOptions和Configure完成了相应的服务注册之后,我们就可以利用由它生成的ServiceProvider对象来提供针对接口类型IOptions <TOptions>的服务实例,并通过后者的只读属性Value得到配置绑定生成的Options对象。

ServiceProvider提供的这个服务实例自然是一个OptionsManager<TOptions>对象,当ServiceProvider调用构造函数对它进行实例化的时候,我们注册的ConfigureFromConfigurationOptions<TOptions>对象会以构造器注入的形式作为参数。在构造函数执行过程中,一个空的Options对象先被创建出来后会作为参数调用ConfigureFromConfigurationOptions<TOptions>的Configure方法,后者将在预先指定的Configuration对象绑定到这个Options对象之上。

 

作者:蒋金楠
微信公众账号:大内老A
微博:
如果你想及时得到个人撰写文章以及著作的消息推送,或者想看看个人推荐的技术资料,可以扫描左边二维码(或者长按识别二维码)关注个人公众号(原来公众帐号
蒋金楠的自媒体将会停用)。
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
你可能感兴趣的文章
苹果公司的产品已用完后门与微软垄断,要检查起来,打架!
查看>>
chrome调试ajax
查看>>
centos 升级php、mysql(webtatic)
查看>>
Java并发编程:Lock
查看>>
中文文本分类器训练集
查看>>
java进程间通信
查看>>
oracle服务器和客户端字符集的查看和修改
查看>>
顶级的JavaScript框架、库、工具及其使用
查看>>
分享Kali Linux 2016.2第49周镜像文件
查看>>
AYUI -AYUI风格的 超美 百度网盘8.0
查看>>
linux下php中文UTF-8转换Unicode方法和注意事项
查看>>
TensorFlow:tf.contrib.layers.xavier_initializer
查看>>
快开学了,又被逼死一个!!现教育部已经成为催命阎王!!, 转自中华网
查看>>
简明 Python 教程
查看>>
Photoshop操作指南
查看>>
用MPMoviePlayerController做在线音乐播放
查看>>
ASP.NET调用cmd命令提示符拒绝访问解决方案
查看>>
Leetcode: Construct Binary Tree from Preorder and Inorder Transversal
查看>>
嵌入式开发之字符叠加---gb2313 国标码,utf8 国际码,unicode 无码
查看>>
Java查找算法——二分查找
查看>>