ASP.NET Core 选项模式源码学习Options IOptionsMonitor(三)
前言
ioptionsmonitor 是一种单一示例服务,可随时检索当前选项值,这在单一实例依赖项中尤其有用。ioptionsmonitor用于检索选项并管理toption实例的选项通知, ioptionsmonitor
optionsmonitor通过ioptionschangetokensource实现监听事件 ioptionschangetokensource 的代码片段: 在optionsmonitor的构造函数中,通过调用其getchangetoken方法,获取到 changetoken ,在 invokechanged 完成 *_onchange* 事件的调用: 对外暴露onchange方法,方便我们添加自己的业务逻辑 通过changetrackerdisposable进行事件的注销 configurationchangetokensource实现ioptionschangetokensource接口 现在我们每次修改配置文件,便会触发onchange事件
ioptionsmonitor
public interface ioptionsmonitor<out toptions>
{
/// <summary>
/// 返回具有 defaultname 的当前 toptions 实例。
/// </summary>
toptions currentvalue { get; }
/// <summary>
/// 返回具有给定名称的已配置的 toptions 实例。
/// </summary>
toptions get(string name);
/// <summary>
/// 注册一个要在命名 toptions 更改时调用的侦听器。
/// </summary>
idisposable onchange(action<toptions, string> listener);
}
optionsmonitor
public class optionsmonitor<toptions> : ioptionsmonitor<toptions>, idisposable where toptions : class, new()
{
private readonly ioptionsmonitorcache<toptions> _cache;
private readonly ioptionsfactory<toptions> _factory;
private readonly ienumerable<ioptionschangetokensource<toptions>> _sources;
private readonly list<idisposable> _registrations = new list<idisposable>();
internal event action<toptions, string> _onchange;
/// <summary>
/// constructor.
/// </summary>
/// <param name="factory">the factory to use to create options.</param>
/// <param name="sources">the sources used to listen for changes to the options instance.</param>
/// <param name="cache">the cache used to store options.</param>
public optionsmonitor(ioptionsfactory<toptions> factory, ienumerable<ioptionschangetokensource<toptions>> sources, ioptionsmonitorcache<toptions> cache)
{
_factory = factory;
_sources = sources;
_cache = cache;
foreach (var source in _sources)
{
var registration = changetoken.onchange(
() => source.getchangetoken(),
(name) => invokechanged(name),
source.name);
_registrations.add(registration);
}
}
private void invokechanged(string name)
{
name = name ?? options.defaultname;
_cache.tryremove(name);
var options = get(name);
if (_onchange != null)
{
_onchange.invoke(options, name);
}
}
/// <summary>
/// the present value of the options.
/// </summary>
public toptions currentvalue
{
get => get(options.defaultname);
}
/// <summary>
/// returns a configured <typeparamref name="toptions"/> instance with the given <paramref name="name"/>.
/// </summary>
public virtual toptions get(string name)
{
name = name ?? options.defaultname;
return _cache.getoradd(name, () => _factory.create(name));
}
/// <summary>
/// registers a listener to be called whenever <typeparamref name="toptions"/> changes.
/// </summary>
/// <param name="listener">the action to be invoked when <typeparamref name="toptions"/> has changed.</param>
/// <returns>an <see cref="idisposable"/> which should be disposed to stop listening for changes.</returns>
public idisposable onchange(action<toptions, string> listener)
{
var disposable = new changetrackerdisposable(this, listener);
_onchange += disposable.onchange;
return disposable;
}
/// <summary>
/// removes all change registration subscriptions.
/// </summary>
public void dispose()
{
// remove all subscriptions to the change tokens
foreach (var registration in _registrations)
{
registration.dispose();
}
_registrations.clear();
}
internal class changetrackerdisposable : idisposable
{
private readonly action<toptions, string> _listener;
private readonly optionsmonitor<toptions> _monitor;
public changetrackerdisposable(optionsmonitor<toptions> monitor, action<toptions, string> listener)
{
_listener = listener;
_monitor = monitor;
}
public void onchange(toptions options, string name) => _listener.invoke(options, name);
public void dispose() => _monitor._onchange -= onchange;
}
}
public interface ioptionschangetokensource<out toptions>
{
ichangetoken getchangetoken();
string name { get; }
}
private void invokechanged(string name)
{
name = name ?? options.defaultname;
_cache.tryremove(name);
var options = get(name);
if (_onchange != null)
{
_onchange.invoke(options, name);
}
}
public idisposable onchange(action<toptions, string> listener)
{
var disposable = new changetrackerdisposable(this, listener);
_onchange += disposable.onchange;
return disposable;
}
internal class changetrackerdisposable : idisposable
{
private readonly action<toptions, string> _listener;
private readonly optionsmonitor<toptions> _monitor;
public changetrackerdisposable(optionsmonitor<toptions> monitor, action<toptions, string> listener)
{
_listener = listener;
_monitor = monitor;
}
public void onchange(toptions options, string name) => _listener.invoke(options, name);
public void dispose() => _monitor._onchange -= onchange;
}
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;
name = name ?? options.defaultname;
}
public string name { get; }
public ichangetoken getchangetoken()
{
return _config.getreloadtoken();
}
}
示例
public class weatherforecastcontroller : controllerbase
{
private readonly ilogger<weatherforecastcontroller> _logger;
private readonly ioptionsmonitor<myoptions> _options;
public weatherforecastcontroller(ioptionsmonitor<myoptions> options, ilogger<weatherforecastcontroller> logger)
{
_options = options;
_logger = logger;
}
[httpget]
public okobjectresult get() {
_options.onchange(_=>_logger.logwarning(_options.currentvalue.name));
return ok(string.format("name:{0},url:{1}", _options.currentvalue.name,_options.currentvalue.url));
}
}
推荐阅读
-
ASP.NET Core 选项模式源码学习Options IOptions(二)
-
ASP.NET Core 选项模式源码学习Options IOptionsMonitor(三)
-
ASP.NET Core 选项模式源码学习Options Configure(一)
-
(13)ASP.NET Core 中的选项模式(Options)
-
ASP.NET Core 选项模式源码学习Options IOptions(二)
-
ASP.NET Core 选项模式源码学习Options IOptionsMonitor(三)
-
ASP.NET Core 选项模式源码学习Options Configure(一)
-
(13)ASP.NET Core 中的选项模式(Options)