.NET 6 中的 ConfigurationManager
Intro
.NET 6 为了 Minimal API 引入了一些新东西,其中就包含了一个全新的配置对象 ConfigurationManager
这并不是 .NET Framework 里的静态类 ConfigurationManager
,而是 .NET Core 里的配置 Microsoft.Extensions.Configuration
中的一个新类型,新的 ConfigurationManager
对象是之前的 ConfigurationBuilder
和 ConfigurationRoot
的结合
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();
输出结果如下:
第一次输出的时候还没有注册配置输出的是空,第一次输出的时候已经注册了配置输出的是我们配置的值
代码示例在可以从 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