前言
IOptionsMonitor 是一种单一示例服务,可随时检索当前选项值,这在单一实例依赖项中尤其有用。IOptionsMonitor用于检索选项并管理TOption实例的选项通知, IOptionsMonitor
- 更改通知
- 命名选项
- 可重载配置
- 选择性选项失效 (IOptionsMonitorCache
IOptionsMonitor
public interface IOptionsMonitor{ ////// 返回具有 DefaultName 的当前 TOptions 实例。 ///TOptions CurrentValue { get; } ////// 返回具有给定名称的已配置的 TOptions 实例。 ///TOptions Get(string name); ////// 注册一个要在命名 TOptions 更改时调用的侦听器。 ///IDisposable OnChange(Actionlistener); }
OptionsMonitor
OptionsMonitor通过IOptionsChangeTokenSource实现监听事件
public class OptionsMonitor: IOptionsMonitor, IDisposable where TOptions : class, new() { private readonly IOptionsMonitorCache_cache; private readonly IOptionsFactory_factory; private readonly IEnumerable<IOptionsChangeTokenSource> _sources; private readonly List_registrations = new List(); internal event Action_onChange; ////// Constructor. //////The factory to use to create options.///The sources used to listen for changes to the options instance.///The cache used to store options.public OptionsMonitor(IOptionsFactoryfactory, IEnumerable<IOptionsChangeTokenSource> sources, IOptionsMonitorCachecache) { _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); } } ////// The present value of the options. ///public TOptions CurrentValue { get => Get(Options.DefaultName); } ////// Returns a configuredinstance with the given. ///public virtual TOptions Get(string name) { name = name ?? Options.DefaultName; return _cache.GetOrAdd(name, () => _factory.Create(name)); } ////// Registers a listener to be called wheneverchanges. //////The action to be invoked whenhas changed.///Anwhich should be disposed to stop listening for changes.public IDisposable OnChange(Actionlistener) { var disposable = new ChangeTrackerDisposable(this, listener); _onChange += disposable.OnChange; return disposable; } ////// Removes all change registration subscriptions. ///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_listener; private readonly OptionsMonitor_monitor; public ChangeTrackerDisposable(OptionsMonitormonitor, Actionlistener) { _listener = listener; _monitor = monitor; } public void OnChange(TOptions options, string name) => _listener.Invoke(options, name); public void Dispose() => _monitor._onChange -= OnChange; } }
IOptionsChangeTokenSource 的代码片段:
public interface IOptionsChangeTokenSource{ 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(Actionlistener) { var disposable = new ChangeTrackerDisposable(this, listener); _onChange += disposable.OnChange; return disposable; }
通过ChangeTrackerDisposable进行事件的注销
internal class ChangeTrackerDisposable : IDisposable { private readonly Action_listener; private readonly OptionsMonitor_monitor; public ChangeTrackerDisposable(OptionsMonitormonitor, Actionlistener) { _listener = listener; _monitor = monitor; } public void OnChange(TOptions options, string name) => _listener.Invoke(options, name); public void Dispose() => _monitor._onChange -= OnChange; }
ConfigurationChangeTokenSource
ConfigurationChangeTokenSource实现IOptionsChangeTokenSource接口
public class ConfigurationChangeTokenSource: IOptionsChangeTokenSource{ 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_logger; private readonly IOptionsMonitor_options; public WeatherForecastController(IOptionsMonitoroptions, ILoggerlogger) { _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)); } }
现在我们每次修改配置文件,便会触发OnChange事件