1. 程式人生 > >.NET Core採用的全新配置系統[8]: 如何實現配置與原始檔的同步

.NET Core採用的全新配置系統[8]: 如何實現配置與原始檔的同步

配置的同步涉及到兩個方面:第一,對原始的配置檔案實施監控並在其發生變化之後從新載入配置;第二,配置重新載入之後及時通知應用程式進而使後者能夠使用最新的配置。接下來我們利用一個簡單的.NET Core控制檯應用來演示針對檔案的配置會涉及到資料同步的問題,我們希望應用能夠對原始配置檔案實施監控,並在檔案內容發生改變的時候從新載入並應用新的配置。針對JSON檔案的配置源通過JsonConfigurationSource型別來表示,該型別定義在“Microsoft.Extensions.Configuration.Json”這個NuGet包中,所以我們需要在project.json檔案中按照如下的形式新增針對這個NuGet包的依賴。[ 本文已經同步到《

ASP.NET Core框架揭祕》之中]

   1: {
   2:   ...
   3:   "dependencies": {
   4:     ...    
   5:     "Microsoft.Extensions.Configuration.Json": "1.0.0"
   6:   }
   7: }

假設我們需要通過配置來當前應用使用的執行緒池的容量,這樣的設定需要根據當前的負載進行調整,所以需要很高的時效性,我們希望一旦修改了JSON檔案的配置,應用程式中針對執行緒池的相關設定可以立即生效。簡單起見,我們僅僅定義MinThreads 和MaxThreads這兩個分別決定執行緒池容量區間的配置項,如下所示的ThreadPoolOptions是對應的Options型別。

   1: public class ThreadPoolOptions
   2: {
   3:     public int MinThreads { get; set; }
   4:     public int MaxThreads { get; set; }
   5:  
   6:     public override string ToString()
   7:     {
   8:         return $"Thread pool size: [{MinThreads}, {MaxThreads}]";
   9:     }
  10: }

我們在專案中新增一個名為threadPool.json的檔案來定義執行緒池的配置。除此之外,我們需要通過修改project.json與編譯相關的配置讓該檔案在編譯的時候自動拷貝到輸出目錄下(預設為bin目錄)。具體來說,我們只需要按照如下的方式將該檔案的路徑設定為“builtOptions/copyToOutput”配置選購的值就可以了。

   1: {
   2:   ...
   3:   "buildOptions": {
   4:     ...
   5:     "copyToOutput": "threadPool.json"
   6:   }
   7: }

接下來我們編寫了如下一段程式來演示應用中使用的配置如何與配置檔案的內容保持同步。我們首先建立了一個ConfigurationBuilder物件,並在它上面註冊了一個JsonConfigurationSource。在建立這個JsonConfigurationSource物件的時候,除了指定配置檔案(“threadPool.json”)的路徑之外,我們還將它的ReloadOnChange屬性設定為True。顧名思義,這個ReloadOnChange屬性的含義就是當原始配置檔案的內容發生改變的時候是否需要重新載入配置。

   1: IConfiguration config = new ConfigurationBuilder()
   2:     .Add(new JsonConfigurationSource {Path = "threadPool.json", ReloadOnChange = true })
   3:     .Build();
   4:  
   5: Action changeCallBack = () => {
   6:     ThreadPoolOptions options = new ServiceCollection()
   7:         .AddOptions()
   8:         .Configure<ThreadPoolOptions>(config)
   9:         .BuildServiceProvider()
  10:         .GetService<IOptions<ThreadPoolOptions>>()
  11:         .Value;
  12:     Console.WriteLine(options);
  13: };
  14:  
  15: ChangeToken.OnChange(()=>config.GetReloadToken(), changeCallBack);
  16:  
  17: Random random = new Random();
  18: while (true)
  19: {
  20:     ThreadPoolOptions options = new ThreadPoolOptions
  21:     {
  22:         MinThreads = random.Next(10, 20),
  23:         MaxThreads = random.Next(40, 50)
  24:     };
  25:     File.WriteAllText(Path.Combine(AppContext.BaseDirectory, "threadPool.json"), JsonConvert.SerializeObject(options));
  26:     Task.Delay(5000).Wait();
  27: }

在利用ConfigurationBuilder得到Configuration物件之後,我們呼叫它的GetReloadToken方法得到一個ChangeToken物件,後者會幫助我們判斷配置是否被重新載入。我們呼叫ChangeToken型別的靜態方法OnChange為這個ChangeToken物件註冊了一個回撥,該回調會在配置被重新載入時自動執行。至於這個註冊的回撥,我們僅僅是採用Options模式得到配置繫結生成的ThreadPoolOptions物件,並將它的相關資訊列印在控制檯上。

在這段程式的最後,我們在一個無限迴圈中以5秒鐘的間隔對threadPool.json檔案進行更新。按照這段程式的意圖,當我們每次完成了針對threadPool.json的更新之後,我們建立的Configuration物件會自動重新載入。Configuration一旦重新載入,之前呼叫它的GetReloadToken方法得到ChangeToken物件的HasChanged屬性將變成True,註冊在它上面的回撥將被執行。所以最終的結果就是重新設定的配置會實時出現在控制檯上,如下所示的輸出結果證實了這一點。(S04)

image