在 上一篇 中,介绍了一下Options的注册,而使用时只需要注入 IOption 即可:
public ValuesController(IOptions<MyOptions> options){ var opt = options.Value;
}
IOptions
IOptions 定义非常简单,只有一个Value
属性:
public interface IOptions<out TOptions> where TOptions : class, new()
{TOptions Value { get; }
}
OptionsManager
而当我们注入IOptions<MyOptions>
时,其默认实现则是OptionsManager<MyOptions>
,而且使用的单例模式,在AddOptions
扩展方法中可以看到:
public static IServiceCollection AddOptions(this IServiceCollection services){services.TryAdd(ServiceDescriptor.Singleton(typeof(IOptions<>), typeof(OptionsManager<>)));
return services;
}
而我们在使用的时候,并没有调用
AddOptions
扩展方法,那是因为在WebHostBuilder
的BuildCommonServices
方法中进行了调用,具体在Hosting系列中会详细来说。
再看一下OptionsManager
的源码:
public class OptionsManager<TOptions> : IOptions<TOptions> where TOptions : class, new()
{
private LegacyOptionsCache<TOptions> _optionsCache;
public OptionsManager(IEnumerable<IConfigureOptions<TOptions>> setups) {_optionsCache = new LegacyOptionsCache<TOptions>(setups);}
public virtual TOptions Value{
get{
return _optionsCache.Value;}}
}
OptionsManager
的构造函数中注入了IConfigureOptions<T>
,而这里使用了 IEnumerable 类型,则表示当注册多个时,则为按顺序依次执行。而其IConfigureOptions
则在上一篇已经讲过,是通过Configure
扩展方法进行注册的。而TOptions
的创建工作则是在LegacyOptionsCache
类中:
LegacyOptionsCache
先看代码,胜过千言万语:
internal class LegacyOptionsCache<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 LegacyOptionsCache(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);}}
}
其实非常简单,首先使用默认构造函数创建TOptions
实例,然后依次执行IConfigureOptions
的Configure
方法,说明最后一次的配置会覆盖之前的配置。而且使用了LazyInitializer
来实现双检锁的效果,保证TOptions
只实例化一次。
总结
本文描述了在 .NET Core Options 系统中,IOptions 的使用及实现原理。IOptions 的实现使用的是单例模式,因此当配置源发生变化时,我们无法获取到最新的配置。如果我们希望能够检测到配置源的变化,并能够自动更新,则可以使用 IOptionsSnapshot
相关文章:
ASP.NET Core 源码学习之 Options[1]:Configure
ASP.NET Core MVC 源码学习:详解 Action 的匹配
asp.net core源码飘香:从Hosting开始
asp.net core源码飘香:Configuration组件
asp.net core源码飘香:Options组件
asp.net core源码飘香:Logging组件
原文地址:http://www.cnblogs.com/RainingNight/p/strongly-typed-options-ioptions-in-asp-net-core.html
.NET社区新闻,深度好文,微信中搜索dotNET跨平台或扫描二维码关注