原文链接:https://www.cnblogs.com/RainingNight/p/strongly-typed-options-ioptions-in-asp-net-core.html

在 上一章 中,介绍了Options的注册,而在使用时只需要注入 IOption<T> 即可:

public ValuesController(IOptions<MyOptions> options)
{
var opt = options.Value;
}

本章就来详细介绍一下我们最熟悉的IOptions对象。

目录

  1. IOptions
  2. OptionsManager
  3. OptionsFactory
  4. OptionsCache
  5. 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参数,我想大家便会想到在第一章中所介绍的指定NameConfigure方法,这便是它的用武之地了,通过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 【转】的更多相关文章

  1. ASP.NET Core 2.1 源码学习之 Options[2]:IOptions

    在 上一章 中,介绍了Options的注册,而在使用时只需要注入 IOption<T> 即可: public ValuesController(IOptions<MyOptions& ...

  2. ASP.NET Core 2.1 源码学习之 Options[1]:Configure

    配置的本质就是字符串的键值对,但是对于面向对象语言来说,能使用强类型的配置是何等的爽哉! 目录 ASP.NET Core 配置系统 强类型的 Options Configure 方法 Configur ...

  3. ASP.NET Core 2.1 源码学习之 Options[3]:IOptionsMonitor

    前面我们讲到 IOptions 和 IOptionsSnapshot,他们两个最大的区别便是前者注册的是单例模式,后者注册的是 Scope 模式.而 IOptionsMonitor 则要求配置源必须是 ...

  4. ASP.NET Core 2.1 源码学习之 Options[3]:IOptionsMonitor 【转】

    原文链接:https://www.cnblogs.com/RainingNight/p/strongly-typed-options-ioptions-monitor-in-asp-net-core. ...

  5. ASP.NET Core 2.1 源码学习之 Options[1]:Configure 【转】

    原文链接:https://www.cnblogs.com/RainingNight/p/strongly-typed-options-configure-in-asp-net-core.html 配置 ...

  6. ASP.NET Core 选项模式源码学习Options Configure(一)

    前言 ASP.NET Core 后我们的配置变得更加轻量级了,在ASP.NET Core中,配置模型得到了显著的扩展和增强,应用程序配置可以存储在多环境变量配置中,appsettings.json用户 ...

  7. ASP.NET Core 源码学习之 Options[2]:IOptions

    在上一篇中,介绍了一下Options的注册,而使用时只需要注入IOption即可: public ValuesController(IOptions<MyOptions> options) ...

  8. ASP.NET Core 选项模式源码学习Options IOptions(二)

    前言 上一篇文章介绍IOptions的注册,本章我们继续往下看 IOptions IOptions是一个接口里面只有一个Values属性,该接口通过OptionsManager实现 public in ...

  9. ASP.NET Core 选项模式源码学习Options IOptionsMonitor(三)

    前言 IOptionsMonitor 是一种单一示例服务,可随时检索当前选项值,这在单一实例依赖项中尤其有用.IOptionsMonitor用于检索选项并管理TOption实例的选项通知, IOpti ...

随机推荐

  1. Uva 11235 RMQ问题

    RMQ: 有一个不变的数组,不停的求一个区间的最小值. 使用倍增的思想优化到logN; d(i,j) 表示从 i 开始的,长度为2j的一段元素中的最小值. 那么状态转移方程: d(i,j) = min ...

  2. DP,得到最多苹果,(POJ2385)

    题目链接:http://poj.org/problem?id=2385 题意: 牛在两棵苹果树下收集苹果,牛只能在这两棵树之间走动w次,在t时刻,某棵树会掉下苹果. 解题报告: ///dp[t][w] ...

  3. 在vue中同时使用过渡和动画

    在上次的动画中,在显示和隐藏有动画效果,但是,刷新页面的时候,第一次的显示没有动画效果 需求:刷新页面的时候也有动画效果 <transition name='fade' appear enter ...

  4. vuejs动态组件和v-once指令

    场景,点击某个按钮,两个子组件交替显示 <div id='root'> <child-one v-if='type==="child-one"'></ ...

  5. Java从入门到放弃——04.数组

    本文目标 数组 1.数组 定义一个数组的三个姿势: 数组类型 []    数组名  =   new   数组类型[数组数量]: 数组类型 []    数组名  =   new   数组类型[]{对象1 ...

  6. Spring Security 实现记住我

    开篇一张图,道理全靠悟. 示例如下: 1.    新建Maven项目  remember_me 2.   pom.xml <project xmlns="http://maven.ap ...

  7. innerHTML动态添加标签的注意事项

    在使用javascript动态添加页面上元素时,我们经常会使用DOM去逐个地将节点添加到文档碎片中,再将整个文档节点添加到DOM树中.其实还有一种方法动态添加元素:innerHTML. 我最近要将一大 ...

  8. C#继承简介与规则

    一.C#继承简介 1. 类的层次结构 下面是一个类的层次结构图: 上图反映了鱼类的派生关系,其中最高层的实体往往具有最一般最普遍的特征,越下层的实体就越具体,并且下层包含了上层的特征.如果将上层的实体 ...

  9. 用dockers实现mysql主从同步

    首先要先看看当前的mysql的版本是什么,可以通过下面命令查看 mysql --version 最好是安装在docker中的mysql和你宿主机器中的mysql版本一致. 我的是mysql5.7.22 ...

  10. ReactiveCocoa实战: 模仿 "花瓣",重写 LeanCloud Rest Api的iOS REST Client.

    这一次我们将要讨论的是移动开发中比较重要的一环--网络请求的封装.鉴于个人经验有限,本文将在一定程度上参考 基于AFNetworking2.0和ReactiveCocoa2.1的iOS REST Cl ...