·您现在的位置: 云翼网络 >> 文章中心 >> 网站建设 >> 网站建设开发 >> ASP.NET网站开发 >> [Asp.net5]Options-配置文件(2)

[Asp.net5]Options-配置文件(2)

作者:佚名      ASP.NET网站开发编辑:admin      更新时间:2022-07-23

很久之前写过一篇介绍Options的文章,2016年再打开发现很多变化。增加了新类,增加OptionMonitor相关的类。今天就对于这个现在所谓的新版本进行介绍。

老版本的传送门([asp.net 5] Options-配置文件之后昂的配置)。

首先上一个图:

*绿线是继承关系,蓝线是关联关系。

我们把上面切成2大部分。

Option部分

这部分分为俩部分,第一部分直接创建Options,该部分通过Options静态类创建一个OptionsWrapper类,之后将(IOptions,OptionsWrapper)进行注入。这部分是DI的实体注入,很简单,没有什么可说的,此处应用非常常见的“工厂模式”。

第二部分是将(IOptions,OptionsManager)进行注入。我们OptionsManager会使用IEnumerable<IConfigureOptions<TOptions>>作为参数,而内部返回的是OptionsCache类型的对象,此处应用非常常见的“代理模式

    internal class OptionsCache<TOptions> where TOptions : class, new()
    {
        PRivate readonly Func<TOptions> _createCache;
        private object _cacheLock = new object();
        private bool _cacheInitialized;
        private TOptions _options;
        private IEnumerable<IConfigureOptions<TOptions>> _setups;

        public OptionsCache(IEnumerable<IConfigureOptions<TOptions>> setups)
        {
            _setups = setups;
            _createCache = CreateOptions;
        }

        private TOptions CreateOptions()
        {
            var result = new TOptions();
            if (_setups != null)
            {
                foreach (var setup in _setups)
                {
                    setup.Configure(result);
                }
            }
            return result;
        }

        public virtual TOptions Value
        {
            get
            {
                return LazyInitializer.EnsureInitialized(
                    ref _options,
                    ref _cacheInitialized,
                    ref _cacheLock,
                    _createCache);
            }
        }
    }
OptionsCache

此处附录OptionsCache代码,里面(IConfigureOptions,ConfigureOptions)已经进行注入了。而ConfigureOptions代码如下:

    public class ConfigureOptions<TOptions> : IConfigureOptions<TOptions> where TOptions : class
    {
        public ConfigureOptions(Action<TOptions> action)
        {
            if (action == null)
            {
                throw new ArgumentNullException(nameof(action));
            }

            Action = action;
        }

        public Action<TOptions> Action { get; private set; }

        public virtual void Configure(TOptions options)
        {
            if (options == null)
            {
                throw new ArgumentNullException(nameof(options));
            }

            Action.Invoke(options);
        }
    }
ConfigureOptions

而ConfigureOptions实际上只是对Action<TOptions>的封装吧了(这里是不是可以理解为适配器)。

*为什么要传递Action<T>进行配置?我的理解是因为延时性延时的概念就是,你做的修改不是立马生效,以至于配置的时候,我们都不用考虑先后顺序。

OptionsMonitor部分

OptionsMonitor是对Options的监视器。我决定这部分好像一个调度者模式??

IOptionsChangeTokenSource

OptionsMonitor代码如下:

    public class OptionsMonitor<TOptions> : IOptionsMonitor<TOptions> where TOptions : class, new()
    {
        private OptionsCache<TOptions> _optionsCache;
        private readonly IEnumerable<IConfigureOptions<TOptions>> _setups;
        private readonly IEnumerable<IOptionsChangeTokenSource<TOptions>> _sources;

        public OptionsMonitor(IEnumerable<IConfigureOptions<TOptions>> setups, IEnumerable<IOptionsChangeTokenSource<TOptions>> sources)
        {
            _sources = sources;
            _setups = setups;
            _optionsCache = new OptionsCache<TOptions>(setups);
        }

        public TOptions CurrentValue
        {
            get
            {
                return _optionsCache.Value;
            }
        }

        public IDisposable OnChange(Action<TOptions> listener)
        {
            var disposable = new ChangeTrackerDisposable();
            foreach (var source in _sources)
            {

                Action<object> callback = null;
                IDisposable previousSubscription = null;
                callback = (s) =>
                {
                    // The order here is important. We need to take the token and then apply our changes BEFORE
                    // registering. This prevents us from possible having two change updates to process concurrently.
                    //
                    // If the token changes after we take the token, then we'll process the update immediately upon
                    // registering the callback.
                    var token = source.GetChangeToken();

                    // Recompute the options before calling the watchers
                    _optionsCache = new OptionsCache<TOptions>(_setups);
                    listener(_optionsCache.Value);

                    // Remove the old callback after its been fired
                    var nextSubscription = token.RegisterChangeCallback(callback, s);
                    disposable.Disposables.Add(nextSubscription);
                    disposable.Disposables.Remove(previousSubscription);
                    previousSubscription = nextSubscription;
                };

                previousSubscription = source.GetChangeToken().RegisterChangeCallback(callback, state: null);
                disposable.Disposables.Add(previousSubscription);
            }
            return disposable;
        }
    }
OptionsMonitor

通过IOptionsChangeTokenSource的IChangeToken对象发出更改请求,之后Action<TOptions> listener进行数据更改。

Onchange方法,实现上就是每次调用都会创建一个新的IDisposable(ChangeTrackerDisposable),如此而已。