02020304 .NET Core核心基础组件04-配置系统、Json文件配置、选项方式读取、扁平化&环境变量&其它配置源

02020304 .NET Core核心基础组件04-配置系统、Json文件配置、选项方式读取、扁平化&环境变量&其它配置源

1. 配置系统入门(视频2-32)

  • 传统Web.config配置的缺点,之前DI讲过。
  • 为了兼容,仍然可以使用web.config和ConfigurationManage类,但不推荐。
  • .NET中的配置系统支持丰富的配置源,包括文件(json、xml、ini等)、注册表、环境变量、命令行、Azure key value等,此外还可以配置自定义配置源。
    • 可以跟踪配置的改变,可以按照优先级覆盖。

2. Json文件配置

2.1 Json文件配置步骤
  • step1 → 创建Json文件,文件名随意。比如config.json,设置如果教新则复制。参考备注。
    • 注意要将Json文件的属性设定为较新则复制,这样文件才会拷贝到和.exe文件同级的目录底下。这样程序运行的时候,是读取的的与.exe文件同级的Json文件,不再加载源代码里面的Json文件。
  • step2 → NuGet安装两个包
    • Microsoft.Extensions.Configuration → 配置框架的包。配置框架可以读Json文件、xml文件、ini文件、数据库、环境变量来读。
    • Microsoft.Extensions.Configuration.Json → 读Json文件的包
  • step3 → 编写代码,先用简单的方式读取配置。
  • 拓展知识
    • 15-20年前,用xml配置。一层套一层,贼恶心
    • 现在流行Json格式来做配置。
    • 自行网上查阅Json格式的资料。
2.2 Json格式
{"a":"3","b":"5",c:{"d":"7","ids":[3,5]},} // 可以多级嵌套
2.3 新建Json文件
  • 项目名称 → 右键 → 添加 → 新建项 → 文本文件 → 名称 → config.json
// 新建:config.json
{
  "name": "yzk",
  "age": "18",
  "qinway": {"address":"wuxi","port":"80"}
}

说明:需要把config.json文件的属性修改为如果较新则复制。
2.4 引入两个包
install-package Microsoft.Extensions.Configuration // 老师演示包的版本:5.0.0。截止2025.09.10,该包的版本为:9.0.9
install-package Microsoft.Extensions.Configuration.Json // 老师演示包的版本:5.0.0。截止2025.09.10,该包的版本为:9.0.9
2.5 读取配置原始方法
图片链接丢失
  • ConfigurationBuilder类 → 用来对Configuration进行配置的构建器。
  • AddJsonFile方法 → 加载配置文件
    • config.json → 文件名
    • optional:false → optional是可选参数。
      • false表示文件不存在就不报错。文件存在我就读,文件不存在不报错也不读。
      • 对于初学者建议设定为true,避免因为Json文件名、代码写的有问题导致写错了发现不了。
    • reloadOnChange → 文件修改之后是否立即加载新的配置。
      • true表示不需要程序重启,配置文件修改之后,立即读到新的配置文件。建议为true。
      • false表示如果配置文件更改了,需要重启程序才能加载新的配置。
  • config对象 → 通过该对象读取配置。IConfigurationRoot是配置项读取器。
  • Json里面所有值默认为字符串类型。
  • config.GetSection("proxy:address").Value → 用于读取多级结构。
2.6 读取Json文件示例
using Microsoft.Extensions.Configuration;
using System;

namespace JsonConfig
{
    class Program
    {
        static void Main(string[] args)
        {
            ConfigurationBuilder configBuider = new ConfigurationBuilder();
            configBuider.AddJsonFile("config.json", optional : true, reloadOnChange : true);
            IConfigurationRoot configRoot = configBuider.Build();
            string name = configRoot["name"];
            Console.WriteLine($"name = {name}");
            string addr = configRoot.GetSection("qinway:address").Value;
            Console.WriteLine($"addr = {addr}");
            Console.ReadLine();
        }
    }
}

控制台输出:
name = yzk
addr = wuxi
2.7 关于config.json文件说明
图片链接丢失
  • 此时如果我们手动的修改拷贝到.exe目录下的config.json文件,然后直接双击.exe文件,程序输出的是修改后的内容。
2.8 绑定读取配置
图片链接丢失
install-package Microsoft.Extensions.Configuration.Binder // 老师演示包的版本:5.0.0。截止2025.09.10,该包的版本为:9.0.9
—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—
using Microsoft.Extensions.Configuration;
using System;

namespace JsonConfig
{
    class Program
    {
        static void Main(string[] args)
        {
            ConfigurationBuilder configBuider = new ConfigurationBuilder();
            configBuider.AddJsonFile("config.json", optional : true, reloadOnChange : true);
            IConfigurationRoot configRoot = configBuider.Build();
            Qinway qinway = configRoot.GetSection("Qinway").Get<Qinway>(); // @1
            Console.WriteLine($"{qinway.Address}, {qinway.Port}");
            Console.ReadLine();
        }
    }

    class Qinway // 类名要和配置名一致,貌似不区分大小写规范。
    {
        public string Address { get; set; }
        public int Port { get; set; }

    }
}

控制台输出
wuxi, 80


说明:
1. 在@1处GetSection("Qinway"),这里的Qinway和config.json里面的qinway对应,不区分大小写。
2. 在@1处Get<Qinway>()是个泛型方法,Qinway是类名。
2.8 将Json文件根节点读出来
using Microsoft.Extensions.Configuration;
using System;

namespace JsonConfig
{
    class Program
    {
        static void Main(string[] args)
        {
            ConfigurationBuilder configBuider = new ConfigurationBuilder();
            configBuider.AddJsonFile("config.json", optional : true, reloadOnChange : true);
            IConfigurationRoot configRoot = configBuider.Build();
            Config cg = configRoot.Get<Config>();
            Console.WriteLine($"{cg.Name}, {cg.Qinway.Port}");
            Console.ReadLine();
        }
    }

    class Qinway
    {
        public string Address { get; set; }
        public int Port { get; set; }

    }

    class Config // 根节点类
    {
        public string Name { get; set; }
        public int Age { get; set; }
        public Qinway Qinway { get; set; }
    }
}

控制台输出:
yzk, 80

3. 选项方式读取(视频2-33)

3.1 选项方式读取用法
图片链接丢失
  • IOptions → 读取配置,不会读到新的值。即使配置文件改了,通过这种方式读的仍然是旧的值。
    • 只有在程序重启之后,读的才是新的值。
  • IOptionsMonitor → 读取配置,会读到新的值。
  • IOptionsSnapshot → 读取配置,会读到新的值。截图有错误,更正为IOptionsSnapshot 会在同一个范围之内。
3.2 演示代码
图片链接丢失
3.3 项目目录
JsonConfig → 解决方案名称
├── JsonConfig  → .NET Core 5.0控制台项目。
|   ├── config.json → Json文件
|   ├── TestController.cs → DI注入用的类,用来读取整个Json文件
|   ├── TestPart.cs → DI注入用的类,用来读取Json文件某个节点
└── └──Program.cs → 包含Main方法,程序的入口。

需要安装如下5个包:
microsoft.extensions.configuration
microsoft.extensions.configuration.binder
microsoft.extensions.configuration.json
microsoft.extensions.options
microsoft.extensions.dependencyinjection
3.4 源码
// config.json
{
  "name": "yzk",
  "age": "18",
  "qinway": {"address":"wuxi","port":"80"}
}
—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—
// TestController.cs
using Microsoft.Extensions.Options;
using System;

namespace JsonConfig
{
    class TestController
    {
        public readonly IOptionsSnapshot<Config> optConfig;
        public TestController(IOptionsSnapshot<Config> optConfig)
        {
            this.optConfig = optConfig;
        }

        public void Test() // 测试读取
        {
            Config config = optConfig.Value;
            Console.WriteLine(config.Age);
            Console.WriteLine("**********************************");
            Console.WriteLine(config.Age);
        }
    }
}
—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—
// TestPart.cs
using Microsoft.Extensions.Options;
using System;

namespace JsonConfig
{
    class TestPart
    {
        public readonly IOptionsSnapshot<Qinway> optQinway;
        public TestPart(IOptionsSnapshot<Qinway> optQinway)
        {
            this.optQinway = optQinway;
        }

        public void TestRead() // 测试读取
        {
            Console.WriteLine(optQinway.Value.Address);
            Console.WriteLine(optQinway.Value.Port);
        }
    }
}
—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—·—
// Program.cs
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using System;

namespace JsonConfig
{
    class Program
    {
        static void Main(string[] args)
        {
            ServiceCollection services = new ServiceCollection();
            services.AddScoped<TestController>(); // 往DI容器注册
            services.AddScoped<TestPart>(); // 往DI容器注册

            ConfigurationBuilder configBuider = new ConfigurationBuilder();
            configBuider.AddJsonFile("config.json", optional : true, reloadOnChange : true);
            IConfigurationRoot configRoot = configBuider.Build();

            // @1 把Config对象绑定到根节点
            services.AddOptions().Configure<Config>(e => configRoot.Bind(e));

            // @2 把Qinway对象绑定到qinway节点
            services.AddOptions().Configure<Qinway>(e => configRoot.GetSection("qinway").Bind(e));

            /*
             * 在@1处和@2处的代码可以写成如下形式
             * services.AddOptions()
             *      .Configure<Config>(e => configRoot.Bind(e));
             *      .Configure<Qinway>(e => configRoot.GetSection("qinway").Bind(e));
             * 即:可以连续点来绑定节点。
             */

            using (var sp = services.BuildServiceProvider())
            {
                var c1 = sp.GetRequiredService<TestController>();
                c1.Test();

                var c2 = sp.GetRequiredService<TestPart>();
                c2.TestRead();
            }

            Console.ReadLine();
        }
    }

    class Qinway // 单个节点类
    {
        public string Address { get; set; }
        public int Port { get; set; }

    }

    class Config // 根节点类
    {
        public string Name { get; set; }
        public int Age { get; set; }
        public Qinway Qinway { get; set; }
    }
}

控制台输出:
18
**********************************
18
wuxi
80
3.5 演示修改本地配置文件后输出结果
// 修改Program.cs文件
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using System;

namespace JsonConfig
{
    class Program
    {
        static void Main(string[] args)
        {
            ServiceCollection services = new ServiceCollection();
            services.AddScoped<TestController>(); // 往DI容器注册
            services.AddScoped<TestPart>(); // 往DI容器注册

            ConfigurationBuilder configBuider = new ConfigurationBuilder();
            configBuider.AddJsonFile("config.json", optional : true, reloadOnChange : true);
            IConfigurationRoot configRoot = configBuider.Build();

            // @1 把Config对象绑定到根节点
            services.AddOptions().Configure<Config>(e => configRoot.Bind(e));

            // @2 把Qinway对象绑定到qinway节点
            services.AddOptions().Configure<Qinway>(e => configRoot.GetSection("qinway").Bind(e));

            /*
             * 在@1处和@2处的代码可以写成如下形式
             * services.AddOptions()
             *      .Configure<Config>(e => configRoot.Bind(e));
             *      .Configure<Qinway>(e => configRoot.GetSection("qinway").Bind(e));
             * 即:可以连续点来绑定节点。
             */

            using (var sp = services.BuildServiceProvider())
            {
                while(true)
                {
                    using (var scope = sp.CreateScope()) // 使用IOptionsSnapshot配置时,在下一个Scope生效。
                    {
                        var c1 = scope.ServiceProvider.GetRequiredService<TestController>();
                        c1.Test();

                        var c2 = scope.ServiceProvider.GetRequiredService<TestPart>();
                        c2.TestRead();
                    }
                    Console.WriteLine("点击任意键继续");
                    Console.ReadLine();
                }
            }
        }
    }

    class Qinway // 单个节点类
    {
        public string Address { get; set; }
        public int Port { get; set; }

    }

    class Config // 根节点类
    {
        public string Name { get; set; }
        public int Age { get; set; }
        public Qinway Qinway { get; set; }
    }
}

step1 → 控制台输出:
18
**********************************
18
wuxi
80
点击任意键继续

step2 → 修改本地配置文件为
{
  "name": "yzk",
  "age": "88",
  "qinway": {"address":"wuhan","port":"60"}
}

step3 → 控制台输出:
18
**********************************
18
wuxi
80
点击任意键继续

注意:这里示例失败了,不纠结,继续推进课程。

4. 其它配置提供者(视频2-34)

4.1 命令行方式配置
图片链接丢失
4.2 项目目录
JsonConfig → 解决方案名称
├── JsonConfig  → .NET Core 5.0控制台项目。
|   ├── config.json → Json文件
|   ├── TestController.cs → DI注入用的类,用来读取整个Json文件
|   ├── TestPart.cs → DI注入用的类,用来读取Json文件某个节点
└── └──Program.cs → 包含Main方法,程序的入口。

需要安装如下6个包:
microsoft.extensions.configuration
microsoft.extensions.configuration.binder
microsoft.extensions.configuration.json
microsoft.extensions.options
microsoft.extensions.dependencyinjection
microsoft.extensions.configuration.commandline
4.3 启动命令行位置
图片链接丢失
4.4 源代码
  • 在3.4基础上修改Program.cs文件
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using System;

namespace JsonConfig
{
    class Program
    {
        static void Main(string[] args) // 这里args是命令行参数,不懂。
        {
            ServiceCollection services = new ServiceCollection();
            services.AddScoped<TestController>();
            services.AddScoped<TestPart>();

            ConfigurationBuilder configBuider = new ConfigurationBuilder();
            // configBuider.AddJsonFile("config.json", optional : true, reloadOnChange : true);
            configBuider.AddCommandLine(args); // 将args传入。
            IConfigurationRoot configRoot = configBuider.Build();

            services.AddOptions()
                .Configure<Config>(e => configRoot.Bind(e))
                .Configure<Qinway>(e => configRoot.GetSection("qinway").Bind(e));

            using (var sp = services.BuildServiceProvider())
            {
                while(true)
                {
                    using (var scope = sp.CreateScope())
                    {
                        var c1 = scope.ServiceProvider.GetRequiredService<TestController>();
                        c1.Test();
                        Console.WriteLine("改一下age");
                        Console.ReadKey();
                        c1.Test();

                        var c2 = scope.ServiceProvider.GetRequiredService<TestPart>();
                        c2.TestRead();
                    }
                    Console.WriteLine("点击任意键继续");
                    Console.ReadLine();
                }
            }
        }
    }

    class Qinway
    {
        public string Address { get; set; }
        public int Port { get; set; }

    }

    class Config
    {
        public string Name { get; set; }
        public int Age { get; set; }
        public Qinway Qinway { get; set; }
    }
}

控制台输出:
0
**********************************
0
改一下age
4.5 命令行启动程序并且输入配置
图片链接丢失
  • 说明:命令行只有在程序运行时才能配置,不存在改配置的问题,这样调试比较麻烦。
4.6 通过VS进行配置
  • 项目名称 → 属性 → 调试 → 应用程序参数。
图片链接丢失
  • 输出结果对比
4.4中控制台输出:
0
**********************************
0
改一下age

在VS 2019中配置了应用程序参数之后,控制台输出:
18
**********************************
18
改一下age

5. 扁平化配置

图片链接丢失
  • 对于命令行来讲,都是名称=值这样的形式,无法嵌套结构。此时通过扁平化来配置。

6. 环境变量配置

图片链接丢失

7. 其它配置源

图片链接丢失

结尾

书籍:ASP.NET Core技术内幕与项目实战

视频:https://www.bilibili.com/video/BV1pK41137He

著:杨中科

ISBN:978-7-115-58657-5

版次:第1版

发行:人民邮电出版社

※敬请购买正版书籍,侵删请联系85863947@qq.com※

※本文章为看书或查阅资料而总结的笔记,仅供参考,如有错误请留言指正,谢谢!※

posted @ 2025-09-11 22:17  qinway  阅读(0)  评论(0)    收藏  举报