.net 温故知新:【8】.NET 中的配置从xml转向json
一、配置概述
在.net framework平台中我们常见的也是最熟悉的就是.config文件作为配置,控制台桌面程序是App.config,Web就是web.config,里面的配置格式为xml格式。

在xml里面有系统生成的配置项,也有我们自己添加的一些配置,最常用的就是appSettings节点,用来配置数据库连接和参数。
使用的话就引用包System.Configuration.ConfigurationManager 之后取里面的配置信息:System.Configuration.ConfigurationManager.AppSettings["ConnectionString"]
随着技术的发展这种配置方式显得冗余复杂,如果配置项太多层级关系参数表达凌乱,在.net core开始也将配置的格式默认成了json格式,包括现在很多的其它配置也是支持的,比如java中常用的yaml格式,为什么能支持这么多读取源和格式,其实质在于配置提供程序。
目前.NET 中的配置是使用一个或多个配置提供程序执行的。 配置提供程序使用各种配置源从键值对读取配置数据,这些配置程序稍后我们会看到,读取的配置源可以是如下这些:
- 设置文件,appsettings.json
- 环境变量
- Azure Key Vault
- Azure 应用配置
- 命令行参数
- 已安装或已创建的自定义提供程序
- 目录文件
- 内存中的 .NET 对象
- 第三方提供程序
二、配置初识
IConfiguration 接口是所有配置源的单个表示形式,给定一个或多个配置源,IConfiguration 类型提供配置数据的统一视图。

上图我们可能没有直观的感受,现在写一个例子来看看
(1). 新建控制台应用程序:
创建控制台使用的是.net 6.0 框架,vs 2022。
安装 Microsoft.Extensions.Configuration.Json NuGet 包,该包提供json配置文件读取。
Install-Package Microsoft.Extensions.Configuration.Json

(2). 添加appsettings.json 文件
{
"person": {
"name": "XSpringSun",
"age": 18
}
}
(3). 使用json提供程序读取json配置
new一个ConfigurationBuilder,添加json配置,AddJsonFile是在包中的IConfigurationBuilder扩展方法,其它配置提供程序也是用这种扩展方法实现。
static void Main(string[] args)
{
IConfiguration configuration = new ConfigurationBuilder()
.AddJsonFile("appsettings.json")
.Build();
Console.WriteLine(configuration["person:name"]);
Console.WriteLine(configuration["person:age"]);
Console.WriteLine("Hello, World!");
Console.ReadLine();
}

可以看到已经取到json配置文件中的值了,配置值可以包含分层数据。 分层对象使用配置键中的 : 分隔符表示。在下面的调试对象中我们可以看到实际configuration的Providers 提供程序数组有一个值,就是我们的JsonConfigurationProvider,并且JsonConfigurationProvider里面已经读取了json的数据存储在Data数组中。
对于如上几行代码干了什么呢:
- 将 ConfigurationBuilder 实例化(new ConfigurationBuilder)。
- 添加 "appsettings.json" 文件,由 JSON 配置提供程序识别(AddJsonFile("appsettings.json"))。
- 使用 configuration 实例获取所需的配置
三、选项模式
这样已经实现json进行配置读取,但是取值的方式似乎和以前没什么太大变法,所以.net提供了选项模式,选项模式就是使用类来提供对相关设置组的强类型访问。
我们创建一个Config类用来转换json:
namespace ConfigDemo
{
public class Config
{
public Person? person { get; set; }
}
public class Person {
public string? name { get; set; }
public int age { get; set; }
}
}
绑定配置
IConfiguration configuration = new ConfigurationBuilder()
.AddJsonFile("appsettings.json")
.Build();
Config options = new Config();
ConfigurationBinder.Bind(configuration, options);
Person person = configuration.GetSection("person").Get<Person>();
Console.WriteLine(options.person.name);
Console.WriteLine(options.person.age);
Console.WriteLine("-----------GetSection获取-------------");
Console.WriteLine(person.name);
Console.WriteLine(person.age);

用了两种方式获取配置,第一种使用ConfigurationBinder.Bind()将整个配置绑定到对象Config上,另外一种是使用IConfiguration的GetSection().Get<T>()并返回指定的类型。两种方式都可以使用,看实际需求和用途。
四、选项依赖注入
在控制台程序中我们引用DI注入包,然后演示下如何进行配置的注入。关于DI和IOC不清楚的看我上篇文章.net 温故知新:【7】IOC控制反转,DI依赖注入
- 新建一个测试类TestOptionDI
public class TestOptionDI
{
private readonly IOptionsSnapshot<Config> _options;
public TestOptionDI(IOptionsSnapshot<Config> options)
{
_options = options;
}
public void Test()
{
Console.WriteLine("DI测试输出:");
Console.WriteLine($"姓名:{_options.Value.person.name}");
Console.WriteLine($"年龄:{_options.Value.person.age}");
}
}
在测试类中我们使用IOptionsSnapshot<T>接口作为依赖注入,还有其它不同定义的接口用来配置注入,关于选项接口:。

不同接口可以配合读取配置的不同方式起作用,IOptionsSnapshot接口可以在配置文件改变后不同作用域进行刷新配置。接着我们修改main方法,引入DI,并将AddJsonFile方法的参数reloadOnChange设置为true,optional参数是否验证文件存在,建议开发时都设置为true,这样如果文件有问题会进行报错。
注入配置这句services.AddOptions().Configure<Config>(e=>configuration.Bind(e))是关键,通过容器调用AddOptions方法注册,然后Configure方法里面是一个委托方法,该委托的作用就是将配置的信息绑定到Config类型的参数e上。注册到容器的泛型选项接口,这样在TestOptionDI类构造函数注入就能注入IOptionsSnapshot了,这里有点绕。
static void Main(string[] args)
{
IConfiguration configuration = new ConfigurationBuilder()
.AddJsonFile("appsettings.json",optional:true,reloadOnChange:true)
.Build();
//IServiceCollection 服务
ServiceCollection services = new ServiceCollection();
//注入配置
services.AddOptions().Configure<Config>(e=>configuration.Bind(e));
//注入TestOptionDI
services.AddScoped<TestOptionDI>();
using (var provider = services.BuildServiceProvider())
{
//获取服务
var testOption = provider.GetRequiredService<TestOptionDI>();
testOption.Test();
}
Console.ReadLine();
}

为了测试IOptionsSnapshot接口在不同作用域会刷新配置,我们修改下main方法,用一个while循环在ReadLine时修改json文件值,不同的Scope里进行打印。
using (var provider = services.BuildServiceProvider())
{
while (true)
{
using (var scope = provider.CreateScope())
{
//获取服务
var testOption = scope.ServiceProvider.GetRequiredService<TestOptionDI>();
testOption.Test();
}
Console.ReadLine();
}
}

这个功能在web中使用很方便,因为框架的一次请求就是一个作用域,所以我们修改了配置,下次请求就能生效了,而不用重启服务。
五、其它配置
如最开始所说,不仅能配置json文件,由于各种提供程序,还可以配置其它的,但是根据配置的顺序会进行覆盖。我们只添加一个环境变量配置演示下:
首先添加提供程序包:Install-Package Microsoft.Extensions.Configuration.EnvironmentVariables。
然后添加环境变量配置代码AddEnvironmentVariables():
IConfiguration configuration = new ConfigurationBuilder()
.AddJsonFile("appsettings.json",optional:true,reloadOnChange:true)
.AddEnvironmentVariables()
.Build();
在VS中配置临时环境变量

这里有个扁平化配置,就是表示层级用冒号person:age

六、托管模式
对于web项目我们没有进行这么多操作它是怎么配置的呢,其实框架已经自动帮我们做了,其它非web项目也可以使用这种托管模式,在Microsoft.Extensions.Hosting 包中,只需要使用简单的代码就能配置好。
IHost host = Host.CreateDefaultBuilder(args).Build();
await host.RunAsync();
其加载配置的优先级:

通过分析我们对整个配置如何运行的机制有了一个大体的了解,如果想详细了解托管模式的还是建议看官方文档:.NET配置
.net 温故知新:【8】.NET 中的配置从xml转向json的更多相关文章
- Servlet中的配置 web.xml
url-pattern配置 可以为同一个Servlet配置多个url-pattern: <servlet> <servlet-name>DoGetPostDemo</se ...
- SSM框架中,配置数据库连接的问题
MySQL数据库版本是8.0.11. 要用驱动:com.mysql.cj.jdbc.Driver 最主要的是数据库的连接url. 搞了半天才把问题搞明白: 数据库url后面要加上参数: jdbc:my ...
- 3、带你一步一步学习ASP.NET Core中的配置之Configuration
如果你是刚接触ASP.NET Core的学习的话,你会注意到:在ASP.NET Core项目中,看不到.NET Fraemwork时代中的web.config文件和app.config文件了.那么你肯 ...
- Linux在fstab中因配置错误导致服务器主机无法重启的问题应该如何解决
fstab中配置错误导致系统无法启动的恢复方案 1制造错误的案例发生,在/etc/fstab中配置如下内容 结尾的倒数第一个为1表示进行磁盘检查,为0表示不进行磁盘检查,倒数第二个为0表示不备份,为1 ...
- Eclipse中安装配置Tomcat
Eclipse(4.4.x及以上)中安装配置Tomcat 以下配置说明全部针对免安装版本 基于tomcat的安装目录和运行目录是可以不同的,本文都会进行说明 首先简单介绍一下tomcat的目录结构,一 ...
- Hadoop在eclipse中的配置
在安装完linux下的hadoop框架,实现完所现有的wordCount程序,能够完美输出结果之后,我们开始来搭建在window下的eclipse的环境,进行相关程序的编写. 在网上有很多未编译版本, ...
- MyBatis入门学习教程-优化MyBatis配置文件中的配置
一.连接数据库的配置单独放在一个properties文件中 之前,我们是直接将数据库的连接配置信息写在了MyBatis的conf.xml文件中,如下: 1 <?xml version=" ...
- Tesseract API在VS 2013中的配置以及调用
[Tesseract]Tesseract API在VS 2013中的配置以及调用 时间:2016-05-31 20:35:19 阅读:127 评论:0 收藏:0 ...
- Mybatis中SqlMapper配置的扩展与应用(2)
三.子表删除兼容问题 这个问题,使用SQL配置函数不太好处理,而且就算使用SQL配置函数,也不够直观,有点自动生成SQL的意味,太Hibernate了(不过要是可以兼收Hibernate和Mybati ...
随机推荐
- 线性代数 | Jordan 标准型的笔记
内容概述: 把方阵 A 的特征多项式 \(c(λ)=|λE-A|\) 展开成 \(c(λ)=\sum_ia_i\lambda^i\) 的形式,然后使用神乎其技的证明,得到 \(c(A)=O\),特征多 ...
- 从0到1写一款自动为Markdown标题添加序号的Jetbrains插件
1. markdown-index 最近做了一个Jetbrains的插件,叫markdown-index,它的作用是为Markdown文档的标题自动添加序号,效果如下: 目前已经可以在Jetbrain ...
- HCNP Routing&Switching之DHCP安全
前文我们了解了MAC地址防漂移技术,回顾请参考https://www.cnblogs.com/qiuhom-1874/p/16632239.html:今天我们来了解下DHCP安全相关话题: 回顾DHC ...
- HiveSql调优系列之Hive严格模式,如何合理使用Hive严格模式
目录 综述 1.严格模式 1.1 参数设置 1.2 查看参数 1.3 严格模式限制内容及对应参数设置 2.实际操作 2.1 分区表查询时必须指定分区 2.2 order by必须指定limit 2.3 ...
- openstack中Nova组件简解
一.Nova组件概述 计算节点通过Nova Computer进行虚拟机创建,通过libvirt调用kvm创建虚拟机,nova之间通信通过rabbitMQ队列进行通信. Nova位于Openstack架 ...
- CentOS7_SSH_安装总结
在使用ssh 连接自己的centos 虚拟机时,发现连接不上,于是有了这个安装过程 (以下是在root用户下执行的,没权限的话就sudo) 1.首先判断是否有这个服务 systemctl list-u ...
- python的环境,你再也不用愁-conda
Conda Guide Conda简介 conda是一个包,依赖和环境管理工具,适用于多种语言,如: Python, R, Scala, Java, Javascript, C/ C++, FORTR ...
- Python数据科学手册-机器学习: 主成分分析
PCA principal component analysis 主成分分析是一个快速灵活的数据降维无监督方法, 可视化一个包含200个数据点的二维数据集 x 和 y有线性关系,无监督学习希望探索x值 ...
- 微信小程序-全局配置、组件、页面跳转、用户信息等
全局配置 三个页面 app.json pages字段 "pages":[ "pages/index/index", # 首页 "pages/home/ ...
- day03-3私聊功能
多用户即时通讯系统03 4.编码实现02 4.4功能实现-私聊功能实现 4.4.1思路分析 客户端 - 发送者: 用户在控制台输入信息,客户端接收内容 将消息构建成Messgae对象,通过对应的soc ...