一、前言
根據該issues來看,System.Configuration在.net core中已經不存在了,那么取而代之的是由Microsoft.Extensions.Cnfiguration.XXX一系列的類庫提供,對應的開源地址為點擊這里。
從當前開源的代碼來看,在.net core下提供了以下類庫給我們:
Microsoft.Extensions.Configuration.Abstractions:基礎接口
Microsoft.Extensions.Configuration:實現上面的基礎接口
Microsoft.Extensions.Configuration.FileProviderExtensions:提供重載配置擴展
Microsoft.Extensions.Configuration.Binder:提供轉換到實體功能
Microsoft.Extensions.Configuration.FileExtensions:提供配置文件根路徑擴展
以下為提供對哪些方式的支持:
Microsoft.Extensions.Configuration.CommandLine:命令行參數
Microsoft.Extensions.Configuration.EnvironmentVariables:環境變量
Microsoft.Extensions.Configuration.Ini:Ini格式
Microsoft.Extensions.Configuration.Json:Json格式
Microsoft.Extensions.Configuration.Xml:Xml格式
由上面類庫的數量我們可以看出今后我們不會在需要加載更多的庫,只要按需加載就可以了,那么我們也可以看到新的Configuration提供了更多格式的支持,當然我們自己也可以自行擴展以提供對更多格式的支持。下面我們開始進入正文,從頭到尾的學習這5種支持的配置格式。
注意:需要VS2015開發工具
二、正文
首先我們需要創建一個名為“CoreClrConfiguration”的空解決方案,下面將會在這一個解決方案中將下面幾節的內容進行演示。如果讀者只對其中某一個部分感興趣可以直接翻閱到對應的內容下,每個小節都是相互獨立的沒有對應關系。
應該新建哪種項目模板如下圖所示:
A. CommandLine(命令行參數)
在新建項目(名為“CommandLineCfg”)中的project.json中增加以下的依賴(具體版本請讀者根據實際情況決定):
"Microsoft.Extensions.Configuration.CommandLine": "1.0.0-rc1-final",
"Microsoft.Extensions.Configuration.Binder": "1.0.0-rc1-final"
需要注意的是該依賴庫為全局依賴庫,非dnx451或dnxcore50下的依賴庫。
注:在project.json指定完依賴庫之后需要右擊“引用”->“還原程序包”,之后的部分將不再闡述。
首先我們先舉一個簡單的例子,讀取一個參數的值。首先打開Program.cs文件在其中寫入以下的程序:
1 public static void Main(string[] args) 2 { 3 var cmdLineConfig = new CommandLineConfigurationProvider(args); 4 cmdLineConfig.Load(); 5 6 string value1 = null; 7 cmdLineConfig.TryGet("key1", out value1); 8 9 Console.WriteLine($"key1={value1}"); 10 11 Console.ReadKey(); 12 }
這里我們可以看到“CommandLineConfigurationProvider”的命名,后面我們介紹的能夠提供對其他格式的支持都會以“xxxConfigurationProvider”來命名的,並且基類都是“ConfigurationProvider”。簡單的介紹完之后下面我們需要開始運行該程序,我們先打開該項目的屬性,輸入一些測試用的命令行參數:
當然我們這里只是使用了其中一種支持的格式,其他支持的格式如下:
-Key1=Value1
--Key1=Value1
/Key1=Value1
--Key1 Value1
如果讀者,在應用程序參數中的后面重復寫了“/Key1 Value2”那么程序中只會采用最后一個設置的值且不區分大小寫。
注:如果命令行參數只傳遞了key而沒有傳遞value那么在load的時候就會拋出FormatException異常。
類似於我們常用的ORM一樣,對於外部命令行傳入的參數,key我們其實是可以自己做投影,將對應的key改為我們所希望的key。比如上面的“key1”我們就可以在改為“key2”。而要做到這一效果只需要在創建CommandLineConfigurationProvider的時候利用第二個參數將我們即可,比如下面我們將會將“key1”改為”key2”:
public static void Main(string[] args) { Dictionary<string, string> defaults = new Dictionary<string, string> { { "--Key1","key2" } }; var cmdLineConfig = new CommandLineConfigurationProvider(args, defaults); cmdLineConfig.Load(); string value1 = null; cmdLineConfig.TryGet("key2", out value1); Console.WriteLine($"key1&key2={value1}"); Console.ReadKey(); }
其中我們可以看到defaults字典中的key必須加上“--”或“-”否則在調用構造函數時將會拋出ArgumentException異常。最終我們可以看到獲取值的時候是利用后來我們投影之后的key的名稱去獲取而不是“key1”了。
除了通過上面這種方式獲取值之外,還提供了一個通用的模型綁定,能夠將其他的格式轉換為POCO,這樣能夠便於我們更快速的開發,下面筆者將通過兩種方式來講述,首先是利用我們當前已經創建好的Provider來進行Bind,其中POCO如下:
public class CommandLineArgs { public string Key1 { get; set; } }
Main方法的實現如下:
var cmdLineConfig = new CommandLineConfigurationProvider(args); var builder = new ConfigurationBuilder(); builder.Add(cmdLineConfig); var item = builder.Build().Get<CommandLineArgs>(); Console.WriteLine($"key1&key2={item.Key1}");
其中ConfigurationBuilder可以管理多個Provider,比如我們開發一個系統可以將命令行、Json文件、Ini文件和XML文件都添加到其中進行管理。如果我們調用了Builder方法,那么我們就可以利用其返回值統一的獲取我們想要的值,內部會從這些Provider中嘗試獲取我們需要的值如果有值則立即返回,而模型綁定是通過對其擴展加進去的。具體擴展了以下的方法:
public static class ConfigurationBinder { public static void Bind(this IConfiguration configuration, object instance); public static object Get(this IConfiguration configuration, Type type); public static object Get(this IConfiguration configuration, Type type, string key); public static T Get<T>(this IConfiguration configuration); public static T Get<T>(this IConfiguration configuration, T defaultValue); public static T Get<T>(this IConfiguration configuration, string key); public static T Get<T>(this IConfiguration configuration, string key, T defaultValue); }
其實現在Microsoft.Extensions.Configuration.Binder中。
另一種方式則是不通過創建CommandLineConfigurationProvider直接利用ConfigurationBuilder實現相同的效果:
var builder = new ConfigurationBuilder(); builder.AddCommandLine(args); var item = builder.Build().Get<CommandLineArgs>(); Console.WriteLine($"key1={item.Key1}");
其中AddCommandLine也是擴展方法,並且下面的四種中都有對應的擴展,內部的實現其實就是創建了Provider,比如這個方法的內部實現如下:
1 public static IConfigurationBuilder AddCommandLine(this IConfigurationBuilder configurationBuilder, string[] args) 2 { 3 configurationBuilder.Add(new CommandLineConfigurationProvider(args)); 4 return configurationBuilder; 5 }
到這里關於命令行參數告一段落,如果讀者想了解更多的信息,可以查看對應的源碼以及單元測試。
B. EnvironmentVariables(環境變量)
在新建項目(名為“EnvironmentVariablesCfg”)中的Project.json中增加以下的依賴:
"Microsoft.Extensions.Configuration.EnvironmentVariables": "1.0.0-rc1-final",
"Microsoft.Extensions.Configuration.Binder": "1.0.0-rc1-final"
需要注意的是該依賴庫為全局依賴庫,非dnx451或dnxcore50下的依賴庫。
跟之前的格式一樣,我們這里先通過一個簡單的例子來講述如何使用。相信很多新建過.NET Core項目的人都曾看到屬性窗口中的“環境變量”,但是卻不知道如何使用,而本節我們將會利用它讀取對應的配置信息。首先我們在其中新建一個值:
然后我們打開Program.cs寫入以下的程序:
public static void Main(string[] args) { var provider = new EnvironmentVariablesConfigurationProvider(); provider.Load(); string value = null; provider.TryGet("con", out value); Console.WriteLine($"con={value}"); Console.ReadKey(); }
我們可以看到跟上一節的方式是一模一樣的,這樣對於我們今后自己進行擴展來說,就避免的我們系統內部的修改。
如果讀者細心查看provider中的Data會發現其中不僅僅保存我們的配置信息還保存了大量的系統配置信息,這是因為在調用Load的時候內部還將系統配置信息也讀取了,對應的源碼如下:
public override void Load() { Load(Environment.GetEnvironmentVariables()); }
在我們初始化provider時可以看到構造函數還支持prefix,那么下面我們利用prefix來定義一個擁有自己前綴的配置避免跟其他的配置信息相互沖突:
var provider = new EnvironmentVariablesConfigurationProvider("cfg:"); provider.Load(); string value = null; provider.TryGet("con", out value); Console.WriteLine($"con={value}"); Console.ReadKey();
讀者還要記得到項目的屬性中將環境配置中的變量的key改成cfg:Con,否則value獲取出來的就是null了。
相信聰明的讀者已經知道對應的如何使用了,所以筆者在這里只列出對應的代碼(兩種方式)。
public class EnvirVarCfg { public string Con { get; set; } }
方式1:
var provider = new EnvironmentVariablesConfigurationProvider("cfg:"); var builder = new ConfigurationBuilder(); builder.Add(provider); var item = builder.Build().Get<EnvirVarCfg>(); Console.WriteLine($"con={item.Con}");
方式2:
var builder = new ConfigurationBuilder(); builder.AddEnvironmentVariables("cfg:"); var item = builder.Build().Get<EnvirVarCfg>(); Console.WriteLine($"con={item.Con}");
至此環境變量這節就結束了,如果已經掌握規律的讀者下面三節應該很快就能夠掌握了。
C. Ini
在新建的項目(名為“IniCfg”)中的Project.json中增加以下的依賴:
"Microsoft.Extensions.Configuration.Ini": "1.0.0-rc1-final",
"Microsoft.Extensions.Configuration.Binder": "1.0.0-rc1-final"
需要注意的是該依賴庫為全局依賴庫,非dnx451或dnxcore50下的依賴庫。
首先我們在項目根目錄下新建一個“config.ini”文件,並在其中寫入如下的內容以便我們讀取:
[SegOne] Con=localhost [SegTwo] Con=192.168.1.113 Ext:Port=5535 [Seg:Three] Con=192.169.12.12
然后我們打開Program.cs文件寫入如下代碼去讀取配置文件中的內容:

1 public static void Main(string[] args) 2 { 3 string path = Path.Combine(Directory.GetCurrentDirectory(), "config.ini"); 4 var provider = new IniConfigurationProvider(path); 5 provider.Load(); 6 7 string segoneCon = null; 8 provider.TryGet("SegOne:Con", out segoneCon); 9 Console.WriteLine($"SegOne-Con={segoneCon}"); 10 11 string segtwoCon = null; 12 provider.TryGet("SegTwo:Con", out segtwoCon); 13 Console.WriteLine($"SegTwo-Con={segtwoCon}"); 14 15 string segtwoExtPort = null; 16 provider.TryGet("SegTwo:Ext:Port", out segtwoExtPort); 17 Console.WriteLine($"SegTwo-Ext:Port={segtwoExtPort}"); 18 19 string segthreeCon = null; 20 provider.TryGet("Seg:Three:Con", out segthreeCon); 21 Console.WriteLine($"Seg:Three-Con={segthreeCon}"); 22 23 Console.ReadKey(); 24 }
相同很多人都看見過類似的配置文件,特別是在搭建一些服務的時候,那么從.net core開始也將原生支持這些配置,當然上面的示例中沒有給出對應的注釋,對應的注釋要以“;”、“#”和“/”開頭即可。
因為在該結構下會存在復雜類型包含復雜類型的情況,所以下面我們的模型可能比較復雜:

1 public class IniModelCfg 2 { 3 public SegOne SegOne { get; set; } 4 public SegTwo SegTwo { get; set; } 5 public Seg Seg { get; set; } 6 } 7 8 public class SegOne 9 { 10 public string Con { get; set; } 11 } 12 13 public class SegTwo 14 { 15 public string Con { get; set; } 16 public Ext Ext { get; set; } 17 } 18 19 public class Ext 20 { 21 public string Port { get; set; } 22 } 23 24 public class Seg 25 { 26 public Three Three { get; set; } 27 } 28 29 public class Three 30 { 31 public string Con { get; set; } 32 }
第一種實現方式:
string path = Path.Combine(Directory.GetCurrentDirectory(), "config.ini"); var provider = new IniConfigurationProvider(path); var builder = new ConfigurationBuilder(); builder.Add(provider); var item = builder.Build().Get<IniModelCfg>(); Console.WriteLine($"SegOne-Con={item.SegOne.Con}"); Console.WriteLine($"SegTwo-Con={item.SegTwo.Con}"); Console.WriteLine($"SegTwo-Ext:Port={item.SegTwo.Ext.Port}"); Console.WriteLine($"Seg:Three-Con={item.Seg.Three.Con}");
第二種實現方式:
string path = Path.Combine(Directory.GetCurrentDirectory(), "config.ini"); var builder = new ConfigurationBuilder(); builder.AddIniFile(path); var item = builder.Build().Get<IniModelCfg>(); Console.WriteLine($"SegOne-Con={item.SegOne.Con}"); Console.WriteLine($"SegTwo-Con={item.SegTwo.Con}"); Console.WriteLine($"SegTwo-Ext:Port={item.SegTwo.Ext.Port}"); Console.WriteLine($"Seg:Three-Con={item.Seg.Three.Con}");
D. Json
在新建的項目(名為“JsonCfg”)中的Project.json中增加以下的依賴:
"Microsoft.Extensions.Configuration.Json": "1.0.0-rc1-final",
"Microsoft.Extensions.Configuration.Binder": "1.0.0-rc1-final"
需要注意的是該依賴庫為全局依賴庫,非dnx451或dnxcore50下的依賴庫。
首先我們在項目根目錄下新建一個“config.json”文件並在其中寫入如下的內容以便測試:
{ "url": "localhost", "port": { "one": 1234, "two": 456 } }
然后打開Program.cs文件並在其中寫入如下內容:
string path = Path.Combine(Directory.GetCurrentDirectory(), "config.json"); var provider = new JsonConfigurationProvider(path); provider.Load(); string url = null; provider.TryGet("url", out url); Console.WriteLine($"url={url}"); string one = null; provider.TryGet("port:one", out one); Console.WriteLine($"port-one={one}"); string two = null; provider.TryGet("port:two", out two); Console.WriteLine($"port0two={two}"); Console.ReadKey();
如何獲取某個元素的元素跟Ini方式下是統一的,都是通過冒號來分割。
基本跟之前的還是一樣的,筆者還是會給出對應的代碼,首先是模型相關的代碼:

1 public class JsonModelCfg 2 { 3 public string Url { get; set; } 4 public Port Port { get; set; } 5 } 6 7 public class Port 8 { 9 public string One { get; set; } 10 public string Two { get; set; } 11 }
第一種實現方式:
string path = Path.Combine(Directory.GetCurrentDirectory(), "config.json"); var provider = new JsonConfigurationProvider(path); var builder = new ConfigurationBuilder(); builder.Add(provider); var item = builder.Build().Get<JsonModelCfg>(); Console.WriteLine($"url={item.Url}"); Console.WriteLine($"port-one={item.Port.One}"); Console.WriteLine($"port-two={item.Port.Two}");
第二種實現方式:

1 string path = Path.Combine(Directory.GetCurrentDirectory(), "config.json"); 2 var builder = new ConfigurationBuilder(); 3 builder.AddJsonFile(path); 4 var item = builder.Build().Get<JsonModelCfg>(); 5 6 Console.WriteLine($"url={item.Url}"); 7 Console.WriteLine($"port-one={item.Port.One}"); 8 Console.WriteLine($"port-two={item.Port.Two}");
E. Xml
在新建的項目(名為“XmlCfg”)中的Project.json中增加以下的依賴:
"Microsoft.Extensions.Configuration.Xml": "1.0.0-rc1-final",
"Microsoft.Extensions.Configuration.Binder": "1.0.0-rc1-final"
需要注意的是該依賴庫為全局依賴庫,非dnx451或dnxcore50下的依賴庫。
在項目根目錄下新建一個“config.xml”文件並在其中寫入如下內容以便后面的測試:
<settings> <data> <con>123456</con> </data> <inventory value="test" /> </settings>
然后打開Program.cs文件並在其中寫入如下代碼:
string path = Path.Combine(Directory.GetCurrentDirectory(), "config.xml"); var provider = new XmlConfigurationProvider(path); provider.Load(); string con = null; provider.TryGet("data:con", out con); Console.WriteLine($"con={con}"); string name = null; provider.TryGet("inventory:value", out name); Console.WriteLine($"value={name}"); Console.ReadKey();
對應的模型綁定就不再重復了,完全一模一樣了。至此所有的配置相關的內容就介紹完畢了。