本篇將記錄.Net Core里頗有特色的結(jié)構(gòu)化配置的使用方法。
相比較之前通過(guò)Web.Config或者App.Config配置文件里使用xml節(jié)點(diǎn)定義配置內(nèi)容的方式,.Net Core在配置系統(tǒng)上發(fā)生了很大的變化,具有了配置源多樣化、更加輕量、擴(kuò)展性更好的特點(diǎn)。
如果要使用結(jié)構(gòu)化配置,需要先引用 "Microsoft.Extensions.Configuration": "1.0.0" nuget包。下面通過(guò)一個(gè).Net Core控制臺(tái)程序演示
1 using Microsoft.Extensions.Configuration; 2 using Microsoft.Extensions.Configuration.Memory; 3 using System; 4 using System.Collections.Generic; 5 6 namespace DiApplicationTest 7 { 8 public class Program 9 {10 public static void Main(string[] args)11 {12 IDictionary<string, string> source = new Dictionary<string, string>()13 {14 ["Ele1"] = "value1",15 ["Ele2"] = "value2"16 };17 18 IConfiguration config = new ConfigurationBuilder().Add(new MemoryConfigurationSource() { InitialData = source }).Build();19 Console.WriteLine($"Ele1: {config["Ele1"]}");20 Console.WriteLine($"Ele2: {config["Ele2"]}");21 22 Console.ReadLine();23 }24 }25 }
啟動(dòng)調(diào)試,查看cmd窗口輸出內(nèi)容
上面的例子里,將一個(gè)字典作為配置源讀入到config配置對(duì)象里,通過(guò)鍵可以讀取到對(duì)應(yīng)的值。
在大多數(shù)情況下,項(xiàng)目里的配置都是多層結(jié)構(gòu)的,也可以稱(chēng)為是結(jié)構(gòu)化的。在上面的例子的基礎(chǔ)上稍加修改,實(shí)現(xiàn)結(jié)構(gòu)化的配置讀取。
1 using Microsoft.Extensions.Configuration; 2 using Microsoft.Extensions.Configuration.Memory; 3 using System; 4 using System.Collections.Generic; 5 6 namespace DiApplicationTest 7 { 8 public class Program 9 {10 public static void Main(string[] args)11 {12 IDictionary<string, string> source = new Dictionary<string, string>()13 {14 ["Ele1"] = "value1",15 ["Ele2:Sub1"] = "value2.1",16 ["Ele2:Sub2"] = "value2.2"17 };18 19 IConfiguration config = new ConfigurationBuilder().Add(new MemoryConfigurationSource() { InitialData = source }).Build();20 Console.WriteLine($"Ele1: {config["Ele1"]}");21 Console.WriteLine($"Ele2.Sub1: {config.GetSection("Ele2")["Sub1"]}");22 Console.WriteLine($"Ele2.Sub2: {config.GetSection("Ele2")["Sub2"]}");23 24 Console.ReadLine();25 }26 }27 }
啟動(dòng)調(diào)試,查看cmd窗口輸出內(nèi)容
在這個(gè)例子里,字典內(nèi)容描述了一個(gè)具有兩層結(jié)構(gòu)的配置,第一層有Ele1和Ele2兩個(gè)節(jié)點(diǎn),分別對(duì)應(yīng)一個(gè)字符內(nèi)容和一個(gè)復(fù)合內(nèi)容,第二層有Sub1和Sub2兩個(gè)節(jié)點(diǎn),同時(shí)掛在Ele2節(jié)點(diǎn)下,組成了一個(gè)復(fù)合結(jié)構(gòu)。
注意看字典項(xiàng)里的Key,因?yàn)樽值淅锏臄?shù)據(jù)是扁平化的,為了能清晰描述節(jié)點(diǎn)之間的上下層關(guān)系,需要通過(guò)“:”符號(hào)來(lái)標(biāo)識(shí)。
config對(duì)象通過(guò)GetSection方法來(lái)獲取當(dāng)前節(jié)點(diǎn)的某個(gè)下級(jí)節(jié)點(diǎn)內(nèi)容。
除了上面例子里展示的配置源來(lái)自?xún)?nèi)存內(nèi)容,也可以來(lái)自Xml文件、JSON文件或者數(shù)據(jù)庫(kù)等。因?yàn)樵?Net Core里使用JSON文件描述配置內(nèi)容很常見(jiàn),下面就展示如何讀取JSON配置文件。
先添加如下兩個(gè)nuget包,支持從json文件讀取內(nèi)容
"Microsoft.Extensions.Configuration.FileExtensions": "1.0.0","Microsoft.Extensions.Configuration.Json": "1.0.0",
添加 appsettings.json 文件
修改Main函數(shù)內(nèi)容
1 using Microsoft.Extensions.Configuration; 2 using System; 3 using System.IO; 4 5 namespace DiApplicationTest 6 { 7 public class Program 8 { 9 public static void Main(string[] args)10 {11 IConfigurationBuilder builder = new ConfigurationBuilder();12 builder.SetBasePath(Directory.GetCurrentDirectory());13 builder.AddJsonFile("appsettings.json");14 15 IConfiguration config = builder.Build();16 Console.WriteLine($"Ele1: {config["Ele1"]}");17 Console.WriteLine($"Ele2.Sub1: {config.GetSection("Ele2")["Sub1"]}");18 Console.WriteLine($"Ele2.Sub2: {config.GetSection("Ele2")["Sub2"]}");19 20 Console.ReadLine();21 }22 }23 }
啟動(dòng)調(diào)試,查看cmd窗口輸入內(nèi)容,與上面的例子內(nèi)容一致。
這個(gè)例子將原來(lái)在字典里的內(nèi)容轉(zhuǎn)換成Json格式化的內(nèi)容存儲(chǔ)在持久化文件里。通過(guò)指定配置源,同樣可以讀取內(nèi)容。
當(dāng)配置文件內(nèi)容較多時(shí),通過(guò)config的Key獲取對(duì)應(yīng)的配置項(xiàng)的值變得比較繁瑣。.Net Core的配置系統(tǒng)采用了一種叫“Options Pattern”的模式使配置內(nèi)容與有著對(duì)應(yīng)結(jié)構(gòu)的對(duì)象進(jìn)行映射,這種對(duì)象就叫做Options對(duì)象。
下面將簡(jiǎn)單演示一下這種映射方式。
首先添加如下nuget包引用,使用此模式的相關(guān)接口和類(lèi)都在這個(gè)包里。同時(shí)還需要引入DI容器。
"Microsoft.Extensions.DependencyInjection": "1.0.0","Microsoft.Extensions.Options.ConfigurationExtensions": "1.0.0",
添加兩個(gè)具有層級(jí)結(jié)構(gòu)的Options類(lèi)
1 public class ConfigOptions 2 { 3 public string Ele1 { get; set; } 4 public SubConfigOptions Ele2 { get; set; } 5 } 6 7 public class SubConfigOptions 8 { 9 public string Sub1 { get; set; }10 public string Sub2 { get; set; }11 }
修改Main函數(shù)內(nèi)容
1 public static void Main(string[] args) 2 { 3 // 創(chuàng)建DI容器,注冊(cè)O(shè)ptions Pattern服務(wù) 4 IServiceCollection services = new ServiceCollection(); 5 services.AddOptions(); 6 7 // 讀取配置文件 8 IConfigurationBuilder builder = new ConfigurationBuilder(); 9 builder.SetBasePath(Directory.GetCurrentDirectory());10 builder.AddJsonFile("appsettings.json");11 IConfiguration config = builder.Build();12 13 // 通過(guò)注冊(cè)的服務(wù)獲取最終映射的配置對(duì)象14 IServiceProvider serviceProvider = services.Configure<ConfigOptions>(config).BuildServiceProvider();15 ConfigOptions options = serviceProvider.GetService<IOptions<ConfigOptions>>().Value;16 17 Console.WriteLine($"Ele1: {options.Ele1}");18 Console.WriteLine($"Ele2.Sub1: {options.Ele2.Sub1}");19 Console.WriteLine($"Ele2.Sub2: {options.Ele2.Sub2}");20 21 Console.ReadLine();22 }
啟動(dòng)調(diào)試,查看cmd窗口輸入內(nèi)容,與上面的例子內(nèi)容一致。
在定義Options對(duì)象結(jié)構(gòu)時(shí),對(duì)象內(nèi)的屬性名稱(chēng)要與對(duì)應(yīng)層級(jí)的配置Key的值保持一致,層級(jí)關(guān)系也要與配置內(nèi)容的層級(jí)結(jié)構(gòu)保持一致。
通過(guò)調(diào)用 services.AddOptions() 方法注冊(cè)O(shè)ptions Pattern服務(wù)。將配置內(nèi)容注冊(cè)到容器里,來(lái)獲取對(duì)應(yīng)的服務(wù)Provider對(duì)象。通過(guò)調(diào)用GetService方法獲得對(duì)應(yīng)的真實(shí)服務(wù)對(duì)象,即帶有事先定義的Options類(lèi)型的泛型接口IOptions,接口的Value值就是配置內(nèi)容映射的Options對(duì)象。
在這個(gè)系列之前使用的例子里添加配置管理相關(guān)的功能,來(lái)修改初始化日志級(jí)別的代碼,同時(shí)添加一些自定義配置。
先添加配置相關(guān)的nuget包
"Microsoft.Extensions.Configuration": "1.0.0", "Microsoft.Extensions.Configuration.FileExtensions": "1.0.0", "Microsoft.Extensions.Configuration.Json": "1.0.0", "Microsoft.Extensions.Options.ConfigurationExtensions": "1.0.0"
添加appsettings.json文件
1 { 2 // 日志配置 3 "Logging": { 4 "LogLevel": { 5 "Microsoft": "Warning" 6 } 7 }, 8 // 自定義配置 9 "CfgContent": {10 "Ele1": "value1",11 "Ele2": {12 "Sub1": "value2.1",13 "Sub2": "value2.2"14 }15 }16 }
添加上個(gè)例子里的 ConfigOptions.cs、SubConfigOptions.cs 類(lèi),修改 Startup.cs 的內(nèi)容,添加配置相關(guān)代碼
1 using System.IO; 2 using Microsoft.AspNetCore.Builder; 3 using Microsoft.Extensions.Configuration; 4 using Microsoft.Extensions.DependencyInjection; 5 using Microsoft.Extensions.Logging; 6 7 namespace WebApiFrame 8 { 9 public class Startup10 {11 public IConfiguration Configuration { get; }12 13 public Startup()14 {15 var builder = new ConfigurationBuilder()16 .SetBasePath(Directory.GetCurrentDirectory())17 .AddJsonFile("appsettings.json");18 19 Configuration = builder.Build();20 }21 22 public void ConfigureServices(IServiceCollection services)23 {24 services.AddOptions();25 services.Configure<ConfigOptions>(Configuration.GetSection("CfgContent"));26 27 // 注入MVC框架28 services.AddMvc();29 }30 31 public void Configure(IApplicationBuilder app, ILoggerFactory loggerFactory)32 {33 // 添加日志支持34 loggerFactory.AddConsole(Configuration.GetSection("Logging"));35 loggerFactory.AddDebug();36 37 // 添加NLog日志支持38 //loggerFactory.AddNLog();39 40 // 添加MVC中間件41 app.UseMvc();42 }43 }44 }
修改 DemoController.cs 內(nèi)容
1 using System.Threading.Tasks; 2 using Microsoft.AspNetCore.Http; 3 using Microsoft.AspNetCore.Mvc; 4 using Microsoft.Extensions.Options; 5 6 namespace WebApiFrame 7 { 8 [Route("[controller]")] 9 public class DemoController : Controller10 {11 private ConfigOptions _cfgContent { get; }12 13 public DemoController(IOptions<ConfigOptions> options)14 {15 _cfgContent = options.Value;16 }17 18 [HttpGet("index")]19 public async Task Index()20 {21 HttpContext.Response.ContentType = "text/html";22 await HttpContext.Response.WriteAsync($"<span>Ele1: {_cfgContent.Ele1}</span><br />");23 await HttpContext.Response.WriteAsync($"<span>Ele2.Sub1: {_cfgContent.Ele2.Sub1}</span><br />");24 await HttpContext.Response.WriteAsync($"<span>Ele2.Sub2: {_cfgContent.Ele2.Sub2}</span><br />");25 }26 }27 }
啟動(dòng)調(diào)試,訪問(wèn)地址 http://localhost:5000/demo/index ,頁(yè)面顯示配置內(nèi)容
從這個(gè)例子里可以看到,讀取 appsettings.json 配置文件內(nèi)容并分成兩部分,其中一部分配置Logging作為L(zhǎng)ogger的配置內(nèi)容用于日志初始化,另外一部分CfgContent配置內(nèi)容注冊(cè)到DI容器,在控制器的構(gòu)造函數(shù)里通過(guò)IOptions泛型類(lèi)型的參數(shù)注入,這樣控制器就可以讀取配置文件的內(nèi)容。
聯(lián)系客服