文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

Dotnet Core 技术之Dotnet 6.0 深度探索

2024-12-02 11:42

关注

本文转载自微信公众号「老王Plus」,作者老王Plus的老王。转载本文请联系老王Plus公众号。

Dotnet 6.0 大家都装了没?

我打算开个专题,系统地写一写 Dotnet 6.0 在各个方面的特性,以及全新的开发方式。也是因为最近讨论 6.0 比较多,看到很多人的畏难情绪,所以打算写写相关的内容。

了解了,就不怕了。

要写的内容很多,我会分几篇来写。

今天是第一篇:ConfigurationManager,配置管理器。

ConfigurationManager 是干什么用的?

引用微软官方的说法:ConfigurationManager 是用来支持 ASP.Net Core 的新的 WebApplication 模型。这个模型主要的作用是在一些特定的场景下(后面我们会说到),用来简化 ASP.NET Core 的启动代码。

当然,如果我们去看 MSDN 的文档,会发现 ConfigurationManager 本身实现还是挺复杂的。好在,大多数情况下,这是一个半隐藏的东西,你可能都意识不到你已经用到了它。

那它到底是干什么用的?

这得从 .Net 5.0 的 Configuration 说起。

.Net 5.0 里的 Configuration

Configuration 配置,从 3.1 到 5.0,增加了很多很多的配置类型,如果你去 MSDN 上看,有好几大篇。

这里面,我们接触最多的是两个:

在实际应用中,IConfigurationBuilder 通常被我们用做配置源列表的包装器,最常用的是通过 AddJsonFile(),将配置源添加到源列表中。看到 AddJsonFile(),你是不是想到了什么?

简单来说,IConfigurationBuilder 是这样的:

  1. public interface IConfigurationBuilder 
  2.     IDictionary Properties { get; } 
  3.     IList Sources { get; } 
  4.     IConfigurationBuilder Add(IConfigurationSource source); 
  5.     IConfigurationRoot Build(); 

而 IConfigurationRoot,里面放的是经过合并的配置值。这个合并需要注意一下,多个配置源逐个加入时,相同名称的项,后面的配置会覆盖前面的项。

在 .Net 5.0 以前,IConfigurationBuilder 和 IConfigurationRoot 接口分别由 ConfigurationBuilder 和 ConfigurationRoot 实现。使用时通常是这么写:

  1. var builder = new ConfigurationBuilder(); 
  2.  
  3. // 加入静态值 
  4. builder.AddInMemoryCollection(new Dictionary 
  5.     { "MyKey""MyValue" }, 
  6. }); 
  7.  
  8. // 加入文件 
  9. builder.AddJsonFile("appsettings.json"); 
  10.  
  11. IConfigurationRoot config = builder.Build(); 
  12.  
  13. string value = config["MyKey"]; // 取一个值 
  14. IConfigurationSection section = config.GetSection("SubSection"); // 取一个节 

这是在 Console 程序中。

在 ASP.NET Core 中,通常不需要这么显式的 new 和 Build(),但事实上也是调用的这个接口。

在默认的 ConfigurationBuilder 实现中,调用 Build() 将遍历所有的源,加载 Provider 程序,并将它们传递给一个新的ConfigurationRoot 实例:

  1. public IConfigurationRoot Build() 
  2.     var providers = new List(); 
  3.     foreach (IConfigurationSource source in Sources) 
  4.     { 
  5.         IConfigurationProvider provider = source.Build(this); 
  6.         providers.Add(provider); 
  7.     } 
  8.     return new ConfigurationRoot(providers); 

然后,ConfigurationRoot 依次遍历每个提供程序并加载配置值:

  1. public class ConfigurationRoot : IConfigurationRoot, IDisposable 
  2.     private readonly IList _providers; 
  3.     private readonly IList _changeTokenRegistrations; 
  4.  
  5.     public ConfigurationRoot(IList providers) 
  6.     { 
  7.         _providers = providers; 
  8.         _changeTokenRegistrations = new List(providers.Count); 
  9.  
  10.         foreach (IConfigurationProvider p in providers) 
  11.         { 
  12.             p.Load(); 
  13.             _changeTokenRegistrations.Add(ChangeToken.OnChange(() => p.GetReloadToken(), () => RaiseChanged())); 
  14.         } 
  15.     } 
  16.     // ...  

这种架构,会有个小问题。在团队开发的时候,在没有统一沟通的情况下,有可能会在多处调用 Build()。当然这也没什么问题。只不过,正常来说这个没有必要,毕竟这是在读文件,会很慢。

不过,在 .Net 5.0 之前,都是这么做。

可喜的是,在 .Net 6.0 里,微软也注意到这个问题,并引入了一个新的类型:ConfigurationManager。

.Net 6.0 里的 ConfigurationManager

ConfigurationManager 是一个 .Net 6.0 中新的配置类型。这个类型也同样实现了两个接口:IConfigurationBuilder 和 IConfigurationRoot。那么,通过这两个接口的实现,我们可以简化上一节讲到的 .Net 5.0 中的通用模式。

不过,还是有一点点区别。这里 IConfigurationBuilder 将源保存为 IList:

  1. public interface IConfigurationBuilder 
  2.     IList Sources { get; } 
  3.     // ... 

这样做有一个好处,就是对于源 IList,就有了 Add() 和 Remove() 方法,我们可以在不知道 ConfigurationManager 的情况下增加和删除配置提供程序。

  1. private class ConfigurationSources : IList 
  2.     private readonly List _sources = new(); 
  3.     private readonly ConfigurationManager _config; 
  4.  
  5.     public ConfigurationSources(ConfigurationManager config) 
  6.     { 
  7.         _config = config; 
  8.     } 
  9.  
  10.     public void Add(IConfigurationSource source) 
  11.     { 
  12.         _sources.Add(source); 
  13.         _config.AddSource(source); // 增加源 
  14.     } 
  15.  
  16.     public bool Remove(IConfigurationSource source) 
  17.     { 
  18.         var removed = _sources.Remove(source); // 删除源 
  19.         _config.ReloadSources(); // 重新加载源 
  20.         return removed; 
  21.     } 
  22.  
  23.     // ...  

这样做可以确保 ConfigurationManager 在改变源的 IList 时,能自动加载源的配置数据。

看一下 ConfigurationManager.AddSource 的定义:

  1. public class ConfigurationManager 
  2.     private void AddSource(IConfigurationSource source) 
  3.     { 
  4.         lock (_providerLock) 
  5.         { 
  6.             IConfigurationProvider provider = source.Build(this); 
  7.             _providers.Add(provider); 
  8.  
  9.             provider.Load(); 
  10.             _changeTokenRegistrations.Add(ChangeToken.OnChange(() => provider.GetReloadToken(), () => RaiseChanged())); 
  11.         } 
  12.  
  13.         RaiseChanged(); 
  14.     } 

这个方法会立即调用 IConfigurationSource 的 Build() 方法来创建 IConfigurationProvider,并加入到源列表中。

下面,这个方法就调用 IConfigurationProvider 的 Load() 方法,将数据加载到 Provider。

这个方法解决了一件事,就是当我们需要从不同的位置向 IConfigurationBuilder 加入各种源时,源只需要加载一次,而且只会加载一次。

上面的代码是增加源。当我们需要 Remove() 源,或者干脆清除掉全部的源 Clear() 时,就需要调用 ReloadSource():

  1. private void ReloadSources() 
  2.     lock (_providerLock) 
  3.     { 
  4.         DisposeRegistrationsAndProvidersUnsynchronized(); 
  5.  
  6.         _changeTokenRegistrations.Clear(); 
  7.         _providers.Clear(); 
  8.  
  9.         foreach (var source in _sources) 
  10.         { 
  11.             _providers.Add(source.Build(this)); 
  12.         } 
  13.  
  14.         foreach (var p in _providers) 
  15.         { 
  16.             p.Load(); 
  17.             _changeTokenRegistrations.Add(ChangeToken.OnChange(() => p.GetReloadToken(), () => RaiseChanged())); 
  18.         } 
  19.     } 
  20.  
  21.     RaiseChanged(); 

当然,看懂上面的代码,也就明白两件事:

如果需要对配置的源进行大量的操作,这样的代价会比较大。不过,这种情况会很不常见。

总结一下

.Net 6.0 引入了一个新的 ConfigurationManager,用来优化配置的构建。

ConfigurationManager 同样实现了 ConfigurationBuilder 和 ConfigurationRoot。这算是个兼容性的设置,主要是为了支持 WebHostBuilder 和 HostBuilder 中对配置的调用。同时,也兼容了早期代码中的调用方式。所以,代码升级时,相关配置调用的部分,如果不想改代码,是完全可以的。而如果想做点改动,就换成使用 ConfigurationManager,或者通过 WebApplicationBuilder 来加载(会自动调用 ConfigurationManager),应用程序会有更好的性能。

这算是一个小礼物,相信也是微软权衡以后的结果。

 

来源:老王Plus内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯