.Net Core下如何管理配置文件

1、前言

根据该issues来看,System.Configuration在.net core中已经不存在了,那么取而代之的是由Microsoft.Extensions.Cnfiguration.XXX一系列的类库提供,对应的开源地址为点击这里git

 

从当前开源的代码来看,在.net core下提供了如下类库给咱们:github

Microsoft.Extensions.Configuration.Abstractions:基础接口json

Microsoft.Extensions.Configuration:实现上面的基础接口ide

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开发工具

 

2、正文

首先咱们须要建立一个名为“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         }
View Code

 

相同不少人都看见过相似的配置文件,特别是在搭建一些服务的时候,那么从.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     }
View Code

 

 

第一种实现方式:

            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     }
View Code

 

 

第一种实现方式:

            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}");
View Code

 

 

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();

 

对应的模型绑定就再也不重复了,彻底如出一辙了。至此全部的配置相关的内容就介绍完毕了。

相关文章
相关标签/搜索