建设通网,网站推广优化的公司,建筑行业征信查询平台官网,oa系统怎么用前言.NetCore中提供的选项框架#xff0c;我把其理解为配置组#xff0c;主要是将服务中可供配置的项提取出来#xff0c;封装成一个类型#xff1b;从而服务可根据应用场景进行相关配置项的设置来满足需求#xff0c;其中使用了依赖注入的形式#xff0c;使得更加简单、… 前言.NetCore中提供的选项框架我把其理解为配置组主要是将服务中可供配置的项提取出来封装成一个类型从而服务可根据应用场景进行相关配置项的设置来满足需求其中使用了依赖注入的形式使得更加简单、便捷另外和配置(Configuration)系统的无缝结合使得服务更加灵活而对于Options我们经常在注册服务中用到相信只要接触过.NetCore中的小伙伴都知道在注册服务的时候经常在参数中进行Options的配置(如下图)可以直接的说没有Options的服务不是好服务~~~正文Options模型中主要有三个核心接口类型IOptionTOptions、IOptionsSnapshotTOptions、IOptionsMonitorTOptions这里的TOptions就是指针对服务提取出来的配置项封装的类型以下分别看看三个核心类型定义了什么IOptionTOptionsnamespace Microsoft.Extensions.Options
{// 这里TOptions 做了一个约束必须有无参构造函数public interface IOptionsout TOptions where TOptions : class, new(){// 这里是通过属性的方式定义TOptions TOptions Value{get;}}
}
IOptionsSnapshotTOptionsnamespace Microsoft.Extensions.Options
{ // 这里TOptions 做了一个约束必须有无参构造函数public interface IOptionsSnapshotout TOptions : IOptionsTOptions where TOptions : class, new(){// 通过名字获取 TOptionsTOptions Get(string name);}
}
IOptionsMonitorTOptionsnamespace Microsoft.Extensions.Options
{public interface IOptionsMonitorout TOptions{// 通过属性获取TOptions TOptions CurrentValue{get;}// 通过名称获取TOptionsTOptions Get(string name);// 这是用于监听改变的如果数据设置项改变就会发出通知IDisposable OnChange(ActionTOptions, string listener);}
}通过以上三种类型的定义大概应该知道TOptions有对应的名字根据对应的名字创建或获取TOptions可能会问IOption中是通过属性获取的没有指定名字啊其实是有的只是名字默认为空所以称之为默认Option而对于IOptionsMonitor一看便知它提供了监听改变的功能所以后续如果需要监听改变就可以用这个类型接口除此微软为三个核心类型提供了默认实现IOptionsTOptions和IOptionsSnapshotTOptions的默认实现为OptionsManagerTOptionsIOptionsMonitorTOptions的默认实现为OptionsMonitorTOptions来、走进他们的世界看看是如何实现的(进行简单的注释)OptionsManagerTOptions// 实现了IOptionsTOptions 和IOptionsSnapshotTOptions, 同时也约束了TOptions
public class OptionsManagerTOptions :IOptionsTOptions, IOptionsSnapshotTOptions where TOptions : class, new()
{// 用于专门提供TOptions实例的同时也对TOpions进行相关初始化private readonly IOptionsFactoryTOptions _factory;// 提高性能将对应的TOptions实例进行缓存private readonly OptionsCacheTOptions _cache new OptionsCacheTOptions(); // 构造函数通过依赖注入的形式将factory进行注入public OptionsManager(IOptionsFactoryTOptions factory)
{_factory factory;}// 实现IOptionsTOptions通过属性获取TOptions实例public TOptions Value{get{// 这里通过一个默认的名字获取只是这个名字默认为空所以还是有名字的return Get(Options.DefaultName);}} // 实现IOptionsSnapshotTOptions通过名字获取TOptions public virtual TOptions Get(string name)
{name name ?? Options.DefaultName;// 如果缓存中没有就通过传入的Action进行创建并加入到缓存中return _cache.GetOrAdd(name, () _factory.Create(name));}
}
// 定义的 TOptions默认名称
public static class Options
{public static readonly string DefaultName string.Empty;
}
OptionsMonitorTOptionsnamespace Microsoft.Extensions.Options
{// 实现IOptionsMonitor ,对TOpitons 进行约束public class OptionsMonitorTOptions : IOptionsMonitorTOptions, IDisposable where TOptions : class, new(){// 根据名称缓存TOptions对象private readonly IOptionsMonitorCacheTOptions _cache;// 用于创建TOptions对象private readonly IOptionsFactoryTOptions _factory;// 监听改变的核心private readonly IEnumerableIOptionsChangeTokenSourceTOptions _sources;private readonly ListIDisposable _registrations new ListIDisposable();// 改变触发的事件internal event ActionTOptions, string _onChange;// 构造函数public OptionsMonitor(IOptionsFactoryTOptions factory, IEnumerableIOptionsChangeTokenSourceTOptions sources, IOptionsMonitorCacheTOptions 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);}}// 这个方法是重点如果发生改变移除之前的TOptions对象重新创建一个新TOptionsprivate void InvokeChanged(string name){name name ?? Options.DefaultName;// 根据名字移除TOpitons对象_cache.TryRemove(name);// 重新根据名称获取对象var options Get(name);if (_onChange ! null){_onChange.Invoke(options, name);}}// 获取默认的TOptions对象public TOptions CurrentValue{get Get(Options.DefaultName);}// 根据名称获取TOptions对象如果没有就利用OptionsFactory创建TOptions对象public virtual TOptions Get(string name){name name ?? Options.DefaultName;// return _cache.GetOrAdd(name, () _factory.Create(name));}// 注册监听改变的蝙蝠public IDisposable OnChange(ActionTOptions, string listener){var disposable new ChangeTrackerDisposable(this, listener);_onChange disposable.OnChange;return disposable;}// 取消注册的监听改变回调同时移除对应的监听Tokenpublic void Dispose(){foreach (var registration in _registrations){registration.Dispose();}_registrations.Clear();}// 内部类internal class ChangeTrackerDisposable : IDisposable{private readonly ActionTOptions, string _listener;private readonly OptionsMonitorTOptions _monitor;public ChangeTrackerDisposable(OptionsMonitorTOptions monitor, ActionTOptions, string listener){_listener listener;_monitor monitor;}// 触发改变时调用对应注册的回调public void OnChange(TOptions options, string name) _listener.Invoke(options, name);// Dispose 方法进行解除注册的监听回调public void Dispose() _monitor._onChange - OnChange;}}
}
通过以上代码段得知IOptionsTOptions和IOptionsSnapshotTOptions其实本质都是一样的都是命名的Options统一由IOptionsFactory创建提供TOptions对象而对于IOptionsMonitorTOptions, 监听的本质是通过IOptionsChangeTokenSourceTOptions这个实现每次监听到改变都把对应名称的TOptions对象移除重新创建一个新的TOptions对象从而获取到最新的值其实最终改变通知的本质还是使用IChangeToken进行通知这个可以参考之前配置的监听改变(参考这篇跟我一起学.NetCore之配置变更监听)本想看完以上默认实现就打算进行举例演示了不再深入看代码但是相信看到这的小伙伴肯定会问IOptionsFactoryTOptions是怎么创建出TOptions的 重点都不说差评^_^~~~~~其实我也是这么想的所以继续再看看IOptionsFactoryTOptionsIOptionsFactoryTOptions的默认实现是OptionsFactoryTOptions创建TOptions我理解为三步骤创建对象-加工对象(初始化)-验证(验证合法性)namespace Microsoft.Extensions.Options
{public interface IOptionsFactoryTOptions where TOptions : class, new(){// 接口中定义了一个创建方法用于创建TOptionsTOptions Create(string name);}
}
namespace Microsoft.Extensions.Options
{// 实现IOptionsFactory接口并约束TOptionspublic class OptionsFactoryTOptions : IOptionsFactoryTOptions where TOptions : class, new(){// 初始化逻辑初始化由IConfigureOptions和IPostConfigureOptions处理private readonly IEnumerableIConfigureOptionsTOptions _setups;private readonly IEnumerableIPostConfigureOptionsTOptions _postConfigures;// 验证逻辑private readonly IEnumerableIValidateOptionsTOptions _validations;// 构造函数 public OptionsFactory(IEnumerableIConfigureOptionsTOptions setups, IEnumerableIPostConfigureOptionsTOptions postConfigures) : this(setups, postConfigures, validations: null){ }// 构造函数 public OptionsFactory(IEnumerableIConfigureOptionsTOptions setups, IEnumerableIPostConfigureOptionsTOptions postConfigures, IEnumerableIValidateOptionsTOptions validations){_setups setups;_postConfigures postConfigures;_validations validations;}// 创建TOptions的核心方法传入名称如果没名称默认是空public TOptions Create(string name){// 1 根据传入的TOptions创建对象这里用无参构造函数所以之前需要对TOptions进行约束var options new TOptions();// 2 初始化foreach (var setup in _setups){// 根据传入的名字是否为默认名称选择不同的加工方法if (setup is IConfigureNamedOptionsTOptions namedSetup){namedSetup.Configure(name, options);}else if (name Options.DefaultName){setup.Configure(options);}}// IPostConfigureOptions对Options加工foreach (var post in _postConfigures){post.PostConfigure(name, options);}// 进行验证 如果不传入验证规则则代表不进行验证if (_validations ! null){// 存放验证失败的错误消息var failures new Liststring();// 遍历验证foreach (var validate in _validations){// 进行验证var result validate.Validate(name, options);// 如果验证失败if (result.Failed){ // 将验证失败错误信息加入到列表中failures.AddRange(result.Failures);}}// 如果验证失败就抛出异常OptionsValidationExceptionif (failures.Count 0){throw new OptionsValidationException(name, typeof(TOptions), failures);}}// 返回实例对象return options;}}
}
对于TOptions的创建逻辑就暂时先看到这吧如果需要再详细了解具体逻辑可以私下进行研究 总结哎呀这篇先不一一举例演示了可能导致篇幅过长上个WC的时间估计看不完(哈哈哈)那么就是单纯的代码说明吗不仅仅如此这篇主要讲解代码的同时其实着重凸显了IOptionTOptions、IOptionsSnapshotTOptions、IOptionsMonitorTOptions三个核心类型然后围绕三个核心类型简单看了内部实现、创建过程和监听逻辑因为在实际应用也是围绕以上进行使用和扩展的最终的目的是让使用不再糊涂其实这才是终极目标啦~~~~ 下一篇就专门针对Options举例演示----------------------------------------------一个被程序搞丑的帅小伙关注Code综艺圈识别关注跟我一起学~~~