P3-2 配置系统

配置系统


配置系统的基本使用

说明

  • 1、传统Web.config配置的缺点,之前DI讲到过。
  • 2、为了兼容,仍然可以使用Web.config和ConfigurationManager类,但不推荐。
  • 3、.NET 中的配置系统支持丰富的配置源,包括文件(json、xml、ini等)、注册表、环境变量、命令行、Azure Key Vault等,还可以配置自定义配置源。可以跟踪配置的改变,可以按照优先级覆盖。
  • 4、通过IConfigurationRoot读取配置绑定读取配置这两种方式都只适合特殊情况(极端情况),一般来说还有另外一个方法更加简洁的去使用
  • 5、(*)懂了即可

Json文件配置

  • 1、创建一个json文件,文件名随意,比如config.json,设置“如果较新则复制”。参考备注
  • 2、NuGet安装Microsoft.Extensions.Configuration和Microsoft.Extensions.Configuration.Json。
    • Microsoft.Extensions.Configuration:配置框架基础包
      • Install-Package Microsoft.Extensions.Configuration
    • Microsoft.Extensions.Configuration.Json:读取Json的包
      • Install-Package Microsoft.Extensions.Configuration.Json
  • 3、编写代码,先用简单的方式读取配置。

通过IConfigurationRoot读取配置(*)

1
2
3
4
5
6
7
8
9
10
11
//读取配置原始方法
ConfigurationBuilder configBuilder = new ConfigurationBuilder();
configBuilder.AddJsonFile(
"config.json", optional: false, reloadOnChange: false);
IConfigurationRoot config = configBuilder.Build();
string name = config["name"];
string proxyAddress = config.GetSection("proxy:address").Value;

//optional参数表示这个文件是否可选。初学者,建议optional设置为false,这样写错了的话能够即使发现
//reloadOnChange参数表示如果文件修改了,是否重新加载配置。

绑定读取配置(*)

  • 1、可以绑定一个类,自动完成配置的读取。
  • 2、NuGet安装:Microsoft.Extensions.Configuration.Binder
  • 3、Server server = configRoot.GetSection(“proxy”).Get()
1
2
3
Config config = configRoot.Get<Config>();
Console.WriteLine(config.Name);
Console.WriteLine(config.Proxy.Port);

使用

使用选项方式读取配置

用法

  • 1、推荐使用选项方式读取,和DI结合更好,且更好利用“reloadonchange”机制。
  • 2、NuGet安装:Microsoft.Extensions.Options、Microsoft.Extensions.Configuration.Binder,当然也需要Microsoft.Extensions.Configuration、Microsoft.Extensions.Configuration.Json。
  • 3、读取配置的时候,DI要声明IOptions<T>IOptionsMonitor<T>IOptionsSnapshot<T>等类型。
    • 三者的区别
    • IOptions<T>:在配置改变后,我们不能读到新的值,必须重启程序才可以读到新的值
    • IOptionsMonitor:在配置改变后,我们能读到新的值
    • IOptionsSnapshot:也是在配置改变后,我们能读到新的值,
      • IOptionsMonitor不同的是,IOptionsSnapshot会在同一个范围内会保持一致性(比如ASP.NET Core一个请求中)
  • 建议用IOptionsSnapshot

演示代码

  • 1、在读取配置的地方,用IOptionsSnapshot注入。不要在构造函数里直接读取IOptionsSnapshot.Value,而是到用到的地方再读取,否则就无法更新变化。
  • 2、如下配置
    1
    2
    3
    4
    services.AddOptions()
    .Configure<DbSettings>(e => config.GetSection("DB").Bind(e))
    .Configure<SmtpSettings>(e => config.GetSection("Smtp").Bind(e));
    services.AddTransient<Demo>();//不能用Singleton

从命令行读取配置

  • 1、配置框架还支持从命令行参数、环境变量等地方读取。
  • 2、NuGet安装Microsoft.Extensions.Configuration.CommandLine。
  • 3、configBuilder.AddCommandLine(args)
  • 4、参数支持多种格式,比如:server=127.0.0.1、–server=127.0.0.1、–server 127.0.0.1(注意在键值之间加空格)、/server=127.0.0.1、/server 127.0.0.1(注意在键值之间加空格)。格式不能混用。
  • 5、调试的时候,VS中简化命令行传参数的方法。
    • 命令行
      • 命令行
    • 2019
      • 2019
    • 2022
      • 2022
1
2
3
4
//DB:DbType=666 Smtp:Server=zane
ConfigurationBuilder configBuilder = new ConfigurationBuilder();
configBuilder.AddCommandLine(args);//从命名行读取配置
IConfigurationRoot config = configBuilder.Build();

扁平化配置

  • 1、对于环境变量、命令行等简单的键值对结构,如果想要进行复杂结构的配置,需要进行“扁平化处理”。对于配置的名字需要采用“层级配置”。例如:a:b:c。对于数字这样配置:a:b:c:0a:b:c:1a:b:c:2
  • 2、演示一下。
  • 3、这个知识点在自定义配置Provider中还会用到。

从环境变量读取配置

  • 1、NuGet安装:Microsoft.Extensions.Configuration.EnvironmentVariables。
  • 2、然后configurationBuilder. AddEnvironmentVariables()
    • AddEnvironmentVariables() 有无参数和有prefix参数的两个重载版本。
    • 无参数版本会把程序相关的所有环境变量都加载进来,由于有可能和系统中已有的环境变量冲突,因此建议用有prefix参数的AddEnvironmentVariables()。
    • 读取配置的时候,prefix参数会被忽略。
  • 3、VS中调试时,避免修改系统环境变量,直接在VS中设置环境变量的方法。
    • 环境变量
      • 环境变量
1
2
3
4
//TEST_Smtp:Server=cool   TEST_DB:DbType=888
ConfigurationBuilder configBuilder = new ConfigurationBuilder();
configBuilder.AddEnvironmentVariables("TEST_");//从环境变量读取配置 建议有前缀去区分 比如:TEST_
IConfigurationRoot config = configBuilder.Build();

其他配置源

1、还支持ini、xml等格式的配置源,如果想用查询文档即可。
2、还支持在运行时、调试时加载不同的json文件;
3、还内置或者第三方支持中心化配置服务器,比如使用Apollo、Nacos等开源服务器,或者使用Azure、阿里云等的配置服务。具体看文档即可。

案例:开发我们的配置提供程序

  • 什么是“自己造轮子”
    • 本来有现成的框架可以使用,但你非得自己去创造,还不一定有现成的好用
    • 对于一个程序员来讲,一定要有自己造轮子的这个能力
    • 价值
    • 对行业:就是说在行业里边,一定是有一些人不满足于现有的东西,去创造新的东西
      • 如果只会用行业内的框架,越用还越觉得越垃圾,但是还必须用~你怎么办呢
    • 对自己
      • 可以提高自己。当你可以造轮子了,你这时就是创造者了,而并非只是一个使用者

开发自定义配置提供者的步骤

  • 1、开发一个直接或者间接实现IConfigurationProvider接口的类XXXConfigurationProvider,一般继承自ConfigurationProvider。
    • 如果是从文件读取,可以继承自FileConfigurationProvider
    • 重写Load方法,把“扁平化数据”设置到Data属性即可。
  • 2、再开发一个实现了IConfigurationSource接口的类XXXConfigurationSource。
    • 如果是从文件读取,可以继承自FileConfigurationSource
    • 在Build方法中返回上面的ConfigurationProvider对象。
  • 3、然后使用即可,configurationBuilder.Add(new ConfigurationSource())即可。
  • 为了简化使用,一般提供一个IConfigurationBuilder的扩展方法。

整体流程:编写ConfigurationProvider类实际读取配置;
编写ConfigurationSource在Build中返回ConfigurationProvider对象;
把ConfigurationSource对象加入IConfigurationBuilder。

开发web.config提供者

  • 1、.NET Core中不建议使用.NET Framework里的web.config,不过仍然继续提供了ConfigurationManager了,不过没有官方支持通过新的Configuration框架读取的方式。
    • 我们来实现一个,能够读取web.config里的connectionStrings和appSettings的内容。没用过web.config也没关系。
  • 2、这个项目主要意义还是展示如何编写自定义配置提供者,实用意义不大。主要为下一个更实用的配置提供者做知识准备。

    代码写在了“Config1\自定义配置提供”这个项目里

项目需求(开发数据库配置提供者)

  • 1、网站用集群部署,如果用本地配置文件,每次修改都要挨个修改。有Apollo、Nacos等开源的配置中心以及云服务平台的配置服务,但是项目对于配置的要求没有非常复杂,因此决定在关系数据库中保存配置。
    • 如果项目用不到云服务平台的话,可以用关系数据库中保存配置达到中心化配置的需求
  • 2、已经开源 https://github.com/yangzhongke/Zack.AnyDBConfigProvider
  • 3、按照文档先使用一下,站在使用者角度体验一下。思考自己如何实现。项目亮点:value支持json格式。

解读源代码

  • 1、杨老师github上的源代码。
  • 2、重点:定时reload的实现(也可以考虑改成用触发器实时触发);ReaderWriterLockSlim 的使用;json解析为“扁平结构”。

步骤中的问题

  • 第一步
    • Id的自动增长
      • 1.设置主键。 2.设置自动增长
    • 创建表
    • 设置主键
    • 自动增长
    • 保存
    • 在表中写入配置数据
    • 写入数据
  • 第二步
    • 在对应的项目中安装第三方包
      • Install-Package Zack.AnyDBConfigProvider
      • Install-Package Microsoft.Data.SqlClient
  • 第三步
    • 在代码中写入配置(下面都是简单写的,具体可以看使用说明中)
      1
      2
      3
      string conn1 = "Server=127.0.0.1;Database=School;Trusted_Connection=True";
      configBuilder.AddDbConfiguration(() => new SqlConnection(conn1), reloadOnChange: true,
      reloadInterval: TimeSpan.FromSeconds(2));
  • 第四步
    • 运行
    • 连接成功

代码写在了“Config1\Config1”这个项目里


多配置源问题

为什么多配置源

  • 1、比如:某个网站需要自定义配置;程序员的同一台机器上,开发调试环境和测试环境用不同的配置。
  • 2、按照注册到ConfigurationBuilder的顺序,“后来者居上”
    • 后注册的优先级高,如果配置名字重复,用后注册的值。
    • 如果配置名字不重复,就用前注册的值。后者有则代替,无则保持
  • 3、实验:控制台的覆盖环境变量的,自定义Provider的覆盖控制台的。
  • 练习
    • 命令行
    • 环境变量

配置文件的重要性

  • 把配置文件不小心传到互联网的下场
    • 杯具故事

保命的UserSecrets(为了防止上述事件的发生)

  • 1、.NET 提供了user-secrets机制, user-secrets的配置不放到源代码中。
  • 2、Nuget安装:Microsoft.Extensions.Configuration.UserSecrets
  • 3、在VS项目上点右键【管理用户机密】,编辑这个配置文件。看看这个文件在哪里。会自动在csproj中的UserSecretsId就是文件夹的名字。
    • 安装包
    • 点击确定后就自动安装了Microsoft.Extensions.Configuration.UserSecrets这个包
  • 4、configBuilder.AddUserSecrets()
注意
  • 1、不能泄漏到源码中的配置放到user-secrets即可,不用都放。
    • 比如公司的服务器配置文件等
    • 取至机密
  • 2、一般把user-secrets优先级放到普通json文件之前。
    • 排序
  • 3、如果开发人员电脑重装系统等原因造成本地的配置文件删除了,就需要重新配置。
    • 因为机密文件储存在C盘,所以如果有,记得提前备份
    • 机密储存
  • 4、并不是生产中的加密,只适用于开发环境。

P3-2 配置系统
http://example.com/2024/09/12/Net Core2022教程/第3章:.NET Core核心基础组件/P3-2 配置系统/
Author
John Doe
Posted on
September 12, 2024
Licensed under