Options是.net core提出的一种辅助配置机制,即选项。

  目前,我们可以使用的Options有五种(源码):

  IOptionsFactory<>:Options的创建工厂(Singleton),所有的Options均使用它仅限创建,可以使用名称创建指定名称的Options

  IOptions<>:常用的一种Options模式,不可指定名称,且会缓存Options,全局将使用这个缓存的Options,没有重新加载机制,不可修改。(ps:可使用反射进行修改)

  IOptionsSnapshot<>:和IOptionsFactory<>差不多,内部使用IOptionsFactory<>来创建,但是IOptionsSnapshot<>内部有缓存,且它的作用于是Scoped,做web开发的时候,如果不想自己实现重新加载,不妨使用IOptionsSnapshot<>。

  IOptionsMonitor<>和IOptionsMonitorCache<>:IOptionsMonitorCache<>是IOptionsMonitor<>的缓存,读取IOptionsMonitor<>时,会先从IOptionsMonitorCache<>缓存中读取,没有则使用IOptionsFactory<>创建并加入到IOptionsMonitorCache<>缓存中去,因此当配置发生改变时,我们需要重新加载才能得到新的Options,所谓重新加载,就是Options中的数据重新执行Configure以及PostConfigure中的方法。

  在继续下面的内容之前,我们应该明确,只有IOptionsMonitor<>会涉及到重新加载,那么何时需要重新加载?也就是何时触发这个重新加载?不同的系统做法会不一样,有的使用一条消息总线,有的使用消息的发布订阅,有的使用接口的手动触发,本文介绍采用定时器来模拟说明:

  一、使用IOptionsMonitorCache<>

  上面介绍到,IOptionsMonitorCache<>是IOptionsMonitor<>缓存,自然可以通过IOptionsMonitorCache<>来清除缓存来实现Options的重新创建了,如:

  假如数据源是一个类的数据,然后使用定时器定时刷新,刷新后需要清除IOptionsMonitorCache<>缓存:  

    //表示Options的数据来源
public class OptionsSource
{
public static DateTime Time { get; private set; } public OptionsSource(IServiceProvider serviceProvider)
{
Timer timer = new Timer();
timer.Interval = 10000;//10秒钟刷新一次Time
timer.Elapsed += new ElapsedEventHandler((o, e) =>
{
Time = DateTime.Now; //清除缓存
var options = serviceProvider.GetService(typeof(IOptionsMonitorCache<DemoOptions>)) as IOptionsMonitorCache<DemoOptions>;
options.Clear();//或者使用TryRemove删除某个名称的Options
});
timer.Start();//启动
}
}

  接着在Startup中注册Options:  

    public void ConfigureServices(IServiceCollection services)
{
//注册Options
services.Configure<DemoOptions>(options =>
{
options.Time = OptionsSource.Time;
});
services.AddSingleton<OptionsSource>();//数据源 //其他服务注入代码
} public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
app.ApplicationServices.GetRequiredService<OptionsSource>();//获取一次,启动定时器 //其他代码
}

  接下来可以使用IOptionsMonitor<>获取Options,会发现每隔10秒,数据会刷新一次,比如有一个接口读取Options,每10秒调用试试:  

    [HttpGet]
public object GetOptions()
{
var options = HttpContext.RequestServices.GetService(typeof(IOptionsMonitor<DemoOptions>)) as IOptionsMonitor<DemoOptions>;
return options.CurrentValue;
}

  二、使用IOptionsChangeTokenSource<>

  IOptionsChangeTokenSource<>是IOptionsMonitor<>用于触发重新加载Options的接口,它有一个Name属性,表示重新加载某个指定名称的Options,还有一个GetChangeToken方法,用于获取一个IChangeToken,由这个IChangeToken来触发何时应该重新加载Options,比如:

  我们先实现IOptionsChangeTokenSource<>接口:

    public class MyOptionsChangeTokenSource<TOptions> : IOptionsChangeTokenSource<TOptions> where TOptions : class
{
ConfigurationReloadToken _reloadToken = new ConfigurationReloadToken(); public MyOptionsChangeTokenSource(string name)
{
Name = name ?? Options.DefaultName;
} public string Name { get; } public IChangeToken GetChangeToken()
{
return _reloadToken;
}
public void OnReload()
{
var previousToken = System.Threading.Interlocked.Exchange(ref _reloadToken, new ConfigurationReloadToken());
previousToken.OnReload();
}
}

  其中OnReload()方法即触发重新加载,何时触发呢?假如配置的数据源来自某个类的数据:  

    //表示Options的数据来源
public class OptionsSource
{
public static DateTime Time { get; private set; } public OptionsSource(IOptionsChangeTokenSource<DemoOptions> optionsChangeTokenSource)
{
Timer timer = new Timer();
timer.Interval = 10000;//10秒钟刷新一次Time
timer.Elapsed += new ElapsedEventHandler((o, e) =>
{
Time = DateTime.Now; if (optionsChangeTokenSource is MyOptionsChangeTokenSource<DemoOptions> source)
{
source.OnReload();//触发MyOptionsChangeTokenSource<>从而重新加载Options
}
});
timer.Start();//启动
}
}

  接着在Startup中注册Options:  

    public void ConfigureServices(IServiceCollection services)
{
//注册Options
services.Configure<DemoOptions>(options =>
{
options.Time = OptionsSource.Time;
});
services.AddSingleton<OptionsSource>();//数据源
services.AddSingleton<IOptionsChangeTokenSource<DemoOptions>>(new MyOptionsChangeTokenSource<DemoOptions>("")); //其他代码
} // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
app.ApplicationServices.GetRequiredService<OptionsSource>();//获取一次,启动定时器 //其他代码
}

  接下来可以使用IOptionsMonitor<>获取Options也会有重新加载的效果了。

  上面的例子中,数据源来自某个类,但是开发过程中,我们的Options中的数据往往来自IConfiguration配置中,这时就更简单了,框架已经给我们准备好了一个ConfigurationChangeTokenSource<>类,当我们使用IConfiguration来配置Options时会自动注入这个类,我们当然也可以手动注入,意思就是说,当对应的IConfiguration中的数据发生改变时,它会触发清除对应的IOptionsMonitorCache<>缓存从而导致重新加载,比如:

  appsettings.json中有下面的json片段:  

  {
"Demo": {
"Value": 1
}
}

  程序启动时会自动加载appsettings.json文件中的配置到IConfiguration中,所以我们可以直接从IConfiguration配置Options:  

    public void ConfigureServices(IServiceCollection services)
{
//方式一:
//这个会添加ConfigurationChangeTokenSource<>类,程序启动后,修改appsettings.json会触发Options的重新加载
services.Configure<DemoOptions>(Configuration.GetSection("Demo")); //方式二:
//这种方式不会添加ConfigurationChangeTokenSource<>类,但是可以手动添加
services.Configure<DemoOptions>(options =>
{
Configuration.GetSection("Demo").Bind(options);
});
services.AddSingleton<IOptionsChangeTokenSource<DemoOptions>>(new ConfigurationChangeTokenSource<DemoOptions>(Options.DefaultName, Configuration.GetSection("Demo"))); //其他代码
}

  如上所述,添加Options的Configure方法有很多,但是只用 OptionsConfigurationServiceCollectionExtensions 类中的Configure方法才会自动添加ConfigurationChangeTokenSource<>类,即Configure方法参数中有IConfiguration参数。

  结语

  Options的重新加载,如果看看源码就会很清晰,但是更多的,希望在读取Options的时候多注意一下吧:

  1、如果配置永远不会发生改变,或者改变或需要重启才能生效(这种配置往往是在启动阶段用到),那么尽量使用IOptions<>

  2、如果要实现配置修改后会自动加载Options,推荐使用OptionsMonitor<>,但是注意,要自行实现何时需要重新加载,其次可以使用IOptionsSnapshot<>,因为它是一个Scoped作用域,最次是IOptionsFactory<>,每次都是重新创建可能会导致一些性能的损失

.net core中的Options重新加载机制的更多相关文章

  1. Android之Android apk动态加载机制的研究(二):资源加载和activity生命周期管理

    转载请注明出处:http://blog.csdn.net/singwhatiwanna/article/details/23387079 (来自singwhatiwanna的csdn博客) 前言 为了 ...

  2. EF如何操作内存中的数据以及加载相关联表的数据:延迟加载、贪婪加载、显示加载

    之前的EF Code First系列讲了那么多如何配置实体和数据库表的关系,显然配置只是辅助,使用EF操作数据库才是每天开发中都需要用的,这个系列讲讲如何使用EF操作数据库.老版本的EF主要是通过Ob ...

  3. .Net Core 程序集管理说明(加载)

    .NET CORE 的程序集加载管理和以前的 .NET 发生了很大的变化, 在 .NET CORE 里, 程序集的加载, 依赖了 xx.deps.json 文件, deps.json 文件里,定义了程 ...

  4. imagesLoaded – 检测网页中的图片是否加载

    imagesLoaded 是一个用于来检测网页中的图片是否载入完成的 JavaScript 工具库.支持回调的获取图片加载的进度,还可以绑定自定义事件.可以结合 jQuery.RequireJS 使用 ...

  5. 在Unity3D的网络游戏中实现资源动态加载

    用Unity3D制作基于web的网络游戏,不可避免的会用到一个技术-资源动态加载.比如想加载一个大场景的资源,不应该在游戏的开始让用户长时间等待全部资源的加载完毕.应该优先加载用户附近的场景资源,在游 ...

  6. JVM中java类的加载时机(转载:http://blog.csdn.net/chenleixing/article/details/47099725)

    Java虚拟机把描述类的数据从Class文件加载到内存,并对数据进行校验.转换解析和初始化,最终形成可以被虚拟机直接使用的Java类型,这就是虚拟机的加载机制.类从被加载到虚拟机内存中开始,到卸载出内 ...

  7. 动态加载JS过程中如何判断JS加载完成

    在正常的加载过程中,js文件的加载是同步的,也就是说在js加载的过程中,浏览器会阻塞接下来的内容的解析.这时候,动态加载便显得尤为重要了,由于它是异步加载,因此,它可以在后台自动下载,并不会妨碍其它内 ...

  8. MapXtreme在asp.net中的使用之加载地图(转)

    MapXtreme在asp.net中的使用之加载地图(转) Posted on 2010-05-04 19:44 Happy Coding 阅读(669) 评论(0) 编辑 收藏 1.地图保存在本地的 ...

  9. Qt中如何 编写插件 加载插件 卸载插件

    Qt中如何 编写插件 加载插件 卸载插件是本文要介绍的内容.Qt提供了一个类QPluginLoader来加载静态库和动态库,在Qt中,Qt把动态库和静态库都看成是一个插件,使用QPluginLoade ...

随机推荐

  1. 分布式系统为什么不用自增id,要用雪花算法生成id???

    1.为什么数据库id自增和uuid不适合分布式id id自增:当数据量庞大时,在数据库分库分表后,数据库自增id不能满足唯一id来标识数据:因为每个表都按自己节奏自增,会造成id冲突,无法满足需求.  ...

  2. JSP 文字乱码、${}引用无效

    问题: 代码:<form action="/test/requestPost.do" method="post"> <input type=& ...

  3. kubernetes list/watch设计原理

    overview kubernetes的设计里面大致上分为3部分: API驱动型的特点 (API-driven) 控制循环(control loops)与 条件触发 (Level Trigger) A ...

  4. Git忽略提交规则 .gitignore文件

    在使用Git的过程中,我们喜欢有的文件比如日志,临时文件,编译的中间文件等不要提交到代码仓库,这时就要设置相应的忽略规则,来忽略这些文件的提交.简单来说一个场景:在你使用git add .的时候,遇到 ...

  5. 【模型推理】量化实现分享二:详解 KL 对称量化算法实现

      欢迎关注我的公众号 [极智视界],回复001获取Google编程规范   O_o   >_<   o_O   O_o   ~_~   o_O   大家好,我是极智视界,本文剖析一下 K ...

  6. Python pyecharts绘制漏斗图

    一.pyecharts绘制漏斗图方法简介 funnel.add()方法简介add(name, attr, value, funnel_sort="ascending", funne ...

  7. C语言程序设计:二分查找(折半查找)

    目录 C语言程序设计:二分查找(折半查找) 1.什么是二分查找 2.二分查找的优点 3.二分查找的缺点 4.二分查找原理 5.源代码实现 6.后话 C语言程序设计:二分查找(折半查找) 1.什么是二分 ...

  8. Linux 三剑客之grep

    目录 Linux 三剑客之grep 搭配命令-find 三剑客之grep: 正则表达式: Linux 三剑客之grep 搭配命令-find find命令是根据文件的名称或者属性查找文件,并不会显示文件 ...

  9. CF628B New Skateboard 题解

    Content 有一个长度为 \(n\) 的数字串 \(s\),求出有多少个子串能够被 \(4\) 整除. 数据范围:\(1\leqslant n\leqslant 3\times 10^5\). S ...

  10. .NET Core基础篇之:白话管道中间件

    在.Net Core中,管道往往伴随着请求一起出现.客户端发起Http请求,服务端去响应这个请求,之间的过程都在管道内进行. 举一个生活中比较常见的例子:旅游景区. 我们都知道,有些景区大门离景区很远 ...