在.net framework平臺中我們常見的也是最熟悉的就是.config
檔案作為設定,控制檯桌面程式是App.config
,Web就是web.config
,裡面的設定格式為xml格式。
在xml裡面有系統生成的設定項,也有我們自己新增的一些設定,最常用的就是appSettings節點,用來設定資料庫連線和引數。
使用的話就參照包System.Configuration.ConfigurationManager
之後取裡面的設定資訊:System.Configuration.ConfigurationManager.AppSettings["ConnectionString"]
隨著技術的發展這種設定方式顯得冗餘複雜,如果設定項太多層級關係參數列達凌亂,在.net core開始也將設定的格式預設成了json格式,包括現在很多的其它設定也是支援的,比如java中常用的yaml格式,為什麼能支援這麼多讀取源和格式,其實質在於設定提供程式
。
目前.NET 中的設定是使用一個或多個設定提供程式
執行的。 設定提供程式使用各種設定源從鍵值對讀取設定資料,這些設定程式稍後我們會看到,讀取的設定源可以是如下這些:
IConfiguration 介面是所有設定源的單個表示形式,給定一個或多個設定源,IConfiguration 型別提供設定資料的統一檢視。
上圖我們可能沒有直觀的感受,現在寫一個例子來看看
(1). 新建控制檯應用程式:
建立控制檯使用的是.net 6.0 框架,vs 2022。
安裝 Microsoft.Extensions.Configuration.Json NuGet 包,該包提供json組態檔讀取。
Install-Package Microsoft.Extensions.Configuration.Json
(2). 新增appsettings.json 檔案
{
"person": {
"name": "XSpringSun",
"age": 18
}
}
(3). 使用json提供程式讀取json設定
new一個ConfigurationBuilder,新增json設定,AddJsonFile
是在包中的IConfigurationBuilder擴充套件方法,其它設定提供程式也是用這種擴充套件方法實現。
static void Main(string[] args)
{
IConfiguration configuration = new ConfigurationBuilder()
.AddJsonFile("appsettings.json")
.Build();
Console.WriteLine(configuration["person:name"]);
Console.WriteLine(configuration["person:age"]);
Console.WriteLine("Hello, World!");
Console.ReadLine();
}
可以看到已經取到json組態檔中的值了,設定值可以包含分層資料。 分層物件使用設定鍵中的 : 分隔符表示。在下面的偵錯物件中我們可以看到實際configuration的Providers 提供程式陣列有一個值,就是我們的JsonConfigurationProvider,並且JsonConfigurationProvider裡面已經讀取了json的資料儲存在Data陣列中。
對於如上幾行程式碼幹了什麼呢:
這樣已經實現json進行設定讀取,但是取值的方式似乎和以前沒什麼太大變法,所以.net提供了選項模式,選項模式就是使用類來提供對相關設定組的強型別存取。
我們建立一個Config
類用來轉換json:
namespace ConfigDemo
{
public class Config
{
public Person? person { get; set; }
}
public class Person {
public string? name { get; set; }
public int age { get; set; }
}
}
繫結設定
IConfiguration configuration = new ConfigurationBuilder()
.AddJsonFile("appsettings.json")
.Build();
Config options = new Config();
ConfigurationBinder.Bind(configuration, options);
Person person = configuration.GetSection("person").Get<Person>();
Console.WriteLine(options.person.name);
Console.WriteLine(options.person.age);
Console.WriteLine("-----------GetSection獲取-------------");
Console.WriteLine(person.name);
Console.WriteLine(person.age);
用了兩種方式獲取設定,第一種使用ConfigurationBinder.Bind()
將整個設定繫結到物件Config
上,另外一種是使用IConfiguration的GetSection().Get<T>()
並返回指定的型別。兩種方式都可以使用,看實際需求和用途。
在控制檯程式中我們參照DI注入包,然後演示下如何進行設定的注入。關於DI和IOC不清楚的看我上篇文章.net 溫故知新:【7】IOC控制反轉,DI依賴注入
public class TestOptionDI
{
private readonly IOptionsSnapshot<Config> _options;
public TestOptionDI(IOptionsSnapshot<Config> options)
{
_options = options;
}
public void Test()
{
Console.WriteLine("DI測試輸出:");
Console.WriteLine($"姓名:{_options.Value.person.name}");
Console.WriteLine($"年齡:{_options.Value.person.age}");
}
}
在測試類中我們使用IOptionsSnapshot<T>
介面作為依賴注入,還有其它不同定義的介面用來設定注入,關於選項介面:。
不同介面可以配合讀取設定的不同方式起作用,IOptionsSnapshot介面可以在組態檔改變後不同作用域進行重新整理設定。接著我們修改main方法,引入DI,並將AddJsonFile
方法的引數reloadOnChange設定為true,optional引數是否驗證檔案存在,建議開發時都設定為true,這樣如果檔案有問題會進行報錯。
注入設定這句services.AddOptions().Configure<Config>(e=>configuration.Bind(e))
是關鍵,通過容器呼叫AddOptions
方法註冊,然後Configure
方法裡面是一個委託方法,該委託的作用就是將設定的資訊系結到Config型別的引數e上。註冊到容器的泛型選項介面,這樣在TestOptionDI類建構函式注入就能注入IOptionsSnapshot
static void Main(string[] args)
{
IConfiguration configuration = new ConfigurationBuilder()
.AddJsonFile("appsettings.json",optional:true,reloadOnChange:true)
.Build();
//IServiceCollection 服務
ServiceCollection services = new ServiceCollection();
//注入設定
services.AddOptions().Configure<Config>(e=>configuration.Bind(e));
//注入TestOptionDI
services.AddScoped<TestOptionDI>();
using (var provider = services.BuildServiceProvider())
{
//獲取服務
var testOption = provider.GetRequiredService<TestOptionDI>();
testOption.Test();
}
Console.ReadLine();
}
為了測試IOptionsSnapshot介面在不同作用域會重新整理設定,我們修改下main方法,用一個while迴圈在ReadLine時修改json檔案值,不同的Scope裡進行列印。
using (var provider = services.BuildServiceProvider())
{
while (true)
{
using (var scope = provider.CreateScope())
{
//獲取服務
var testOption = scope.ServiceProvider.GetRequiredService<TestOptionDI>();
testOption.Test();
}
Console.ReadLine();
}
}
這個功能在web中使用很方便,因為框架的一次請求就是一個作用域,所以我們修改了設定,下次請求就能生效了,而不用重啟服務。
如最開始所說,不僅能設定json檔案,由於各種提供程式,還可以設定其它的,但是根據設定的順序會進行覆蓋。我們只新增一個環境變數設定演示下:
首先新增提供程式包:Install-Package Microsoft.Extensions.Configuration.EnvironmentVariables
。
然後新增環境變數設定程式碼AddEnvironmentVariables()
:
IConfiguration configuration = new ConfigurationBuilder()
.AddJsonFile("appsettings.json",optional:true,reloadOnChange:true)
.AddEnvironmentVariables()
.Build();
在VS中設定臨時環境變數
這裡有個扁平化設定,就是表示層級用冒號person:age
對於web專案我們沒有進行這麼多操作它是怎麼設定的呢,其實框架已經自動幫我們做了,其它非web專案也可以使用這種託管模式,在Microsoft.Extensions.Hosting 包中,只需要使用簡單的程式碼就能設定好。
IHost host = Host.CreateDefaultBuilder(args).Build();
await host.RunAsync();
其載入設定的優先順序:
通過分析我們對整個設定如何執行的機制有了一個大體的瞭解,如果想詳細瞭解託管模式的還是建議看官方檔案:.NET設定
作者:SunSpring
出處:https://www.cnblogs.com/SunSpring/p/16850510.html
本文版權歸作者所有,歡迎轉載,但未經作者同意需在文章頁面明顯位置給出原文連結。