重新整理 .net core 实践篇—————服务的配置更新[十三]

前文讲述了,服务和配置直接的配合,这一节写一下,当配置文件修改了,每个服务如何感知自己的配置。

正文

服务感知到自己的配置发生变化,这就牵扯出两个东西:

IoptionsMonitor<out TOptions> IoptionSnapshot<out TOptions>

在作用域范围使用IoptionSnapshot,在单例中使用IoptionsMonitor 。

IoptionsMonitor

先来演示作用域范围的使用。
配置:

{ "SelfService": { "name" : "zhangsan" } }

SelfServiceOption:

public class SelfServiceOption { public string Name { get; set; } }

服务:

public class SelfService : ISelfService { IOptionsSnapshot<SelfServiceOption> _options; public SelfService(IOptionsSnapshot<SelfServiceOption> options) { this._options = options; } public string ShowOptionName() { return _options.Value.Name; } }

注册:

services.Configure<SelfServiceOption>(Configuration.GetSection("SelfService"), BinderOptions => { BinderOptions.BindNonPublicProperties = true; }); services.AddScoped<ISelfService, SelfService>();

测试:

[HttpGet] public int GetService([FromServices]ISelfService selfService) { Console.WriteLine(selfService.ShowOptionName()); return 1; }

结果:

重新整理 .net core 实践篇—————服务的配置更新[十三]

第一次访问后修改为zhangsan_change,再次访问接口,会呈现上述效果。

那么为什么使用IoptionsMonitor,而为什么Ioptions 没有用呢。

前一篇写过Ioptions 的实现类OptionsManager,这个是有缓存的_cache,如下:

public class OptionsManager<TOptions> : IOptions<TOptions>, IOptionsSnapshot<TOptions> where TOptions : class, new() { private readonly IOptionsFactory<TOptions> _factory; private readonly OptionsCache<TOptions> _cache = new OptionsCache<TOptions>(); // Note: this is a private cache /// <summary> /// Initializes a new instance with the specified options configurations. /// </summary> /// <param>The factory to use to create options.</param> public OptionsManager(IOptionsFactory<TOptions> factory) { _factory = factory; } /// <summary> /// The default configured <typeparamref/> instance, equivalent to Get(Options.DefaultName). /// </summary> public TOptions Value { get { return Get(Options.DefaultName); } } /// <summary> /// Returns a configured <typeparamref/> instance with the given <paramref/>. /// </summary> public virtual TOptions Get(string name) { name = name ?? Options.DefaultName; // Store the options in our instance cache return _cache.GetOrAdd(name, () => _factory.Create(name)); } }

IoptionsMonitor的实现类也是OptionsManager,但是人家是作用域模式。

在Addoptions中:

services.TryAdd(ServiceDescriptor.Singleton(typeof(IOptions<>), typeof(OptionsManager<>))); services.TryAdd(ServiceDescriptor.Scoped(typeof(IOptionsSnapshot<>), typeof(OptionsManager<>)));

也就是说每创建一个SelfService,就会创建一个OptionsManager。缓存自然只在作用域内有效。

好的,那么来看下单例。

IoptionsMonitor

服务:

public class SelfService : ISelfService { IOptionsMonitor<SelfServiceOption> _options; public SelfService(IOptionsMonitor<SelfServiceOption> options) { this._options = options; _options.OnChange((selftServiceOptions) => { Console.WriteLine("alter change:"+selftServiceOptions.Name); }); } public string ShowOptionName() { return _options.CurrentValue.Name; } }

注册:

services.Configure<SelfServiceOption>(Configuration.GetSection("SelfService"), BinderOptions => { BinderOptions.BindNonPublicProperties = true; }); services.AddSingleton<ISelfService, SelfService>();

测试接口:

[HttpGet] public int GetService([FromServices]ISelfService selfService) { Console.WriteLine(selfService.ShowOptionName()); return 1; }

同意是修改钱访问一次,修改后访问一次。

结果如下:

重新整理 .net core 实践篇—————服务的配置更新[十三]

那么看下IOptionMonitor的实现类OptionsMonitor:

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>The factory to use to create options.</param> /// <param>The sources used to listen for changes to the options instance.</param> /// <param>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/> instance with the given <paramref/>. /// </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/> changes. /// </summary> /// <param>The action to be invoked when <typeparamref/> 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; } }

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zzfxxz.html