当前位置: 移动技术网 > IT编程>开发语言>.net > ASP.NET Core 选项模式源码学习Options IOptionsMonitor(三)

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

2019年12月16日  | 移动技术网IT编程  | 我要评论

hopemv,僵尸卖铁,雁来红是什么花

前言

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

image

如对本文有疑问,请在下面进行留言讨论,广大热心网友会与你互动!! 点击进行留言回复

相关文章:

验证码:
移动技术网