ASP.NET Core 选项模式源码学习Options IOptions(二)
前言
上一篇文章介绍ioptions的注册,本章我们继续往下看
ioptions
ioptions是一个接口里面只有一个values属性,该接口通过optionsmanager实现
public interface ioptions<out toptions> where toptions : class, new() { /// <summary> /// the default configured <typeparamref name="toptions"/> instance /// </summary> toptions value { get; } }
optionsmanager
optionsmanager实现了ioptions<>和ioptionssnapshot<>,他使用内部属性optionscache
optionscache采用了线程安全字典concurrentdictionary进行了封装用于内存缓存 optionsfactory实现了 ioptionsfactory.create(string name);, 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 name="factory">the factory to use to create options.</param>
public optionsmanager(ioptionsfactory<toptions> factory)
{
_factory = factory;
}
/// <summary>
/// the default configured <typeparamref name="toptions"/> instance, equivalent to get(options.defaultname).
/// </summary>
public toptions value
{
get
{
return 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;
// store the options in our instance cache
return _cache.getoradd(name, () => _factory.create(name));
}
}
public interface ioptionssnapshot<out toptions> : ioptions<toptions> where toptions : class, new()
{
/// <summary>
/// returns a configured <typeparamref name="toptions"/> instance with the given name.
/// </summary>
toptions get(string name);
}
optionscache
public class optionscache<toptions> : ioptionsmonitorcache<toptions> where toptions : class
{
private readonly concurrentdictionary<string, lazy<toptions>> _cache = new concurrentdictionary<string, lazy<toptions>>(stringcomparer.ordinal);
/// <summary>
/// clears all options instances from the cache.
/// </summary>
public void clear() => _cache.clear();
/// <summary>
/// gets a named options instance, or adds a new instance created with <paramref name="createoptions"/>.
/// </summary>
/// <param name="name">the name of the options instance.</param>
/// <param name="createoptions">the func used to create the new instance.</param>
/// <returns>the options instance.</returns>
public virtual toptions getoradd(string name, func<toptions> createoptions)
{
if (createoptions == null)
{
throw new argumentnullexception(nameof(createoptions));
}
name = name ?? options.defaultname;
return _cache.getoradd(name, new lazy<toptions>(createoptions)).value;
}
/// <summary>
/// tries to adds a new option to the cache, will return false if the name already exists.
/// </summary>
/// <param name="name">the name of the options instance.</param>
/// <param name="options">the options instance.</param>
/// <returns>whether anything was added.</returns>
public virtual bool tryadd(string name, toptions options)
{
if (options == null)
{
throw new argumentnullexception(nameof(options));
}
name = name ?? options.defaultname;
return _cache.tryadd(name, new lazy<toptions>(() => options));
}
/// <summary>
/// try to remove an options instance.
/// </summary>
/// <param name="name">the name of the options instance.</param>
/// <returns>whether anything was removed.</returns>
public virtual bool tryremove(string name)
{
name = name ?? options.defaultname;
return _cache.tryremove(name, out var ignored);
}
}
optionsfactory
而optionsfactory构造函数中注入了iconfigureoptions<>和ipostconfigureoptions<>,
这里使用了ienumerable类型标识当注册多个时候按照次数依次的执行,从如下代码中我们也看到了我们在上一章中所说的configures和postconfigures注册先后顺序问题。
public class optionsfactory<toptions> : ioptionsfactory<toptions> where toptions : class, new()
{
private readonly ienumerable<iconfigureoptions<toptions>> _setups;
private readonly ienumerable<ipostconfigureoptions<toptions>> _postconfigures;
private readonly ienumerable<ivalidateoptions<toptions>> _validations;
public optionsfactory(ienumerable<iconfigureoptions<toptions>> setups, ienumerable<ipostconfigureoptions<toptions>> postconfigures) : this(setups, postconfigures, validations: null)
{ }
public optionsfactory(ienumerable<iconfigureoptions<toptions>> setups, ienumerable<ipostconfigureoptions<toptions>> postconfigures, ienumerable<ivalidateoptions<toptions>> validations)
{
_setups = setups;
_postconfigures = postconfigures;
_validations = validations;
}
public toptions create(string name)
{
var options = new toptions();
foreach (var setup in _setups)
{
if (setup is iconfigurenamedoptions<toptions> namedsetup)
{
namedsetup.configure(name, options);
}
else if (name == options.defaultname)
{
setup.configure(options);
}
}
foreach (var post in _postconfigures)
{
post.postconfigure(name, options);
}
if (_validations != null)
{
var failures = new list<string>();
foreach (var validate in _validations)
{
var result = validate.validate(name, options);
if (result.failed)
{
failures.addrange(result.failures);
}
}
if (failures.count > 0)
{
throw new optionsvalidationexception(name, typeof(toptions), failures);
}
}
return options;
}
}
推荐阅读
-
ASP.NET Core 选项模式源码学习Options IOptions(二)
-
ASP.NET Core 选项模式源码学习Options IOptionsMonitor(三)
-
ASP.NET Core 选项模式源码学习Options Configure(一)
-
(13)ASP.NET Core 中的选项模式(Options)
-
ASP.NET Core 选项模式源码学习Options IOptions(二)
-
ASP.NET Core 选项模式源码学习Options IOptionsMonitor(三)
-
ASP.NET Core 选项模式源码学习Options Configure(一)
-
(13)ASP.NET Core 中的选项模式(Options)