前言
IOptionsMonitor 是一种单一示例服务, 可随时检索当前选项值, 这在单一实例依赖项中尤其有用. IOptionsMonitor 用于检索选项并管理 TOption 实例的选项通知, IOptionsMonitor 支持以下方案:
更改通知
命名选项
可重载配置
选择性选项失效 (IOptionsMonitorCache)
- 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
OptionsMonitor 通过 IOptionsChangeTokenSource 实现监听事件
- 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;
- }
- }
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, string> listener)
- {
- var disposable = new ChangeTrackerDisposable(this, listener);
- _onChange += disposable.OnChange;
- return disposable;
- }
通过 ChangeTrackerDisposable 进行事件的注销
- 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
ConfigurationChangeTokenSource 实现 IOptionsChangeTokenSource 接口
- 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));
- }
- }
现在我们每次修改配置文件, 便会触发 OnChange 事件
来源: https://www.cnblogs.com/yyfh/p/12047289.html