日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > asp.net >内容正文

asp.net

ASP.NET Core 配置源:实时生效

發布時間:2023/12/4 asp.net 26 豆豆
生活随笔 收集整理的這篇文章主要介紹了 ASP.NET Core 配置源:实时生效 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

在之前的文章 ASP.NET Core 自定義配置源 和 ASP.NET Core etcd 配置源 中主要是介紹如何實現自定義的配置源,但不論內置的和自定義的配置源,都會面臨如何使配置修改后實時生效的問題(修改配置后在不重啟服務的情況下能馬上生效)。在 ASP.NET Core etcd 配置源 的最后部分其實有用到 IOptionsSnapshot Options 快照的方式獲取到最新配置,但其實這里依然不是實時數據,所以本文將繼續深入介紹配置使用方式及內部處理機制。(以下測試代碼基于 ASP.NET Core 3.1)。

Configuration 模式

在 ASP.NET Core Web API 應用程序中 IConfiguration 服務默認已以單例模式注入到 services 中,含以下 ConfigurationProvider 中的配置信息,同時對 appsettings.json 和 appsettings.Development.json 已設置 reloadOnChange 為 true,即文件內容有變化將自動更新到 IConfiguration 的對象中:

代碼如下:

public class TestController : ControllerBase {private readonly IConfiguration _configuration;public TestController(IConfiguration configuration){_configuration = configuration;}[HttpGet]public string Get(){return _configuration["Name"];} }

在不重啟服務的情況下修改 Name 的值,重新調用接口將會馬上獲取到最新值,所以通過從 IConfiguration 中獲取配置可以做到實時生效,這主要是因為在 JsonConfigurationProvider 的實現中當設置 reloadOnChange 為 true,則會監控文件的變化,一旦有變則重新加載當前 Provider 的配置信息,整個原理和 ASP.NET Core etcd 配置源 的實現類似,JsonConfigurationProvider 源碼[1]

Options 模式

Options 模式 也是比較常用的一種配置使用方式,通過將某個 Section 的配置信息以對象的方式注入到服務中,在程序中使用將更加方便與形象,在 Options 模式 主要有 3 種使用方式,分別是:IOptions、IOptionsSnapshot、IOptionsMonitor。

使用方式及表現

首先在 appsettings.json 中添加如下配置:

{..."UserOption": {"Name": "beck"} }

然后在 startup.cs 的 ConfigureServices 注冊配置服務:

public void ConfigureServices(IServiceCollection services) {services.Configure<UserOption>(Configuration.GetSection("UserOption"));services.AddControllers(); }

使用方式如下:

public class TestController : ControllerBase {private readonly IOptions<UserOption> _options;public TestController(IOptions<UserOption> options){_options = options;}[HttpGet]public void Get(){Console.WriteLine(_options.Value.Name);Thread.Sleep(5000); // 等待過程中,手動修改配置文件Console.WriteLine(_options.Value.Name);} }

分布使用 IOptions、IOptionsSnapshot、IOptionsMonitor(需改為 _options.CurrentValue) 進行測試,每種測試對配置文件中 Name 的值進行調整,具體表現結果如下:

  • IOptions:本次請求內修改不會生效,重新請求也不會生效,需重啟服務;

  • IOptionsSnapshot:本次請求內修改不會生效,重新請求生效;

  • IOptionsMonitor:實時生效;

處理機制分析

基于以上表現結果,我們接下來通過 Options 源碼[2] 來分析其本質原因。

首先在服務啟動階段 HostBuilder 的 Build 方法中調用 services.AddOptions() 進行 Options 相關服務的注冊,代碼如下:

public static IServiceCollection AddOptions(this IServiceCollection services) {if (services == null){throw new ArgumentNullException(nameof(services));}services.TryAdd(ServiceDescriptor.Singleton(typeof(IOptions<>), typeof(OptionsManager<>)));services.TryAdd(ServiceDescriptor.Scoped(typeof(IOptionsSnapshot<>), typeof(OptionsManager<>)));services.TryAdd(ServiceDescriptor.Singleton(typeof(IOptionsMonitor<>), typeof(OptionsMonitor<>)));services.TryAdd(ServiceDescriptor.Transient(typeof(IOptionsFactory<>), typeof(OptionsFactory<>)));services.TryAdd(ServiceDescriptor.Singleton(typeof(IOptionsMonitorCache<>), typeof(OptionsCache<>)));return services; }

從代碼中可以明顯的看出 IOptions、IOptionsSnapshot 對應的實現都是OptionsManager,IOptions 的生命周期是 Singleton 模式,IOptionsSnapshot 的生命周期是 Scoped 模式,所以這個就比較好解釋為什么 IOptions 方式下配置調整后需要重啟才能生效,而 IOptionsSnapshot 是每次請求內不變,重新請求會變化的原因了。

另外 IOptionsMonitor 的具體實現是 OptionsMonitor,生命周期是 Singleton 模式。同時還包含了 IOptionsFactory 和 IOptionsMonitorCache 兩個服務的注冊,它們也是 Options 模式 下核心部分。

這幾個服務之間的關系如下:

IOptionsFactory 主要負責創建 TOptions 類型的具體對象,核心代碼如下:

public class OptionsFactory<TOptions> : IOptionsFactory<TOptions> where TOptions : class, new() {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.Add(result.FailureMessage);}}if (failures.Count > 0){throw new OptionsValidationException(name, typeof(TOptions), failures);}}return options;} }

其中 _setups 的來源即最開始 services.Configure 注冊的配置服務,_postConfigures 的來源是以 services.PostConfigure 方式注冊的配置服務(本例中未使用到),它們的區別是 PostConfigure 注冊的服務將在 Configure 之后執行。_validations 是參數合法性驗證集合,如果有需要,可以在服務注冊時指定。

OptionsManager 同時是 IOptions 和 IOptionsSnapshot 的實現,內部通過 OptionsCache 緩存 IOptionsFactory 創建的具體 TOptions 對象,區別在于創建出的具體對象生命周期不一樣,核心代碼如下:

public class OptionsManager<TOptions> : IOptions<TOptions>, IOptionsSnapshot<TOptions> where TOptions : class, new() {public TOptions Value{get{return Get(Options.DefaultName);}}public virtual TOptions Get(string name){name = name ?? Options.DefaultName;return _cache.GetOrAdd(name, () => _factory.Create(name));} }

OptionsMonitor 是 IOptionsMonitor 的實現,內部通過 IOptionsMonitorCache 緩存 IOptionsFactory 創建的具體 TOptions 對象,同時對于采用 IConfiguration 作為數據源類型的,通過 ChangeToken.OnChange 監聽變化并實時更新配置。

public class OptionsMonitor<TOptions> : IOptionsMonitor<TOptions> where TOptions : class, new() {public OptionsMonitor(IOptionsFactory<TOptions> factory, IEnumerable<IOptionsChangeTokenSource<TOptions>> sources, IOptionsMonitorCache<TOptions> cache){foreach (var source in _sources){ChangeToken.OnChange<string>(() => source.GetChangeToken(),(name) => InvokeChanged(name),source.Name);}}private void InvokeChanged(string name){name = name ?? Options.DefaultName;_cache.TryRemove(name);var options = Get(name);if (_onChange != null){_onChange.Invoke(options, name);}}public TOptions CurrentValue{get => Get(Options.DefaultName);}public virtual TOptions Get(string name){name = name ?? Options.DefaultName;return _cache.GetOrAdd(name, () => _factory.Create(name));} }

自實現 OptionsMonitor

Configuration 對象默認提供了 GetReloadToken 方法,所以我們也可以通過監聽 Token 的變化自己實現類似 OptionsMonitor 的效果,畢竟有時候并不會選擇 Configuration 模式Options 模式,以下是在控制臺程序中的使用,假設使用 Autofac 作為 DI 容器,SetUserOption 內將可重新注冊 UserOption 對象。

private static UserOption userOption;static void Main(string[] args) {var configurationRoot = GetRoot();ChangeToken.OnChange(() => configurationRoot.GetReloadToken(), () =>{SetUserOption(configurationRoot);Console.WriteLine(userOption.Name);});Console.WriteLine("started");Console.ReadKey(); }private static IConfigurationRoot GetRoot() {var builder = new ConfigurationBuilder().SetBasePath(Directory.GetCurrentDirectory()).AddJsonFile("appsettings.json", true, true);return builder.Build(); }private static void SetUserOption(IConfigurationRoot configuration) {userOption = configuration.GetSection("UserOption").Get<UserOption>(); }

參考資料

[1]

JsonConfigurationProvider 源碼: https://github.com/aspnet/Configuration/blob/master/src/Config.Json/JsonConfigurationProvider.cs

[2]

Options 源碼: https://github.com/aspnet/Options/tree/master/src/Microsoft.Extensions.Options

總結

以上是生活随笔為你收集整理的ASP.NET Core 配置源:实时生效的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。