配置系统 .NET Core中提供了非常强大的配置系统以简化配置相关代码的编写方法。
配置系统的基本使用 .NET Core中的配置系统支持非常丰富的配置源,包括文件(JSON、XML、INI等)、注册表、环境变量、命令行、Azure Key Vault等, 配置系统还支持自定义配置源。 .NET Core中读取配置有很多种方式,既可以通过IConfigurationRoot读取配置,也可以使用绑定的方式把配置读取为一个C#对象。
在项目根目录下添加一个JSON文件,命名为:config.json
因为程序在运行的时候默认加载EXE文件同文件夹下的配置文件,而不是项目中的config.json文件,所以我们需要把config.json文件设置为生成项目的时候自动被复制到生成目录。
.NET Core中配置系统的基础开发包是
1 Microsoft.Extensions.Configuration,
而读取JSON文件的开发包是
1 Microsoft.Extensions.Configuration.Json
,用NuGet安装这两个包。
1 2 3 4 5 6 7 8 9 10 11 { "name" : "YOUXIANYU" , "age" : "19" , { "name" : "Almango" , "proxy" : { "address" : "255.255.255.255" , "port" : "80" } } }
收到读取代码
1 2 3 4 5 6 7 8 9 10 11 12 using Microsoft.Extensions.Configuration;using Microsoft.Extensions.Configuration.Json;ConfigurationBuilder configurationBuilder=new ConfigurationBuilder(); configurationBuilder.AddJsonFile("config.json" ,optional:false ,reloadOnChange:true ); IConfigurationRoot configRoot= configurationBuilder.Build(); string name=configRoot["name" ];Console.WriteLine($"name={name} " ); string add =configRoot.GetSection("proxy:address" ).Value;Console.WriteLine($"address={add } " ); Console.ReadKey();
绑定读取配置(*) 可以绑定一个类,自动完成配置的读取
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 ConfigurationBuilder configurationBuilder=new ConfigurationBuilder(); configurationBuilder.AddJsonFile("config.json" ,optional:false ,reloadOnChange:true ); IConfigurationRoot configRoot= configurationBuilder.Build(); Config config = configRoot.Get<Config>(); Console.WriteLine(config.Name); Console.WriteLine(config.Proxy.Port); Console.ReadKey(); class Config { public string Name { get ; set ; } public int Add { get ; set ; } public string Address { get ; set ; } public Proxy Proxy { get ; set ; } } class Proxy { public string Address { get ; set ; } public int Port { get ; set ; } }
ConfigurationBuilder添加了一个待解析的配置文件。optional参数表示这个文件是否可选,如果它的值为trun,则当配置文件不存在的时候,程序不会报错;如果它的值为false,当配置文件不存在的时候,程序会报错。
IConfigurationRoot对象,我们能够通过他读取配置项,如果配置分级,也可以用“proxy:address”这种冒号分隔的方式读取配置项。
IConfigurationRoot中有一个GetConnectionString(string name)方法用于获取连接字符串,他读取“ConnectionStrings”节点下的名为name的值作为连接字符串。“ConnectionStrings”只是一个建议,不是.NET Core要求必须使用这个节点保存数据库连接字符串。
使用选项方式读取配置 使用选项方式读取配置是.NET Core中推荐的方式,因为他不及和依赖注入机制结合的更好,而且它可以实现配置修改后自动更新,用起来更方便。
使用选项方式读取,和DI结合更好,且更好利用“reloadonchange”机制。 读取配置的时候,DI要声明IOptions<T>、IOptionsMonitor<T>、IOptionsSnapshot<T>等类型。IOptions<T>不会读取到新的值;和IOptionsMonitor相比,IOptionsSnapshot会在同一个范围内(比如ASP.NET Core一个请求中)保持一致。建议用IOptionsSnapshot。
使用选项方式读取配置需要通过NuGet为项目安装
1 Microsoft.Extensions.Options
由于这种方式是对绑定方式的封装,因此我们任然需要同时安装包
1 Microsoft.Extensions.Configuration.Binder
在读取配置的地方,用IOptionsSnapshot<T>注入。不要在构造函数里直接读取IOptionsSnapshot.Value,而是到用到的地方在读取,否则无法更新变化。
1 2 3 4 5 6 7 8 9 10 11 12 { "Logging" : { "LogLevel" : { "Default" : "Warning" } } , "DB" : { "DbType" : "SQLServre" , "ConnectionString" : "Data Source=.;Initial Catalog=DemoDB; Integrated Security=Ture" } , "Smtp" : { "Server" : "youxianyu.cn" , "UserName" : "zeng" , "Password" : "123456" } , "AllowedHosts" : "*" }
读取“DB”和“Smtp”这两部分 建立对应配置项的两个模型类
1 2 3 4 5 6 7 8 9 10 11 public class DbSettings { public string DbType { get ; set ; } public string ConnectionString { get ; set ; } } public class SmtpSettings { public string Server { get ; set ; } public string Username { get ; set ; } public string Password { get ; set ; } }
由于使用选项方式读取配置的时候,需要和依赖注入一起使用,因此我们需要创建一个类用于获取注入的选项值。 声明接收选项注入的对象的类型不能直接使用DbSettings、SmtpSettings,而要使用IOptions<T>、IOptionsMonitor<T>、IOptionsSnapshot<T>等泛型接口类型,可以帮我们处理容器生命周期、配置刷新等。 IOptions<T>在配置改变后,我们不能读到新的值,必须重启程序才可以读到新的值; IOptionsMonitor<T>在配置改变后,我们能读到新的值;IOptionsSnapshot<T>也是在配置改变后,我们能读到新的值,和IOptionsMonitor<T>不同的是,在同一个范围内IOptionsMonitor<T>会保持一致性。
由于IOptions<T>不监听配置的改变,因此它的资源占用会比较少,适用与对服务启动后就不会改变的值进行读取。由于IOptionsMonitor<T>可能会导致用一个请求过程中,配置的改变使读取同一个选项的值不一致,从而导致程序出错,因此如果我们需要在程序运行中读取修改后的值,建议使用IOptionsSnapshot<T>。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 class Demo { private readonly IOptionsSnapshot<DbSettings> optDbSettings; private readonly IOptionsSnapshot<SmtpSettings> optSmtpSettings; public Demo (IOptionsSnapshot<DbSettings> optDbSettings, IOptionsSnapshot<SmtpSettings> optSmtpSettings ) { this .optDbSettings = optDbSettings; this .optSmtpSettings = optSmtpSettings; } public void Test () { var db=optDbSettings.Value; Console.WriteLine($"数据库:{db.DbType} ,{db.ConnectionString} " ); var smtp = optSmtpSettings.Value; Console.WriteLine($"SMTP:{smtp.Server} ,{smtp.Username} ,{smtp.Password} " ); } }
这里,通过构造方法注入IOptionsSnapshot、IOptionsSnapshot两个服务,我们可以通过IOptionsSnapshot<T>的Value属性获取DbSettings、SmtpSettings等具体配置模型对象的值。
编写注入服务到容器的代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 using Microsoft.Extensions.Configuration;using Microsoft.Extensions.DependencyInjection;using Microsoft.Extensions.Options;using Microsoft.Extensions.Configuration.Json;using 选项方式读取配置_ID;ConfigurationBuilder configBuilder= new ConfigurationBuilder(); configBuilder.AddJsonFile("config.json" , optional: false , reloadOnChange: true ); IConfigurationRoot config = configBuilder.Build(); ServiceCollection services = new ServiceCollection(); services.AddOptions().Configure<DbSettings>(e=>config.GetSection("DB" ).Bind(e)) .Configure<SmtpSettings>(e=> config.GetSection("SMTP" ).Bind(e)); services.AddSingleton<Demo>(); using (var sp = services.BuildServiceProvider()){ while (true ) { using (var scope = sp.CreateScope()) { var spScope = scope.ServiceProvider; var demo = spScope.GetRequiredService<Demo>(); demo.Test(); } Console.WriteLine("按任意键继续..." ); Console.ReadKey(); } }
在第2行代码中,把方法的reloadOnChange参数设定为true,以启动“修改后重新加载配置”的功能;在第5行代码中,通过AddOptions方法注册与选项相关的服务,然后使用第六行代码把DB节点的内容绑定到DbSettings类型的模型对象上。 由于IOptionsSnapshot<T>的生命周期为“范围”,因此Demo这个用与读取配置的类的生命周期不能是单例,我们在第8行代码中把Demo注册为瞬态服务。
其他配置提供者 命令行读取配置 配置框架还支持从命令行参数、环境变量等地方读取。 NuGet安装:
1 Microsoft.Extensions.Configuration.CommandLine
configBuilder.AddCommandLine(args) 参数支持多种格式,比如:server=127、–server=127.0.0.1、–server 127.0.0、(注意在键值之间加空格)、/server=127.0.0.1、/server 127.0.0.1(主要在键值之间加空格)。格式不能混用。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 using Microsoft.Extensions.Configuration;using Microsoft.Extensions.DependencyInjection;using Microsoft.Extensions.Options;using Microsoft.Extensions.Configuration.Json;using Microsoft.Extensions.Configuration.CommandLine;using 选项方式读取配置_ID;ServiceCollection services = new ServiceCollection(); services.AddSingleton<Demo>(); ConfigurationBuilder configBuilder= new ConfigurationBuilder(); configBuilder.AddCommandLine(args); IConfigurationRoot config = configBuilder.Build(); services.AddOptions().Configure<DbSettings>(e=>config.GetSection("DB" ).Bind(e)) .Configure<SmtpSettings>(e=> config.GetSection("SMTP" ).Bind(e)); services.AddOptions().Configure<nameSettings>(e =>config.Bind(e)); using (var sp = services.BuildServiceProvider()){ while (true ) { using (var scope = sp.CreateScope()) { var spScope = scope.ServiceProvider; var demo = spScope.GetRequiredService<Demo>(); demo.Test(); } Console.WriteLine("按任意键继续..." ); Console.ReadKey(); } }
在项目的属性的调试 中设置命令行参数,这样Visual Studio中调试、运行程序的时候,Visual Studio会自动把这里设定的参数以命令行参数的形式传递给程序。
从环境变量读取配置 .NET Core中从环境变量读取配置需要安装:
1 Microsoft.Extensions.Configuration.EnvironmentVariables
然后调用AddEnvironmentVariables方法进行注册即可。AddEnvironmentVariables方法存在无参数和有prefix参数两个重载版本,无参数版本会将所有环境变量都加载进来,因此使用prefix参数的AddEnvironmentVartables重载方法进行注册。 prefix指的是环境变量名字的前缀。
1 2 3 4 5 ConfigurationBuilder configBuilder= new ConfigurationBuilder(); configBuilder.AddEnvironmentVariables("TEST_" ); IConfigurationRoot configRoot=configBuilder.Build(); string name =configRoot["Name" ];Console.WriteLine(name);