AspNetCore Configuration

前言

该总结Configuration了。。。

1.基础知识

配置的本质是键值对,微软对于配置提供了大量的配置源提供程序,包括xml,json,ini,环境变量,命令行参数,内存等等。还提供了一个扩展包用于配置绑定和类型转换。

  • 依赖项

    Microsoft.Extensions.Configuration.Abstractions:抽象包,用于编写扩展时使用

    Microsoft.Extensions.Configuration:基础包提供了内存配置的方案

    Microsoft.Extensions.Configuration.Json:json支持

    Microsoft.Extensions.Configuration.EnvironmentVariables:环境变量支持

    Microsoft.Extensions.Configuration.CommandLine:命令行参数

    Microsoft.Extensions.Configuration.Binder:用于配置绑定到实体或者基本类型

  • 核心接口

    IConfiguration:配置的核心接口,用于读取配置

    IConfigurationRoot:表示根配置,继承IConfiguration接口

    IConfigurationSection:表示子配置节点,继承IConfiguration接口

    IConfigurationBuilder:提供了大量的扩展,用于构建IConfiguration实列。

    ConfigurationManager:实现了IConfigurationRoot、IConfigurationBuilder接口。因此ConfigurationManager既可以用于构建配置,也可以读取配置。

2.注册配置

安装配置包

Microsoft.Extensions.Configuration.Abstractions
Microsoft.Extensions.Configuration
Microsoft.Extensions.Configuration.Json
Microsoft.Extensions.Configuration.EnvironmentVariables
Microsoft.Extensions.Configuration.CommandLine

代码:

var configurationBuilder = new ConfigurationManager();
// 内存配置源
configurationBuilder.AddInMemoryCollection(new Dictionary<string, string>() {
    { "1","11111"},
    { "2","22222"}
});
// json配置源
configurationBuilder.SetBasePath(Directory.GetCurrentDirectory()).AddJsonFile("config.json");
// 命令行配置源
configurationBuilder.AddCommandLine(args);
// 环境变量配置源
configurationBuilder.AddEnvironmentVariables("Path");
Console.WriteLine("Hello, World!");
Console.ReadKey();

2.1Json

添加json文件

image-20231111233331969

修改文件属性,可以在程序编译后生成文件,方便读取

image-20231111233424213

添加测试数据

image-20231111233524646

{
  "MvcOptions": {
    "Host": "127.0.0.1",
    "Port": 8080,
    "Urls": [
      "http://127.0.0.1:80",
      "http://127.0.0.1:81",
      "http://127.0.0.1:82"
    ]
  },
  "ConnectionStrings": {
    "default": "127.0.0.1"
  }
}

查看json配置

image-20231111234134336

2.2命令行

项目右键属性

image-20231111234422732

configurationBuilder.AddCommandLine(args);

image-20231111234730664

2.3环境变量

configurationBuilder.AddEnvironmentVariables("Path");

image-20231111234920667

3.构建配置

//由于ConfigurationManager实现了IConfiguration接口,并且没有build方法
//因此构建很简单,或者你根本不需要构建,但是建议把配置和读取分开
IConfiguration configuration = configurationBuilder;

4.读取配置

注释都写清楚了。

using Microsoft.Extensions.Configuration;

var configurationBuilder = new ConfigurationManager();
// 内存配置源
configurationBuilder.AddInMemoryCollection(new Dictionary<string, string>() {
    { "1","11111"},
    { "2","22222"}
});
// json配置源
configurationBuilder.SetBasePath(Directory.GetCurrentDirectory()).AddJsonFile("config.json");
// 命令行配置源
configurationBuilder.AddCommandLine(args);
// 环境变量配置源
configurationBuilder.AddEnvironmentVariables("Path");
// 由于ConfigurationManager实现了IConfiguration接口,并且没有build方法
// 因此构建很简单,或者你根本不需要构建,但是建议把配置和读取分开
IConfiguration configuration = configurationBuilder;
// 读取配置
string tmp1 = configuration["1"]!;
// 获取子配置
IConfigurationSection options = configuration.GetSection("MvcOptions");
// 获取数据
IEnumerable<IConfigurationSection> sections = configuration.GetSection("MvcOptions:Urls").GetChildren();
foreach (IConfigurationSection item in sections)
{
    var url = item.Value;
}
// 获取数据库连接字符串
var connstr = configuration.GetConnectionString("default");

5.配置转换

扩展接口,需要安装Binder支持

Microsoft.Extensions.Configuration.Binder

配置类型转换

image-20231112003306895

配置转换实体,俩种方式

image-20231112003341933

using Microsoft.Extensions.Configuration;
var configurationBuilder = new ConfigurationManager();
// 内存配置源
configurationBuilder.AddInMemoryCollection();
// json配置源
configurationBuilder.SetBasePath(Directory.GetCurrentDirectory()).AddJsonFile("config.json");
// 由于ConfigurationManager实现了IConfiguration接口,并且没有build方法
// 因此构建很简单,或者你根本不需要构建,但是建议把配置和读取分开
IConfiguration configuration = configurationBuilder;
// 将配置绑定到基本类型上,底层调用Convert.ToXXX();
var host = configuration.GetValue<string>("MvcOptions:Host");
var Port = configuration.GetValue<int>("MvcOptions:Port");
// 将配置绑定到实列上,底层调用GetValue
var options1 = new MvcOptions();
configuration.Bind("MvcOptions", options1);
// 将配置绑定到实列上,并返回这个实列,底层调用Bind
var options2 = configuration.GetSection("MvcOptions").Get<MvcOptions>();

Console.WriteLine("Hello, World!");
Console.ReadKey();

public class MvcOptions
{
    public string Host { get; set; }
    public string Port { get; set; }
}

6.ChangeToken

  • 依赖项

    Microsoft.Extensions.Primitives:提供配置更改的核心接口和实现

  • 核心接口

    IChangeToken:用于注册回调

    ChangeToken:用于绑定生产者和消费者,注册一个回调,如果更改发生就获取使用生成者生产一个新的IChangeToken,并执行消费者,并在次注册回调

    CancellationChangeToken:IChangeToken的实现一种实现,

    CancellationTokenSource:用于产生取消令牌,执行取消令牌,

    CancellationToken:取消令牌,可以注册取消之后的回调。负责在CancellationChangeToken和CancellationTokenSource直接传递消息

using Microsoft.Extensions.Primitives;


var provider = new FileConfigurationProvider();
// 绑定
provider.Watch();
new TaskCompletionSource().Task.Wait();


/// <summary>
/// 文件配置程序超类
/// </summary>
public class FileConfigurationProvider
{
    private CancellationTokenSource? tokenSource;

    public void Load()
    {
        Console.WriteLine($"[{DateTime.Now}]文件已加载...");
    }

    public void Watch()
    {
        Load();
        // 将changeToken生产者和changeToken消费者进行绑定(订阅)
        ChangeToken.OnChange(GetReloadToken, Load);
        // 触发Chang事件,通知更新
        var t = new Thread(() =>
        {
            while (true)
            {
                Thread.Sleep(3000);
                var t = tokenSource;
                // 取消之前一定要设置成null,要不会递归
                tokenSource = null;
                // 执行回调,发布取消事件
                t!.Cancel();
            }
        });
        t.Start();
    }

    /// <summary>
    /// 更新令牌,通过该令牌可以注册回调,用于执行更新通知
    /// </summary>
    /// <returns></returns>
    public IChangeToken GetReloadToken()
    {
        lock (this)
        {
            if (tokenSource == null)
            {
                tokenSource = new CancellationTokenSource();
            }
            return new CancellationChangeToken(tokenSource.Token);
        }
    }

}
  • 执行原理

    CancellationChangeToken:接收到了CancellationToken,并把回调注册到CancellationToken上。

    CancellationToken:构造器接收CancellationTokenSource即注册到CancellationToken的回调,本质上是注册到了CancellationTokenSource上。CancellationToken充当CancellationChangeToken和CancellationTokenSource的中间人。

    CancellationTokenSource:执行Cancel,执行注册的回调,即执行了CancellationChangeToken中注册的回调。

  • 执行流程

    1. 首先执行Watch()
    2. 然后执行ChangeToken.OnChange
    3. ChangeToken.OnChange执行生成者委托GetReloadToken,获取一个IChangeToken,然后注册了一个嵌套回调使得消费者和生产者永久绑定
    4. 3秒之后CancellationTokenSource通知取消,并执行CancellationTokenSource上的回调。

image-20231112004742653

7.自定义配置源

太省了,记录一下,后面慢慢理解

using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Primitives;
using System.Collections.Concurrent;

Console.WriteLine("Hello, World!");

// 配置提供器选项:用于提供配置选项
public class HttpConfigurationSource : IConfigurationSource
{
    public bool ReloadOnChange { get; set; }
    public HttpConfigurationSource() { }
    public IConfigurationProvider Build(IConfigurationBuilder builder)
    {
        return new HttpConfigurationProvider(this);
    }
}

// 配置提供器:配置源逻辑
public class HttpConfigurationProvider : IConfigurationProvider
{
    private ConcurrentDictionary<string, string> values = new ConcurrentDictionary<string, string>();
    private HttpConfigurationSource options;
    private CancellationTokenSource? tokenSource;
    public HttpConfigurationProvider(HttpConfigurationSource options)
    {
        this.options = options;
        if (this.options.ReloadOnChange)
        {
            Watch();
        }
    }
    private void Watch()
    {
        // 注册时间
        ChangeToken.OnChange(GetReloadToken, Load);
        // 模拟更改
        var t = new Thread(() =>
        {
            while (true)
            {
                var token = tokenSource;
                tokenSource = null;
                // 每3s之后发生更改
                Thread.Sleep(3000);
                // 触发事件,触发之前一定要将tokenSource设置成null
                token!.Cancel();
            }
        });
        t.Start();
    }
    public IEnumerable<string> GetChildKeys(IEnumerable<string> earlierKeys, string? parentPath)
    {
        return values.Keys;
    }

    public IChangeToken GetReloadToken()
    {
        lock (this)
        {
            if (tokenSource == null)
            {
                tokenSource = new CancellationTokenSource();
            }
            return new CancellationChangeToken(tokenSource!.Token);
        }
    }

    public void Load()
    {
        //假设我们从第三方地址获取
        //var client = new HttpClient();
        //var response = client.GetAsync(source.Url).GetAwaiter().GetResult();
        //var json = response.Content.ReadAsStringAsync().GetAwaiter().GetResult();
        values.TryAdd("t1", "1111111");
        values.TryAdd("t2", "2222222");
        Console.WriteLine("ison文件已加载...");
    }

    public void Set(string key, string? value)
    {
        values.TryAdd(key, value);
    }

    public bool TryGet(string key, out string? value)
    {
        var flag = values.TryGetValue(key, out string? data);
        value = data ?? string.Empty;
        return flag;
    }
}

// 扩展IConfigurationBuilder
public static class HttpConfigurationExtensions
{
    public static IConfigurationBuilder AddJsonHttp(this IConfigurationBuilder builder, Action<HttpConfigurationSource> configure)
    {
        if (builder == null)
        {
            throw new ArgumentNullException(nameof(builder));
        }
        /*
         * Add会执行如下逻辑
         * 实列化HttpConfigurationSource
         * 执行委托配置HttpConfigurationSource实列
         * 调用httpConfigurationSource实列的Build返回HttpConfigurationProvider实列
         * HttpConfigurationProvider实列又依赖了HttpConfigurationSource实列
         * 最后执行Load加载配置到ConfigurationManager实列上
         */
        return builder.Add(configure);
    }
}
posted @   peng_boke  阅读(44)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
点击右上角即可分享
微信分享提示