前言

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事件

ASP.NET Core 选项模式源码学习Options IOptionsMonitor(三)_IOptionsMonitor