簡讀《ASP.NET Core技術內幕與項目實戰》之3:配置

特別說明:
1、本系列內容主要基於楊中科老師的書籍《ASP.NET Core技術內幕與項目實戰》及配套的B站影片影片教程,同時會增加極少部分的小知識點
2、本系列教程主要目的是提煉知識點,追求快准狠,以求快速複習,如果說書籍學習的效率是影片的2倍,那麼「簡讀系列」應該做到再快3-5倍

 

本節內容,涉及3.2(P60-P69),7.2(P188-P193),NuGet包

  • Microsoft.Extensions.Configuration
  • Microsoft.Extensions.Configuration.Json
  • Microsoft.Extensions.Configuration.CommandLine
  • Microsoft.Extensions.Configuration.EnvironmentVariables
  • Microsoft.Extensions.Configuration.Binder
  • Microsoft.Extensions.Options
  • ...

 

一、直接讀取配置

 1 //appsetting.json文件,需設置為「如果較新則複製」
 2 {
 3   "name": "functionMC",
 4   "proxy": {
 5     "address": "192.1.1.1",
 6     "port": 1088
 7   }
 8 }
 9 
10 
11 //Program.cs
12 ConfigurationBuilder configBuilder = new ConfigurationBuilder();
13 configBuilder.AddJsonFile("appsettings.json", optional: false, reloadOnChange:false);
14 IConfigurationRoot config = configBuilder.Build();
15 
16 string name = config["proxy:address"];
17 Console.WriteLine(name);
18 
19 string proxyAddress = config.GetSection("name").Value;
20 Console.WriteLine(proxyAddress);

程式碼解釋:

12-13行:構建ConfigurationBuild對象,並調用該對象的AddJsonFile方法,載入Json配置文件

14行:調用ConfigurationBuild對象的Build方法,構建IConfigurationRoot對象-config,用於讀取配置

16行:通過config["key"]方式,讀取key值,讀取聯級key的方式,與config.GetSection一致,"proxy:address"

19行:通過config.GetSection方法,讀取key值

補充說明:

①涉及類型: ConfigurationBuild(配置)、IConfigurationRoot(讀取)-體現面向介面編程,根據不同的配置源有不同的實現

②13行可以設置其它配置源:

  • 從命令行讀取:configBuild.AddCommandLine(args);
  • 從環境變數讀取:configBuild.AddEnvironmentVariables("Test_"),其中Test_為環境變數的前綴,可以實現過濾
  • 其它配置源:INI文件、XML文件、Key-per-file文件、用戶機密、第三方配置提供程式等
  • 當在13行,配置多個數據源時,按Add的添加順序讀取,如果多個配置源設置了相同的key,則後面的key值覆蓋前面的key值
  • 在ASP.NET Core,已經默認添加了多個配置源,添加順序為appsettings.json < appsettings.[運行時環境變數].json< 用戶機密 < 環境變數 < 命令行

 ③在VS上設置命令行參數和環境變數的入口,項目右擊>屬性>調試>打開調試啟動配置文件UI。用戶機密入口,項目右擊>管理用戶機密

 

 

二、通過選項方式讀取

 1 //appsettings.json文件
 2 {
 3   "Smtp": {
 4     "Server": "smtp.youzack.com",
 5     "UserName": "functionMC",
 6     "Password": "hello123"
 7   },
 8   "Db": {
 9     "DbType": "SQLServer",
10     "ConnectionString": "Data..."
11   }
12 }
13 
14 
15 //兩個與配置Smtp和Db關聯的類
16 //SmtpSettings.cs
17 class SmtpSettings
18 {
19     public string Server { get; set; }
20     public string UserName { get; set; }
21     public string Password { get; set; }
22 }
23 
24 //DbSettings.cs
25 class DbSettings
26 {
27     public string DbType { get; set; }
28     public string ConnectionString { get; set; }
29 }
30 
31 
32 //配置、選項綁定,並調用一個方法來讀取配置
33 //Program.cs
34 ConfigurationBuilder configBuilder = new ConfigurationBuilder();
35 configBuilder.AddJsonFile("appsettings.json", optional: false, reloadOnChange:true);
36 IConfigurationRoot config = configBuilder.Build();
37 
38 ServiceCollection services = new ServiceCollection();
39 services.AddOptions()
40     .Configure<DbSettings>(e=>config.GetSection("Db").Bind(e))
41     .Configure<SmtpSettings>(e=>config.GetSection("Smtp").Bind(e));
42 
43 services.AddTransient<ReadOptions>();
44 
45 using (var sp = services.BuildServiceProvider())
46 {
47     while (true)
48     {
49         using (var scope = sp.CreateScope())
50         {
51             var sp_scope = scope.ServiceProvider;
52             var readOptions = sp_scope.GetRequiredService<ReadOptions>();
53             readOptions.Read();
54         }
55         Console.WriteLine("修改appsettings後,按任意鍵讀取最新的配置");
56         Console.ReadKey();
57     }
58 }
59 
60 
61 //讀取配置的方法類
62 //ReadOptions.cs
63 class ReadOptions
64 {
65     private readonly IOptionsSnapshot<SmtpSettings> optSmtpSettings;
66     private readonly IOptionsSnapshot<DbSettings> optDbSettings;
67 
68     public ReadOptions(IOptionsSnapshot<SmtpSettings> optSmtpSettings, IOptionsSnapshot<DbSettings> optDbSettings)
69     {
70         this.optSmtpSettings = optSmtpSettings;
71         this.optDbSettings = optDbSettings;
72     }
73 
74     public void Read()
75     {
76         var smtp = optSmtpSettings.Value;
77         var db = optDbSettings.Value;
78         Console.WriteLine(smtp.UserName);
79         Console.WriteLine(db.DbType);
80     }
81 }

程式碼解釋:

17-29行:定義兩個類(選項類),分別映身appsettings的兩個屬性。SmtpSettings.cs映射Smtp屬性,DbSettings.cs映射Db屬性,名字一一對應

38行:構建依賴注入的容器

39-41行:註冊選項服務AddOptions,並設置「選項類和配置文件屬性」之間的映射關係。這樣寫也可以:services.AddOption;services.Configure<DbSettings>...... 

43行:將讀取配置的類註冊為瞬時服務(ReadOptions),這樣在後面循環讀取配置時,每次都能創建一個新的服務

45-58行:通過服務定位器的方式獲取服務(ReadOptions對象),使用了子域方式,稍顯複雜,主要目的是測試修改appsettings時的實時更新

63-81行:以依賴注入的方式,注入讀取配置的服務,注意不能直接使用SmtpSettings或DbSettings,需要使用IOptions<T>泛型介面

補充說明:

①讀取配置的泛型介面,有三種:IOptions<T>(類似單例),IOptionsMonitor<T>(類似範圍),IOptionsSnapshot<T>(類似瞬時)。以上案例,改成另外兩個,都無法實現配置資訊的實時更新。其中IOptions<T>,需要重啟應用;IOptionsMonitor<T>,重啟應用,或者修改程式碼,不在Scope中讀取

 

 

三、在ASP.NET Core中設置和讀取配置(本節有補充知識點)

 1 //appsettings.json文件
 2 {
 3   "Smtp": {
 4     "Server": "192.1.1.1",
 5     "UserName": "functionMC",
 6     "Password": "123456"
 7   }
 8 }
 9 
10 
11 //選項類SmtpSettings.cs
12 public class SmtpSettings
13 {
14     public string Server { get; set; }
15     public string UserName { get; set; }
16     public string Password { get; set; }
17 }
18 
19 
20 //使用MiniApi方式,直接在Program中設置選項綁定和讀取配置
21 var builder = WebApplication.CreateBuilder(args);
22 builder.Services.Configure<SmtpSettings>(builder.Configuration.GetSection("Smtp"));
23 
24 var app = builder.Build();
25 
26 app.MapGet("/", (IConfiguration config,IOptions<SmtpSettings> smtpOptions) =>
27 {
28     return $"直接讀取:{config["Smtp:UserName"]},選項讀取:{smtpOptions.Value.UserName}";
29 });
30 
31 app.Run();

程式碼解釋:

21行:CreateBuilder完成一系列框架設置,包括配置體系(AddJsonFile,AddOptions等),所以不需要手動設置配置體系,框架自動設置多配置源

22行:綁定選項類和配置屬性。在Program中不方便注入,通過調用build的屬性Configuration,返回IConfiguration介面讀取配置(區別於.NET中的IConfigurationRoot)

26行:通過MiniApi的參數注入兩個服務,IConfigurations和IOptions<T>,均由框架自動註冊。如果使用控制器,可通過構造函數方式注入

28行:使用兩種方式讀取配置:直接讀取配置、通過選項方式讀取配置