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

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

前面我们讲到 IOptions 和 IOptionsSnapshot,他们两个最大的区别便是前者注册的是单例模式,后者注册的是 Scope 模式。而 IOptionsMonitor 则要求配置源必须是可监听的,用来实现 Options 实例的自动更新,并对外提供了 OnChage 事件,给我们更多的控制权。

目录

  1. IOptionsMonitor
  2. OptionsMonitor源码探索
  3. ConfigurationChangeTokenSource
  4. 示例

IOptionsMonitor

对于 IOptionsMonitor 我们接触的较少,它的定义如下:

public interface IOptionsMonitor<out TOptions> { TOptions CurrentValue { get; } TOptions Get(string name); IDisposable OnChange(Action<TOptions, string> listener); }

AddOptions扩展方法中,可以看到它的默认实现为 OptionsMonitor

public static IServiceCollection AddOptions(this IServiceCollection services) { services.TryAdd(ServiceDescriptor.Singleton(typeof(IOptionsMonitor<>), typeof(OptionsMonitor<>))); services.TryAdd(ServiceDescriptor.Transient(typeof(IOptionsFactory<>), typeof(OptionsFactory<>))); services.TryAdd(ServiceDescriptor.Singleton(typeof(IOptionsMonitorCache<>), typeof(OptionsCache<>))); }

OptionsMonitor源码探索

OptionsMonitor通过IOptionsChangeTokenSource来实现事件的监听,具体如下:

public class OptionsMonitor<TOptions> : IOptionsMonitor<TOptions> where TOptions : class, new() { private readonly IOptionsMonitorCache<TOptions> _cache; private readonly IOptionsFactory<TOptions> _factory; private readonly IEnumerable<IOptionsChangeTokenSource<TOptions>> _sources; internal event Action<TOptions, string> _onChange; public OptionsMonitor(IOptionsFactory<TOptions> factory, IEnumerable<IOptionsChangeTokenSource<TOptions>> sources, IOptionsMonitorCache<TOptions> cache) { _factory = factory; _sources = sources; _cache = cache; foreach (var source in _sources) { ChangeToken.OnChange<string>(() => source.GetChangeToken(), (name) => InvokeChanged(name), source.Name); } } public TOptions CurrentValue => Get(Options.DefaultName); public virtual TOptions Get(string name) { name = name ?? Options.DefaultName; return _cache.GetOrAdd(name, () => _factory.Create(name)); } public IDisposable OnChange(Action<TOptions, string> listener) { ... } private void InvokeChanged(string name) { ... } }

首先看构造函数中的三个参数,其中 IOptionsFactory<>在上一章已讲过,而IOptionsChangeTokenSource则在 第一章 中介绍过,通过IConfiguration进行配置的 Options,会注册该类型的实现,用来实现对配置源的监听:

public static IServiceCollection Configure<TOptions>(this IServiceCollection services, string name, IConfiguration config) where TOptions : class { ... services.AddSingleton<IOptionsChangeTokenSource<TOptions>>(new ConfigurationChangeTokenSource<TOptions>(name, config)); ... }

IOptionsChangeTokenSource 的定义如下:

public interface IOptionsChangeTokenSource<out TOptions> { IChangeToken GetChangeToken(); string Name { get; } }

OptionsMonitor的构造函数中,通过调用其GetChangeToken方法,获取到 ChangeToken ,在 InvokeChanged 完成 *_onChange* 事件的调用:

private void InvokeChanged(string name) { name = name ?? Options.DefaultName; _cache.TryRemove(name); var options = Get(name); if (_onChange != null) { _onChange.Invoke(options, name); } }

而对外暴露的OnChange方法,方便我们注册自己的逻辑:

public IDisposable OnChange(Action<TOptions> listener) { var disposable = new ChangeTrackerDisposable(this, listener); _onChange += disposable.OnChange; return disposable; }

这里又使用了一个 ChangeTrackerDisposable 的包装类,用来实现事件的注销:

internal class ChangeTrackerDisposable : IDisposable { private readonly Action<TOptions> _listener; private readonly OptionsMonitor<TOptions> _monitor; public ChangeTrackerDisposable(OptionsMonitor<TOptions> monitor, Action<TOptions> listener) { _listener = listener; _monitor = monitor; } public void OnChange(TOptions options) => _listener.Invoke(options); public void Dispose() => _monitor._onChange -= OnChange; }

构造函数的最后一个参数IOptionsMonitorCache的默认实现便是 上一章 中介绍的 OptionsCache

ConfigurationChangeTokenSource

IConfigurationChangeTokenSource 的默认实现类是 ConfigurationChangeTokenSource :

public class ConfigurationChangeTokenSource<TOptions> : IOptionsChangeTokenSource<TOptions> { private IConfiguration _config; public ConfigurationChangeTokenSource(IConfiguration config) : this(Options.DefaultName, config) { } public ConfigurationChangeTokenSource(string name, IConfiguration config) { if (config == null) { throw new ArgumentNullException(nameof(config)); } _config = config; } public string Name { get; } public IChangeToken GetChangeToken() { return _config.GetReloadToken(); } }

上面用到的 ChangeToken 便是通过构造函数接受的IConfiguration类型的参数来获取的:

public interface IConfiguration
{
    ...

    IChangeToken GetReloadToken(); ... }

因此要想使用IOptionsMonitor,通常要使用IConfiguration来注册才可以,当然,你也可以实现自己的 ConfigurationChangeTokenSource

示例

下面简单演示一下IOptionsMonitor的使用:

首先创建一个控制台程序,添加appsettings.json

{
  "Name": "bob"
}

然后修改Program.cs如下:

public class MyOptions
{
    public string Name { get; set; } } class Program { private IOptionsMonitor<MyOptions> _options; public Program() { var configuration = new ConfigurationBuilder() .SetBasePath(Directory.GetCurrentDirectory()) .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true) .Build(); var serviceCollection = new ServiceCollection(); serviceCollection.Configure<MyOptions>(configuration); var serviceProvider = serviceCollection.BuildServiceProvider(); _options = serviceProvider.GetRequiredService<IOptionsMonitor<MyOptions>>(); } public static void Main(string[] args) { new Program().Execute(args); } public void Execute(string[] args) { Console.WriteLine(_options.CurrentValue.Name); _options.OnChange(_ => Console.WriteLine(_.Name)); Console.ReadKey(); } }

我们手动修改配置文件,便会触发OnChange事件。

附示例代码地址:https://github.com/RainingNight/AspNetCoreSample/tree/master/src/OptionsSample 。

总结

本章介绍了 IOptionsMonitor 的实现:通过 IConfiguration 所提供的 ChangeToken ,来注册监听事件,对其 CurrentValue 进行更新。到此,ASP.NET Core 中的 Options 源码也就分析完了,其本身比较简单,并没有太多东西。更具体的可以去 Github 上看完整的源码。

 

转载于:https://www.cnblogs.com/fuyouchen/p/9578613.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值