前面我们讲到 IOptions 和 IOptionsSnapshot,他们两个最大的区别便是前者注册的是单例模式,后者注册的是 Scope 模式。而 IOptionsMonitor 则要求配置源必须是可监听的,用来实现 Options 实例的自动更新,并对外提供了 OnChage 事件,给我们更多的控制权。
IOptionsMonitor
public interface IOptionsMonitor<out TOptions>
{TOptions CurrentValue { get; }
TOptions Get(string name);
IDisposable OnChange(Action<TOptions> listener);
}
IOptionsMonitor 与 IOptionsSnapshot 类似,都提供了根据指定名称获取 Options
的功能,并多了一个 OnChange
方法。而它的默认实现者是 OptionsMonitor。
public static IServiceCollection AddOptions(this IServiceCollection services){...services.TryAdd(ServiceDescriptor.Singleton(typeof(IOptions<>), typeof(OptionsManager<>)));services.TryAdd(ServiceDescriptor.Scoped(typeof(IOptionsSnapshot<>), typeof(OptionsManager<>)));services.TryAdd(ServiceDescriptor.Singleton(typeof(IOptionsMonitor<>), typeof(OptionsMonitor<>)));...
}
OptionsMonitor
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> _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(() => source.GetChangeToken(),() => InvokeChanged());}}
public TOptions CurrentValue { get => Get(Options.DefaultName); }
public virtual TOptions Get(string name) => _cache.GetOrAdd(name, () => _factory.Create(name));
private void InvokeChanged() {...}
public IDisposable OnChange(Action<TOptions> listener) {...}
}
首先看构造函数中的三个参数,其中 IOptionsFactory<>
和 IOptionsMonitorCache<>
在上一章已讲过,而第二个 IOptionsChangeTokenSource<>
则是用来实现对配置源的监听:
public interface IOptionsChangeTokenSource<out TOptions>
{
IChangeToken GetChangeToken();
string Name { get; }
}
通过 GetChangeToken
获取 ChangeToken , 从而注册其 InvokeChanged
方法:
private void InvokeChanged(){
_cache.TryRemove(Options.DefaultName);
var options = CurrentValue;
if (_onChange != null){_onChange.Invoke(options);}
}
首先移除 Options 缓存,再通过 IOptionsFactory 重新创建 Options,然后调用 _onChange
事件。
而 OnChange 方法则用来注册 _onChange
事件:
public IDisposable OnChange(Action<TOptions> listener){
var disposable = new ChangeTrackerDisposable(this, listener);_onChange += disposable.OnChange;
return disposable;
}
这里又使用了一个 OptionsMonitore 的包装类,用来实现事件的注销:
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;
}
再去看一下 IConfigurationChangeTokenSource 的实现
ConfigurationChangeTokenSource
IConfigurationChangeTokenSource 的默认实现类便是 ConfigurationChangeTokenSource<>
:
public static IServiceCollection Configure<TOptions>(this IServiceCollection services, string name, IConfiguration config)
where TOptions : class{...services.AddSingleton<IOptionsChangeTokenSource<TOptions>>(new ConfigurationChangeTokenSource<TOptions>(name, config));...
}
ConfigurationChangeTokenSource 构造函数要求传入 IConfiguration,其而 ChangeToken
的获取便是通过 IConfiguration 来得到的:
public interface IConfiguration{... IChangeToken GetReloadToken();...
}
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();}
}
因此要想使用 IOptionsMonitor,必须要使用 IConfiguration 进行注册才可以,当然,你也可以实现自己的 ChangeToken
。
总结
本章介绍了 IOptionsMonitor
的实现:通过 IConfiguration 所提供的 ChangeToken
,来注册监听事件,对其 CurrentValue
进行更新。到此,ASP.NET Core 中的 Options 源码也就分析完了,其本身比较简单,并没有太多东西。更具体的可以去 Github 上看完整的源码,而 .NET Core 才刚刚发布了 Preview2
版本,随时可能会有大的变化,而我也会保持更新,通过观察每次的变化,也能学到更多的编程思想,也是一件很快乐的事。
相关文章:
ASP.NET Core 源码学习之 Options[1]:Configure
ASP.NET Core 源码学习之 Options[2]:IOptions
ASP.NET Core 源码学习之 Options[3]:IOptionsSnapshot
ASP.NET Core MVC 源码学习:详解 Action 的匹配
asp.net core源码飘香:从Hosting开始
asp.net core源码飘香:Configuration组件
asp.net core源码飘香:Options组件
asp.net core源码飘香:Logging组件
原文地址:http://www.cnblogs.com/RainingNight/p/strongly-typed-options-ioptions-monitor-in-asp-net-core.html
.NET社区新闻,深度好文,微信中搜索dotNET跨平台或扫描二维码关注