ASP.NET Core 2.1 源码学习之 Options[2]:IOptions
在 上一章 中,介绍了Options的注册,而在使用时只需要注入 IOption<T> 即可:
public ValuesController(IOptions<MyOptions> options)
{
var opt = options.Value;
}
本章就来详细介绍一下我们最熟悉的IOptions对象。
目录
- IOptions
- OptionsManager
- OptionsFactory
- OptionsCache
- IOptionsSnapshot
IOptions
IOptions 定义非常简单,只有一个Value属性:
public interface IOptions<out TOptions> where TOptions : class, new()
{
TOptions Value { get; }
}
在 上一章 中,我们知道它的默认实现为OptionsManager:
services.TryAdd(ServiceDescriptor.Singleton(typeof(IOptions<>), typeof(OptionsManager<>)));
OptionsManager
OptionsManager 对options的创建和获取进行管理,我们先看一下它的源码:
public class OptionsManager<TOptions> : IOptions<TOptions>, IOptionsSnapshot<TOptions> where TOptions : class, new()
{
private readonly IOptionsFactory<TOptions> _factory;
private readonly OptionsCache<TOptions> _cache = new OptionsCache<TOptions>(); // Note: this is a private cache
public OptionsManager(IOptionsFactory<TOptions> factory)
{
_factory = factory;
}
public TOptions Value => Get(Options.DefaultName);
public virtual TOptions Get(string name) => _cache.GetOrAdd(name, () => _factory.Create(name ?? Options.DefaultName));
}
如上,OptionsManager 的实现非常简单,使用IOptionsFactory来创建options对象,并使用内部属性OptionsCache<TOptions> _cache进行缓存。
OptionsFactory
IOptionsFactory 只定义了一个Create方法:
public interface IOptionsFactory<TOptions> where TOptions : class, new()
{
TOptions Create(string name);
}
其默认实现为:OptionsFactory:
public class OptionsFactory<TOptions> : IOptionsFactory<TOptions> where TOptions : class, new()
{
private readonly IEnumerable<IConfigureOptions<TOptions>> _setups;
private readonly IEnumerable<IPostConfigureOptions<TOptions>> _postConfigures;
public OptionsFactory(IEnumerable<IConfigureOptions<TOptions>> setups, IEnumerable<IPostConfigureOptions<TOptions>> postConfigures)
{
_setups = setups;
_postConfigures = postConfigures;
}
public TOptions Create(string name)
{
var options = new TOptions();
foreach (var setup in _setups)
{
if (setup is IConfigureNamedOptions<TOptions> namedSetup)
{
namedSetup.Configure(name, options);
}
else if (name == Options.DefaultName)
{
setup.Configure(options);
}
}
foreach (var post in _postConfigures)
{
post.PostConfigure(name, options);
}
return options;
}
}
OptionsFactory的构造函数中注入了IConfigureOptions<> 和 IPostConfigureOptions<>,也就是我们在 上一章 中介绍的 Configure 方法中所注册的配置,而这里使用了 IEnumerable 类型,则表示当注册多个时,为按顺序依次执行。
而我们在第一章中遇到的疑惑也豁然开朗,其Create方法,依次调用完Configure方法后,再调用PostConfigure方法,完成配置项的创建。
OptionsCache
OptionsCache 则是对字典的一个简单封装,就不再多说,直接看代码:
public class OptionsCache<TOptions> : IOptionsMonitorCache<TOptions> where TOptions : class
{
private readonly ConcurrentDictionary<string, Lazy<TOptions>> _cache = new ConcurrentDictionary<string, Lazy<TOptions>>(StringComparer.Ordinal);
public void Clear() => _cache.Clear();
public virtual TOptions GetOrAdd(string name, Func<TOptions> createOptions)
{
name = name ?? Options.DefaultName;
return _cache.GetOrAdd(name, new Lazy<TOptions>(createOptions)).Value;
}
public virtual bool TryAdd(string name, TOptions options)
{
name = name ?? Options.DefaultName;
return _cache.TryAdd(name, new Lazy<TOptions>(() => options));
}
public virtual bool TryRemove(string name)
{
name = name ?? Options.DefaultName;
return _cache.TryRemove(name, out var ignored);
}
}
IOptionsSnapshot
最后再来介绍一下 IOptionsSnapshot :
public interface IOptionsSnapshot<out TOptions> : IOptions<TOptions> where TOptions : class, new()
{
TOptions Get(string name);
}
看到Get方法的Name参数,我想大家便会想到在第一章中所介绍的指定Name的Configure方法,这便是它的用武之地了,通过Name的不同,可以配置同一个Options类型的多个实例。
而IOptionsSnapshot的实现与IOptions一样,都是OptionsManager:
services.TryAdd(ServiceDescriptor.Singleton(typeof(IOptions<>), typeof(OptionsManager<>)));
services.TryAdd(ServiceDescriptor.Scoped(typeof(IOptionsSnapshot<>), typeof(OptionsManager<>)));
通过如上代码,我们也可以发现它与IOptions还有一个本质的区别:IOptionsSnapshot注册的是Scoped类型,每一个请求中,都会创建一个新的OptionsManager对象。这样有什么好处呢?如果我们使用的是Action的方式配置的,那的确是没什么用,但是如果是使用IConfiguration配置的,则在我们修改了配置文件时,重新创建的Options会保持一致。
总结
本文描述了在 .NET Core Options 系统中IOptions的使用及实现原理。由于IOptions使用的是单例模式,因此当配置发生变化时,我们无法获取到最新的配置。而IOptionsSnapshot支持通过name来区分同一类型的不同 options ,并且每次请求都会重新创建 options 实例,相应的,会有稍微的性能损耗。如果我们希望能够监控配置源的变化,来自动更新,则可以使用下一章要介绍的更为强大的 IOptionsMonitor 。
ASP.NET Core 2.1 源码学习之 Options[2]:IOptions的更多相关文章
- ASP.NET Core 2.1 源码学习之 Options[2]:IOptions 【转】
原文链接:https://www.cnblogs.com/RainingNight/p/strongly-typed-options-ioptions-in-asp-net-core.html 在 上 ...
- ASP.NET Core 2.1 源码学习之 Options[1]:Configure
配置的本质就是字符串的键值对,但是对于面向对象语言来说,能使用强类型的配置是何等的爽哉! 目录 ASP.NET Core 配置系统 强类型的 Options Configure 方法 Configur ...
- ASP.NET Core 2.1 源码学习之 Options[3]:IOptionsMonitor
前面我们讲到 IOptions 和 IOptionsSnapshot,他们两个最大的区别便是前者注册的是单例模式,后者注册的是 Scope 模式.而 IOptionsMonitor 则要求配置源必须是 ...
- ASP.NET Core 2.1 源码学习之 Options[3]:IOptionsMonitor 【转】
原文链接:https://www.cnblogs.com/RainingNight/p/strongly-typed-options-ioptions-monitor-in-asp-net-core. ...
- ASP.NET Core 2.1 源码学习之 Options[1]:Configure 【转】
原文链接:https://www.cnblogs.com/RainingNight/p/strongly-typed-options-configure-in-asp-net-core.html 配置 ...
- ASP.NET Core 选项模式源码学习Options Configure(一)
前言 ASP.NET Core 后我们的配置变得更加轻量级了,在ASP.NET Core中,配置模型得到了显著的扩展和增强,应用程序配置可以存储在多环境变量配置中,appsettings.json用户 ...
- ASP.NET Core 源码学习之 Options[2]:IOptions
在上一篇中,介绍了一下Options的注册,而使用时只需要注入IOption即可: public ValuesController(IOptions<MyOptions> options) ...
- ASP.NET Core 选项模式源码学习Options IOptions(二)
前言 上一篇文章介绍IOptions的注册,本章我们继续往下看 IOptions IOptions是一个接口里面只有一个Values属性,该接口通过OptionsManager实现 public in ...
- ASP.NET Core 选项模式源码学习Options IOptionsMonitor(三)
前言 IOptionsMonitor 是一种单一示例服务,可随时检索当前选项值,这在单一实例依赖项中尤其有用.IOptionsMonitor用于检索选项并管理TOption实例的选项通知, IOpti ...
随机推荐
- SEIG Modbus 3.4 CVE-2013-0662 漏洞分析与利用
前言 Schneider Electric Modbus Serial Driver 会监听 27700 端口,程序在处理客户端发送的数据时会导致栈溢出. 测试环境: windows xp sp3 相 ...
- Expo大作战(三十一)--expo sdk api之Payments(expo中的支付),翻译这篇文章傻逼了,完全不符合国内用户,我只负责翻译大家可以略过!
简要:本系列文章讲会对expo进行全面的介绍,本人从2017年6月份接触expo以来,对expo的研究断断续续,一路走来将近10个月,废话不多说,接下来你看到内容,讲全部来与官网 我猜去全部机翻+个人 ...
- Java 数据驱动测试
适用场景 测试搜索功能, 基于数据类型需要测多种不同的数据, 比如最大值, 小数, 负数, 字符串, 特异符号等等. 如果直接写代码, 每一种数据类型都需要写一遍代码, 冗长且不方便调试. 如果采用数 ...
- TensorFlow深度学习入门
# -*- coding: utf-8 -*- """ Created on Tue Oct 2 15:49:08 2018 @author: zhen "&q ...
- [20170705]理解linux su命令.txt
[20170705]理解linux su命令.txt --//我一般在维护时经常使用root用户登录,然后su - oracle 转到其他用户操作--//一般都加入 - 参数.这个已经成了条件反射.. ...
- 百度-淘宝-360搜索引擎搜索API
百度(baidu) Api地址:http://suggestion.baidu.com/su?wd=设计&p=3&cb=window.bdsug.sug window.bdsug.su ...
- Linux 小知识翻译 - 「Linux」和病毒
据说,「Linux」系统上的病毒要远远少于Windows系统上病毒.从2种系统的普及度来看,这是很显然的, 「Linux」的使用人群很少,所以「Linux」上的病毒的扩散时,受害的范围也不大. 但是, ...
- VRS生成的虚拟观测值存在的问题
目前生成的虚拟观测值. 天津的版本,如果有数据库中有天线类型,那么会对天线类型改正了两次. 解决方法:在生成虚拟观测值编码的部分,注释掉天线改正的部分. 对结果的影响:错误版本生成的虚拟观测值,移动站 ...
- Scrapy中将item字段转为简体or繁体
1. 安装hanziconv安装一个简繁体转换的包: pip install hanziconv 2. 自定义一个itempiples找到项目中的pipelines.py文件 添加自定义的pipeli ...
- python五十六课——正则表达式(常用函数之compile())
2).compile(regex,[flags=0]):返回一个Pattern对象(认为:它内部已经封装了一套regex和flags) 可以再通过Pattern对象继续调用match函数(此时只需要传 ...