前言
IOptionsMonitor 是一種單一示例服務,可隨時檢索當前選項值,這在單一實例依賴項中尤爲有用。IOptionsMonitor用於檢索選項並管理TOption實例的選項通知, IOptionsMonitor
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實現監聽事件this
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 的代碼片斷:code
public interface IOptionsChangeTokenSource<out TOptions> { IChangeToken GetChangeToken(); string Name { get; } }
在OptionsMonitor的構造函數中,經過調用其GetChangeToken方法,獲取到 ChangeToken ,在 InvokeChanged 完成 *_onChange* 事件的調用:orm
private void InvokeChanged(string name) { name = name ?? Options.DefaultName; _cache.TryRemove(name); var options = Get(name); if (_onChange != null) { _onChange.Invoke(options, name); } }
對外暴露OnChange方法,方便咱們添加本身的業務邏輯blog
public IDisposable OnChange(Action<TOptions, string> listener) { var disposable = new ChangeTrackerDisposable(this, listener); _onChange += disposable.OnChange; return disposable; }
經過ChangeTrackerDisposable進行事件的註銷token
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事件事件