Configuration配置

发布时间 2023-12-02 01:34:49作者: louzi

Configuration相关项目:

  • Microsoft.Extensions.Configuration:配置接口实现
  • Microsoft.Extensions.Configuration.Abstractions:配置相关接口
  • Microsoft.Extensions.Configuration.Binder:配置绑定
  • Microsoft.Extensions.Configuration.CommandLine:命令行配置源
  • Microsoft.Extensions.Configuration.EnvironmentVariables:环境变量配置源
  • Microsoft.Extensions.Configuration.FileExtensions:文件配置源,虚基类
  • Microsoft.Extensions.Configuration.Json:Json文件配置源
  • Microsoft.Extensions.Configuration.Xml:Xml文件配置源
  • Microsoft.Extensions.Configuration.Ini:ini文件配置源
  • Microsoft.Extensions.Configuration.UserSecrets:用户机密配置源

Configuration相关接口:

  • IConfiguration:基础接口
  • IConfigurationRoot:根节点,包含所有配置提供程序
  • IConfigurationSection:子节点
  • IConfigurationBuilder:创建器,创建IConfigurationRoot
  • IConfigurationProvider:配置提供程序,提供配置源中的数据
  • IConfigurationSource:配置源,创建配置提供程序

实现

IConfigurationBuilder中管理了所有的配置源,通过Add(IConfigurationSource source)方法添加配置源。

IConfigurationSource创建IConfigurationProvider,IConfigurationProvider调用Load()方法加载配置文件中的数据。

调用IConfigurationBuilder.Build()方法创建IConfigurationRoot。

public IConfigurationRoot Build()
{
    var providers = new List<IConfigurationProvider>();
    foreach (IConfigurationSource source in Sources)
    {
        IConfigurationProvider provider = source.Build(this);
        providers.Add(provider);
    }
    return new ConfigurationRoot(providers);
}

IConfigurationRoot中管理所有的IConfigurationProvider,在其构造函数中调用IConfigurationProvider.Load()方法加载配置,并监听文件修改。通过倒序遍历所有IConfigurationProvider获取指定配置项的值。

public ConfigurationRoot(IList<IConfigurationProvider> providers)
{
    if (providers == null)
        throw new ArgumentNullException(nameof(providers));

    _providers = providers;
    _changeTokenRegistrations = new List<IDisposable>(providers.Count);
    foreach (IConfigurationProvider p in providers)
    {
        p.Load();
        _changeTokenRegistrations.Add(ChangeToken.OnChange(() => p.GetReloadToken(), () => RaiseChanged()));
    }
}

internal static string? GetConfiguration(IList<IConfigurationProvider> providers, string key)
{
    for (int i = providers.Count - 1; i >= 0; i--)
    {
        IConfigurationProvider provider = providers[i];

        if (provider.TryGet(key, out string? value))
            return value;
    }

    return null;
}

自定义配置源

自定义配置源需实现IConfigurationSource和IConfigurationProvider,然后调用IConfigurationBuilder.Add(IConfigurationSource source)方法添加配置源。

使用

首先,Configuration模块不依赖容器就可以使用。

创建一个ConfigurationBuilder实例,并添加配置源。reloadOnChange参数指定当文件修改时重新加载配置源。以Json文件为例,需添加Microsoft.Extensions.Configuration.Json:

IConfigurationBuilder configurationBuilder = new ConfigurationBuilder()
    .SetBasePath(Directory.GetCurrentDirectory())
    .AddJsonFile("config.json", optional: true, reloadOnChange: true);

调用Build方法创建IConfigurationRoot:

IConfiguration configuration = configurationBuilder.Build();

通过不同方式获取配置项的值:

// 通过key取值
Console.WriteLine($"Test:Name:{configuration["Test:Name"]}");

// 通过GetValue扩展方法取值
Console.WriteLine($"Test:Age:{configuration.GetValue<int>("Test:Age")}");

// 通过IConfigurationSection.Value取值
Console.WriteLine($"Test:Sex:{configuration.GetSection("Test:Sex").Value}");

使用Bind方法绑定实体,需添加Microsoft.Extensions.Configuration.Binder:

// 绑定实体
TestOptions testOptions = new TestOptions();
configuration.GetSection("Test").Bind(testOptions);
Console.WriteLine($"Test.Name = {testOptions.Name}");
Console.WriteLine($"Test.Age = {testOptions.Age}");
Console.WriteLine($"Test.Sex = {testOptions.Sex}");

class TestOptions
{
    public string Name { get; set; }
    public string Sex { get; set; }
    public int Age { get; set; }
}