.NET 6 中的 ConfigurationManager

.NET 6 中的 ConfigurationManager

Intro

.NET 6 为了 Minimal API 引入了一些新东西,其中就包含了一个全新的配置对象 ConfigurationManager

这并不是 .NET Framework 里的静态类 ConfigurationManager,而是 .NET Core 里的配置 Microsoft.Extensions.Configuration 中的一个新类型,新的 ConfigurationManager 对象是之前的 ConfigurationBuilderConfigurationRoot 的结合

Implement

API Proposal:

namespace Microsoft.Extensions.Configuration
{
+    public sealed class ConfigurationManager : IConfigurationRoot, IConfigurationBuilder, IDisposable
+    {
+        public ConfigurationManager();
+        public string? this[string key] { get; set; }
+        public IConfigurationSection GetSection(string key);
+        public void Dispose();
+    }

Implement:

public sealed class ConfigurationManager : IConfigurationBuilder, IConfigurationRoot, IDisposable
{
    private readonly ConfigurationSources _sources;
    private readonly ConfigurationBuilderProperties _properties;
    private readonly object _providerLock = new();
    private readonly List<IConfigurationProvider> _providers = new();
    private readonly List<IDisposable> _changeTokenRegistrations = new();
    private ConfigurationReloadToken _changeToken = new();

    /// <summary>
    /// Creates an empty mutable configuration object that is both an <see cref="IConfigurationBuilder"/> and an <see cref="IConfigurationRoot"/>.
    /// </summary>
    public ConfigurationManager()
    {
        _sources = new ConfigurationSources(this);
        _properties = new ConfigurationBuilderProperties(this);
        
        // Make sure there's some default storage since there are no default providers.
        this.AddInMemoryCollection();
        AddSource(_sources[0]);
    }
    // ...
}

ConfigurationManager在添加 ConfigurationSource 的时候也会注册 IConfigurationProvider,这样在添加 Source 之后就能够拿到 Configuration 中的配置了,在实现上,微软封装了一个私有的 ConfigurationSource 的类型,这里我们看一下注册配置源的代码

private class ConfigurationSources : IList<IConfigurationSource>
{
    private readonly List<IConfigurationSource> _sources = new();
    private readonly ConfigurationManager _config;

    public ConfigurationSources(ConfigurationManager config)
    {
        _config = config;
    }

    public IConfigurationSource this[int index]
    {
        get => _sources[index];
        set
        {
            _sources[index] = value;
            _config.ReloadSources();
        }
    }

    public void Add(IConfigurationSource source)
    {
        _sources.Add(source);
        _config.AddSource(source);
    }
    // ...
}

ConfigurationManager 中的 AddSource 方法实现如下:

IConfigurationBuilder IConfigurationBuilder.Add(IConfigurationSource source)
{
    _sources.Add(source ?? throw new ArgumentNullException(nameof(source)));
    return this;
}

private void RaiseChanged()
{
    var previousToken = Interlocked.Exchange(ref _changeToken, new ConfigurationReloadToken());
    previousToken.OnReload();
}

// Don't rebuild and reload all providers in the common case when a source is simply added to the IList.
private void AddSource(IConfigurationSource source)
{
    lock (_providerLock)
    {
        var provider = source.Build(this);
        _providers.Add(provider);

        provider.Load();
        _changeTokenRegistrations.Add(ChangeToken.OnChange(() => provider.GetReloadToken(), () => RaiseChanged()));
    }

    RaiseChanged();
}

可以看到每次新加一个配置源的时候,都会去构建对应的一个 IConfigurationProvider 而且会去加载配置数据并注册配置更新事件,所以我们注册完配置之后才能够获取到配置,更多实现细节参考 Github 上的源码:https://github.com/dotnet/runtime/blob/v6.0.0-rc.1.21451.13/src/libraries/Microsoft.Extensions.Configuration/src/ConfigurationManager.cs

Sample

来看下面使用时的 Sample 吧,非常的简单

const string testKey = "test";

var configuration = new ConfigurationManager();
Console.WriteLine(configuration[testKey]);

configuration.AddInMemoryCollection(new Dictionary<string, string>()
{
    { testKey, "test" }
});
Console.WriteLine(configuration[testKey]);
Console.ReadLine();

输出结果如下:

24bdcf17846dc8db7b2a4e0b1562c647.png

第一次输出的时候还没有注册配置输出的是空,第一次输出的时候已经注册了配置输出的是我们配置的值

代码示例在可以从 Github 获取 https://github.com/WeihanLi/SamplesInPractice/blob/master/net6sample/ConfigurationManagerSample/Program.cs

More

目前来说,ConfigurationManager 对象主要是为了 .NET 6 的 Minimal API 的需要,.NET 6 的 Minimal API 里用了这个,可以参考:https://github.com/dotnet/aspnetcore/blob/v6.0.0-rc.1.21452.15/src/DefaultBuilder/src/WebApplicationBuilder.cs ,但就像上面的示例一样,我们也是可以直接使用的,而且原来的 IConfigurationBuilder 依然是可以用的,无需担心升级到 .NET 6 会 break 的问题。

对于需要用到配置的测试程序直接用 ConfigurationManager 会更为简单一些,不需要先声明一个 ConfigurationBuilder 的对象注册好配置之后再构建一个 IConfiguration 对象,直接用一个对象就可以了,至少从我们写代码的角度会简单很多,但是性能会稍差一些,注册的配置源越多越明显,因为 ConfigurationManager 每次注册配置源的时候都会去构建和注册 IConfigurationProvider  而 IConfigurationBuilder 则是在最后 Build 的时候才构建一次,不过通常我们的配置也只是启动时只用配置一次,个人认为是可以接受的

References

  • https://github.com/dotnet/runtime/blob/v6.0.0-rc.1.21451.13/src/libraries/Microsoft.Extensions.Configuration/src/ConfigurationManager.cs

  • https://github.com/dotnet/runtime/blob/v6.0.0-rc.1.21451.13/src/libraries/Microsoft.Extensions.Configuration/src/ConfigurationRoot.cs

  • https://github.com/dotnet/runtime/blob/v6.0.0-rc.1.21451.13/src/libraries/Microsoft.Extensions.Configuration/src/ConfigurationBuilder.cs

  • https://github.com/dotnet/runtime/pull/55338

  • https://github.com/dotnet/runtime/issues/51770

  • https://github.com/dotnet/aspnetcore/blob/v6.0.0-rc.1.21452.15/src/DefaultBuilder/src/BootstrapHostBuilder.cs

  • https://github.com/dotnet/aspnetcore/blob/v6.0.0-rc.1.21452.15/src/DefaultBuilder/src/WebApplicationBuilder.cs

  • https://github.com/WeihanLi/SamplesInPractice/blob/master/net6sample/ConfigurationManagerSample/Program.cs

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值