聊聊ASP.NET Core中的配置

碼農譯站發表於2021-02-20

​作為軟體開發人員,我們當然喜歡一些可配置選項,尤其是當它允許我們改變應用程式的行為而無需修改或編譯我們的應用程式時。無論你是使用新的還是舊的.NET時,可能希望利用json檔案的配置。在這篇文章中,我們將探討讀取配置所需的必要步驟以及使用這些值。

.NET的配置歷史

對於那些ASP.NET老兵,你可能還記得wen.config。雖然它沒有完全被拋棄,但它在ASP.NET Core中扮演著不那麼重要的角色。web.config是一個基於XML的檔案,用於配置IIS的主機環境。在這個檔案中,我們可以放置應用程式設定、載入額外的web模組、註冊處理程式等等。

另一個限制是web.config更改後將迫使應用程式重新啟動。更改可以很簡單,如新增新的應用程式設定,也可以很複雜,如向請求管道新增新模組。ASP.NET應用程式必須重新載入,以確保邏輯一致性。開發人員可以將所有設定通過ConfigurationManager訪問。坦率地說,隨著時間的推移,開發人員將重新啟動看作是一種功能,而不是一種障礙,使用它來重置陷入故障狀態的應用程式。

現在的ASP.NET Core配置

ASP.NET Core看到了圍繞配置產生主要問題,並試圖通過以下三方面為開發人員改進:

  • 除了XML之外,還支援其他形式的配置格式。
  • 用依賴注入(DI)的友好方法替換ConfigurationManager。
  •  配置熱更改,可以立即在訪問的程式碼中發生。

這些變化反映了更先進的設定,並且對本地雲的web應用程式更友好。應用程式配置可以來自多個位置,可擴充套件性使開發人員更容易避免自定義解決方案。

隨著.NET採用async/await和非同步程式設計,使用單例可能會導致死鎖和效能開銷。使DI支援配置後,給開發人員提供了更多的方式來使用設定依賴項,並將這些資料與任何源解耦。它還可以在不訪問ConfigurationManager或web.config的情況下測試配置設定。

冷啟動是所有使用者的敵人,它會創造令人沮喪的體驗。無需重新啟動就可以進行更改的能力確保了更好的執行時體驗。

看看具體程式碼

目前,我們已經討論了配置的歷史和當前狀態,但是讓我們跳到實際使用環節。

第一步是建立一個從配置提供程式讀取設定的資料類。ASP.NET Core提供了多個開箱即用的功能,但最常用的是JSON配置提供程式。該類需要包含與JSON部分相同的結構。

public class HelloWorldOptions{
  public string Text { get; set; }
}

下一部分是講述ASP.NET Core如何繫結HelloWorldOptions類。我們可以使用BindConfiguration方法做到這一點。

public void ConfigureServices(IServiceCollection services){
    services.AddOptions<HelloWorldOptions>()
            .BindConfiguration("HelloWorld");
}

字串HelloWorld表示appsettings.json檔案中的部分。

{
  "HelloWorld" : {
    "Text": "Hello, Khalid!"
  },
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft": "Warning",
      "Microsoft.Hosting.Lifetime": "Information"
    }
  },
  "AllowedHosts": "*"
}

很好,現在我們準備好使用我們的配置資訊了。接下來就有點讓人困惑了。我們有三個介面可供選擇:

  • IOptions<T>
  • IOptionsSnapshot<T>
  • IOptionsMonitor<T>

每個介面都包裝了我們的配置資料,併為我們提供了略微不同的生命週期。

IOptions< T>被註冊為一個單例,因此所有的值都被檢索一次並儲存在ASP.NET Core應用程式的記憶體。在應用程式啟動後,這種方法無法讀取任何更新的配置。註冊為單例意味著ASP.NET可以將介面注入到任何依賴項中,而不必擔心捕獲它或導致記憶體洩漏問題。這個版本很可能是大多數人會使用的。

IOptionsSnapshot< T>具有作用域生存期。ASP.NET Core將對每個HTTP請求重新檢查一次。

快取每個請求的例項,直到使用者收到響應。這個方法對於那些希望動態更改配置但仍然需要通過當前管道進行重新整理的請求的人非常有用。這個版本有助於使用切換配置,而無需重新載入應用程式。

最後,IOptionsMonitor< T>與IOptionsSnapshot<T>很相似,卻是單例生命週期。IOptionsMonitor方法對於應該立即處理的關鍵資料更改非常有用。長期存在的後臺服務可能希望使用IOptionsMonitor繼續接收配置更改,但不需要支付昂貴的物件建立成本。

既然我們知道了每個介面的優點,我們就可以使用我們的配置了。在啟動時找到的Configure方法中,讓我們新增一個新的GET終結點。

public void Configure(IApplicationBuilder app, IWebHostEnvironment env){
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }
​
    app.UseRouting();
​
    app.UseEndpoints(endpoints =>
    {
        endpoints.MapGet("/", async context =>
        {
            var options = 
                context
                    .RequestServices
                    .GetRequiredService<IOptionsSnapshot<HelloWorldOptions>>()
                    .Value;
            
            await context.Response.WriteAsync(options.Text);
        });
    });
}

注意,在我們的程式碼中,我們使用的是IOptionsSnapshot。通過例項將允許我們更新配置,而不需要重新啟動我們的應用程式。啟動應用程式時,我們應該看到配置值。更改配置將更改請求的結果。

{
  "HelloWorld" : {
    "Text": "Hello, World!"
  },
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft": "Warning",
      "Microsoft.Hosting.Lifetime": "Information"
    }
  },
  "AllowedHosts": "*"
}

重新載入後,我們現在看到的內容:

Hello, World!

這很有效,而且我們不需要為配置中的微小更改支付啟動成本。

總結

最初使用ASP.NET Core中的配置可能會讓人感到困惑。微軟文件對IOption介面有一個詳細的解釋。大多數情況下,人們應該使用IOptions<T>,因為它可能是效能最好的。也就是說,如果我們想要熱載入設定的能力,如果我們想要請求一致性,IOptionsSnapshot是最好的。

最後,如果你的應用嚴重依賴單例生存期,仍然需要熱載入設定,考慮IOptionsMonitor。

原文連結:https://khalidabuhakmeh.com/aspnet-core-ioptions-configuration

相關文章