本文将为您提供关于c#–为什么Mono.GetOptions已过时?的详细介绍,我们还将为您解释c#使用mongodb的相关知识,同时,我们还将为您提供关于.NetCore配置文件读取IOptions
本文将为您提供关于c# – 为什么Mono.GetOptions已过时?的详细介绍,我们还将为您解释c#使用mongodb的相关知识,同时,我们还将为您提供关于.Net Core 配置文件读取IOptions,IOptionsMonitor,IOptionsSnapshot、ASP.NET Core 选项模式源码学习 Options IOptions(二)、ASP.NET Core 选项模式源码学习Options IOptionsMonitor(三)、ASP.NET Core 选项模式源码学习Options IOptions(二)的实用信息。
本文目录一览:- c# – 为什么Mono.GetOptions已过时?(c#使用mongodb)
- .Net Core 配置文件读取IOptions,IOptionsMonitor,IOptionsSnapshot
- ASP.NET Core 选项模式源码学习 Options IOptions(二)
- ASP.NET Core 选项模式源码学习Options IOptionsMonitor(三)
- ASP.NET Core 选项模式源码学习Options IOptions(二)
c# – 为什么Mono.GetOptions已过时?(c#使用mongodb)
解决方法
NDesk.Options / Mono.Options是“不稳定的”,因为API实际上是不稳定的 – 如果认为合适,我保留以不兼容的方式更改公共API的权利. (我希望我不需要,但我保留了这一点.)那就是说,我还在,所以它正在被维护(或者能够被维护).
这就是Mono.Options作为源分发的原因 – 如果API发生变化,则无关紧要,因为您拥有与程序捆绑在一起的源代码副本. (这也是NDesk.Options.dll未签名的原因 – 因此它不会被放置在GAC中,因为GAC中的程序集强烈假设它们不会以不兼容的方式更改API.)
.Net Core 配置文件读取IOptions,IOptionsMonitor,IOptionsSnapshot
前言
众所周知,appsetting.json 配置文件是.Net 的重大革新之心,抛开了以前繁杂的xml文件,使用了更简洁易懂的json方式,简直不要太舒服了!东西虽然好,但怎么在程序中读取这个配置呢,是每个新手必须要跨过去的坑(当然也是包括我这个菜狗子)。
遇事不明上注入,只要是遇到不知道怎么办的事,首先要往注入方便想,框架有了这个配置文件,必然配备了简单直接的读取API,按照我的习惯,直接上代码:
首先,我们在配置文件中,增加 Demo 配置节点:
{ "Logging": { "LogLevel": { "Default": "Information", "Microsoft.AspNetCore": "Warning" } }, "Demo": { "Value1": "1", "Value2": "2", "Value3": "3", "Value4": "4" } }
在需要用到配置文件的地方,注入 IConfiguration 服务接口
private readonly IConfiguration _configuration; public ValuesController(IConfiguration configuration) { _configuration = configuration; }
通常,我们比较直接的方式是通过 GetSection 获取对应的配置节点,然后再获取对应的配置项
var section = _configuration.GetSection("Demo"); var value1 = section.GetValue("Value1", "1");
如果 Demo 节点内还有更深的节点,GetSection 可以通过 : 深入到对应的下一个节点
appsetting.json
{ "Logging": { "LogLevel": { "Default": "Information", "Microsoft.AspNetCore": "Warning" } }, "Demo": { "Value1": "1", "Value2": "2", "Value3": "3", "Value4": "4", "Model" { "Name": "小二", "Phone": "12345678911" } } }
var model = _configuration.GetSection("Demo:Model");
有些小伙伴可能就会问了,那我每个需要用到的地方都需要直接以字符串作为参数去读取配置,以后要是突然改了配置项,岂不是非常麻烦;
这点小伙伴们大可放心,你可以定义一个实体类,然后绑定上去,以后有什么更改了,直接重命名对应的属性就行了,实例代码
方法一:
var options = new DemoOptions(); _configuration.GetSection("Demo").Bind(options);
方法二:
var options2 = _configuration.GetSection("Demo").Get<DemoOptions>();
方法三:在 Startup.cs、.Net 6 以上在 Program.cs- 中使用依赖注入方式,以下是 .Net 6
builder.Services.Configure<DemoOptions>(builder.Configuration.GetSection("Demo"));
在需要使用的地方注入 IOptions<TOptions> 即可获取到配置值,需要注意的是,IOptions 是单例(Singleton)服务,即在应用启动时进行注册,后续更改配置文件,该 IOptions 将不会同步更新,依然还是旧值
private readonly DemoOptions _demoOptions; public ValuesController(IOptions<DemoOptions> options) { _demoOptions = options.Value; }
如需要配置进行热更新,只需要改成注入 IOptionsMonitor<TOptions> 或者 IOptionsSnapshot<TOptions>;IOptionsSnapshot<TOptions>的生命周期是作用域(Scoped),每次请求都会重新获取一次配置;IOptionsSnapshot<TOptions> 的生命周期是单例(Singleton),与 IOptions<TOptions> 不一样的是当配置文件发生改变时,将会自动同步响应。
到此这篇关于.Net Core 配置文件读取IOptions,IOptionsMonitor,IOptionsSnapshot的文章就介绍到这了,更多相关.Net Core 文件读取内容请搜索以前的文章或继续浏览下面的相关文章希望大家以后多多支持!
- .NetCore获取Json和Xml格式的配置信息
- .NET Core控制台应用ConsoleApp读取appsettings.json配置文件
- .net6 使用Senparc开发小程序配置过程
- .NET Core自定义配置文件
- .NET Core读取配置文件
- .NET 中配置从xml转向json方法示例详解
ASP.NET Core 选项模式源码学习 Options IOptions(二)
https://yq.aliyun.com/articles/743159
前言
上一篇文章介绍 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 进行缓存操作;实现 IOptionsSnapshot 接口 Get (string name) 其实就是获取我们第一章所指定的 Name,通过 IOptionsFactory<> 创建 TOptions 实例
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
OptionsCache 采用了线程安全字典 ConcurrentDictionary 进行了封装用于内存缓存
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 实现了 IOptionsFactory.Create(string name);,
而 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 IOptionsMonitor(三)
前言
IOptionsMonitor 是一种单一示例服务,可随时检索当前选项值,这在单一实例依赖项中尤其有用。IOptionsMonitor用于检索选项并管理TOption实例的选项通知, IOptionsMonitor<TOptions> 支持以下方案:
- 更改通知
- 命名选项
- 可重载配置
- 选择性选项失效 (IOptionsMonitorCache<TOptions>)
IOptionsMonitor
public interface IOptionsMonitor<out TOptions>
{
/// <summary>
/// 返回具有 DefaultName 的当前 TOptions 实例。
/// </summary>
TOptions CurrentValue { get; }
/// <summary>
/// 返回具有给定名称的已配置的 TOptions 实例。
/// </summary>
TOptions Get(string name);
/// <summary>
/// 注册一个要在命名 TOptions 更改时调用的侦听器。
/// </summary>
IDisposable OnChange(Action<TOptions, string> listener);
}
OptionsMonitor
OptionsMonitor通过IOptionsChangeTokenSource实现监听事件
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 name="factory">The factory to use to create options.</param>
/// <param name="sources">The sources used to listen for changes to the options instance.</param>
/// <param name="cache">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 name="TOptions"/> instance with the given <paramref name="name"/>.
/// </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 name="TOptions"/> changes.
/// </summary>
/// <param name="listener">The action to be invoked when <typeparamref name="TOptions"/> 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;
}
}
IOptionsChangeTokenSource 的代码片段:
public interface IOptionsChangeTokenSource<out TOptions>
{
IChangeToken GetChangeToken();
string Name { get; }
}
在OptionsMonitor的构造函数中,通过调用其GetChangeToken方法,获取到 ChangeToken ,在 InvokeChanged 完成 _onChange 事件的调用:
private void InvokeChanged(string name)
{
name = name ?? Options.DefaultName;
_cache.TryRemove(name);
var options = Get(name);
if (_onChange != null)
{
_onChange.Invoke(options, name);
}
}
对外暴露OnChange方法,方便我们添加自己的业务逻辑
public IDisposable OnChange(Action<TOptions, string> listener)
{
var disposable = new ChangeTrackerDisposable(this, listener);
_onChange += disposable.OnChange;
return disposable;
}
通过ChangeTrackerDisposable进行事件的注销
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;
}
ConfigurationChangeTokenSource
ConfigurationChangeTokenSource实现IOptionsChangeTokenSource接口
public class ConfigurationChangeTokenSource<TOptions> : IOptionsChangeTokenSource<TOptions>
{
private IConfiguration _config;
public ConfigurationChangeTokenSource(IConfiguration config) : this(Options.DefaultName, config)
{ }
public ConfigurationChangeTokenSource(string name, IConfiguration config)
{
if (config == null)
{
throw new ArgumentNullException(nameof(config));
}
_config = config;
Name = name ?? Options.DefaultName;
}
public string Name { get; }
public IChangeToken GetChangeToken()
{
return _config.GetReloadToken();
}
}
示例
public class WeatherForecastController : ControllerBase
{
private readonly ILogger<WeatherForecastController> _logger;
private readonly IOptionsMonitor<MyOptions> _options;
public WeatherForecastController(IOptionsMonitor<MyOptions> options, ILogger<WeatherForecastController> logger)
{
_options = options;
_logger = logger;
}
[HttpGet]
public OkObjectResult Get() {
_options.OnChange(_=>_logger.LogWarning(_options.CurrentValue.Name));
return Ok(string.Format("Name:{0},Url:{1}", _options.CurrentValue.Name,_options.CurrentValue.Url));
}
}
现在我们每次修改配置文件,便会触发OnChange事件
原文出处:https://www.cnblogs.com/yyfh/p/12047289.html
ASP.NET Core 选项模式源码学习Options IOptions(二)
https://yq.aliyun.com/articles/743159
前言
上一篇文章介绍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 进行缓存操作;实现IOptionsSnapshot接口Get(string name)其实就是获取我们第一章所指定的Name,通过IOptionsFactory<>创建TOptions实例
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
OptionsCache采用了线程安全字典ConcurrentDictionary进行了封装用于内存缓存
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实现了 IOptionsFactory.Create(string name);,
而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;
}
}
我们今天的关于c# – 为什么Mono.GetOptions已过时?和c#使用mongodb的分享就到这里,谢谢您的阅读,如果想了解更多关于.Net Core 配置文件读取IOptions,IOptionsMonitor,IOptionsSnapshot、ASP.NET Core 选项模式源码学习 Options IOptions(二)、ASP.NET Core 选项模式源码学习Options IOptionsMonitor(三)、ASP.NET Core 选项模式源码学习Options IOptions(二)的相关信息,可以在本站进行搜索。
本文标签: