Dotnet 6.0 深度探索(一)

Dotnet 6.0 已来。

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 - 这个接口主要用来增加配置源,并在构建器上调用 Build() 来读取每个配置源,并形成最终的配置

  • IConfigurationRoot - 这就是上面 Build() 完成后形成的配置,我们会从这里面读配置值

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

简单来说,IConfigurationBuilder 是这样的:

public interface IConfigurationBuilder
{IDictionary<string, object> Properties { get; }IList<IConfigurationSource> Sources { get; }IConfigurationBuilder Add(IConfigurationSource source);IConfigurationRoot Build();
}

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

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

var builder = new ConfigurationBuilder();// 加入静态值
builder.AddInMemoryCollection(new Dictionary<string, string>
{{ "MyKey", "MyValue" },
});// 加入文件
builder.AddJsonFile("appsettings.json");IConfigurationRoot config = builder.Build();string value = config["MyKey"]; // 取一个值
IConfigurationSection section = config.GetSection("SubSection"); // 取一个节

这是在 Console 程序中。

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

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

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);
}

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

public class ConfigurationRoot : IConfigurationRoot, IDisposable
{private readonly IList<IConfigurationProvider> _providers;private readonly IList<IDisposable> _changeTokenRegistrations;public ConfigurationRoot(IList<IConfigurationProvider> providers){_providers = providers;_changeTokenRegistrations = new List<IDisposable>(providers.Count);foreach (IConfigurationProvider p in providers){p.Load();_changeTokenRegistrations.Add(ChangeToken.OnChange(() => p.GetReloadToken(), () => RaiseChanged()));}}// ... 
}

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

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

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

.Net 6.0 里的 ConfigurationManager

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

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

public interface IConfigurationBuilder
{IList<IConfigurationSource> Sources { get; }// ...
}

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

private class ConfigurationSources : IList<IConfigurationSource>
{private readonly List<IConfigurationSource> _sources = new();private readonly ConfigurationManager _config;public ConfigurationSources(ConfigurationManager config){_config = config;}public void Add(IConfigurationSource source){_sources.Add(source);_config.AddSource(source); // 增加源}public bool Remove(IConfigurationSource source){var removed = _sources.Remove(source); // 删除源_config.ReloadSources(); // 重新加载源return removed;}// ... 
}

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

看一下 ConfigurationManager.AddSource 的定义:

public class ConfigurationManager
{private void AddSource(IConfigurationSource source){lock (_providerLock){IConfigurationProvider provider = source.Build(this);_providers.Add(provider);provider.Load();_changeTokenRegistrations.Add(ChangeToken.OnChange(() => provider.GetReloadToken(), () => RaiseChanged()));}RaiseChanged();}
}

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

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

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

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

private void ReloadSources()
{lock (_providerLock){DisposeRegistrationsAndProvidersUnsynchronized();_changeTokenRegistrations.Clear();_providers.Clear();foreach (var source in _sources){_providers.Add(source.Build(this));}foreach (var p in _providers){p.Load();_changeTokenRegistrations.Add(ChangeToken.OnChange(() => p.GetReloadToken(), () => RaiseChanged()));}}RaiseChanged();
}

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

  1. 增加源是代码最小的,加到列表中就行了 ;

  2. 删除或更改源代码会有点大,需要重新遍历加载所有源。

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

总结一下

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

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

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

又:写着写着,发出这个题目有点大了,要写的很多,可最近年底了,又有点忙,得容我慢慢写:P

喜欢就来个三连,让更多人因你而受益

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/293415.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

TCP协议中的三次握手和四次挥手(图解)

建立TCP需要三次握手才能建立&#xff0c;而断开连接则需要四次握手。整个过程如下图所示&#xff1a; 先来看看如何建立连接的。 首先Client端发送连接请求报文&#xff0c;Server段接受连接后回复ACK报文&#xff0c;并为这次连接分配资源。Client端接收到ACK报文后也向Serv…

java 矩阵题目_java练习本(原每日一练)(20190517)

名人名言昨日翻译“You will face many defeats in life, but never let yourself be defeated.”——Maya Angelou“你将在生活中面临许多失败&#xff0c;但决不让自己被打败。”——玛雅安吉罗今日名言“May you live all the days of your life.”——Jonathan Swift2019.0…

Sharepoint在itemUpdating中获取修改后的用户或用户组栏的值

获取用户或用户组栏的值&#xff0c;在网上有不少的文章已经写得非常好了&#xff08;http://www.cnblogs.com/McJeremy/archive/2009/08/03/1537876.html&#xff09;。但是我现在遇到一个问题就是&#xff1a;我在EventHandler的itemUpdating中需要获取到更改后的用户或用户组…

(转)直接拿来用!最火的iOS开源项目(一)

2019独角兽企业重金招聘Python工程师标准>>> 1. AFNetworking 在众多iOS开源项目中&#xff0c;AFNetworking可以称得上是最受开发者欢迎的库项目。AFNetworking是一个轻量级的iOS、Mac OS X网络通信类库&#xff0c;现在是GitHub上第三大Objective-C库。它建立在N…

nginx php 配置

/*************************************************************************************** nginx php 配置* 说明&#xff1a;* 配置一下nginx和php的开发环境&#xff0c;这个主要是为了将来运行的TI的Matrix GUI。* *…

.NET+Sqlite如何支持加密

点击上方蓝字关注我们.NETSqlite如何支持加密SqliteSQLite 来源于公共领域 SQLite Is Public Domain、确保代码不会受到任何专有或许可内容的污染&#xff0c;没有任何来自互联网上的未知来源复制。即全是原创的。虽然是免费的&#xff0c;无需许可证&#xff0c;可用于任何目的…

linux之scp命令

svn 删除所有的 .svn文件 find . -name .svn -type d -exec rm -fr {} \; linux之cp/scp命令&#xff0b;scp命令详解 名称&#xff1a;cp 使用权限&#xff1a;所有使用者 使用方式&#xff1a; cp [options] source dest cp [options] source... directory 说明&#xff1a…

裸奔、抽烟、凡尔赛,原来数学家玩得这么野……

全世界只有3.14 % 的人关注了爆炸吧知识六个数学家一部数学史假如宇宙真的由神明设计那他一定是个数学家数学就是他描绘自然的语言数学的重要性已经不用多说但是很多人仍觉得数学是高冷的女神其实数学神奇却并不神秘高贵却并不高冷因为有一群智者早就用他们的智慧和精力将那些晦…

SqlServer和MySQL中存储过程out返回值处理C#代码

1.SqlServer中out处理 C#代码 #region"SqlServer中存储过程处理out返回值"//public void getdata()//{// string str " server192.168.xxxx ;user idxxx;passwordxxxxx#;databasexxxxx_db;min pool size4;max pool size4;packet size3072";// SqlCo…

C#摄像头实现拍照功能的简单代码示例

C#摄像头实现拍照功能的简单代码示例2009-11-20 来自&#xff1a;网上整理字体大小&#xff1a;【大中小】摘要&#xff1a;这里将介绍一个C#摄像头实现拍照功能的简单代码示例&#xff0c;代码虽然不短&#xff0c;但是基本上实现了相对应的功能&#xff0c;希望对大家有所帮…

数据分析在零售业八大应用点总结

1、销售指标分析&#xff1a; 主要分析各项销售指标&#xff0c;例如毛利、毛利率、坪效、交叉比、销进比、盈利能力、周转率、同比、环比等等&#xff1b;而分析维又可从管理架构、类别品牌、日期、时段等角度观察&#xff0c;这些分析维又采用多级钻取&#xff0c;从而获得相…

foreach循环符合就不往下走了_柴油发电机组冷却液循环故障解决方法

点击上方蓝字了解更多精彩柴油发电机组冷却液循环故障是发电机组的常见故障之一&#xff01;下面给大家介绍一下针对循环故障做出的排查解决。1、柴油发电机组水泵故障。首先我们要先检查水泵作用是否良好&#xff0c;要是发现水泵传动齿轴磨损过限时&#xff0c;说明水泵已失去…

java web移植 遇到Project facet Java version 1.7 is not supported

2019独角兽企业重金招聘Python工程师标准>>> 在移植eclipse项目时&#xff0c;如果遇到 “Project facet Java version 1.7 is not supported.” 项目中的jdk1.7不支持。说明项目是其他版本jdk编译的&#xff0c;在eclipse里运行时会报版本不支持。 解决办法: 法1&a…

c#winform自定义窗体(含源码)

第一步&#xff1a;首先引用DLL再窗体中继承DevComponents.DotNetBar.OfficeFormpublic partial class MainForm : DevComponents.DotNetBar.OfficeForm初始化程序中添加 this.EnableGlass false;public MainForm(){this.EnableGlass false;InitializeComponent();}第二步&a…

linux之tmp文件夹

最近开始学习LINUX&#xff0c;关于/tmp文件夹&#xff0c; 查了些资料&#xff0c;/tmp文件夹是存放linux临时文件的地方&#xff0c;在Linux系统中/tmp文件夹里面的文件会被清空&#xff0c;至于多长时间被清空&#xff0c;如何清空的&#xff0c;可能就不清除了。 在CentOS5…

如何巧妙拒绝老同学借钱?哈哈哈哈哈......

1 别说&#xff0c;还挺像...cr&#xff1a;豆瓣银河系漫游1999▼2 奇奇怪怪的赚钱方式又增加了▼3 教你如何做到边吃边睡...▼4 方法二还挺有道理...▼5 总是在不该清醒的时候清醒▼6 多令人怀念&#xff01;▼7 对不起&#xff0c;我太菜了▼8 哈哈哈哈哈▼8 数学能有…

协同过滤

在现今的推荐技术和算法中&#xff0c;最被大家广泛认可和采用的就是基于协同过滤的推荐方法。本文将带你深入了解协同过滤的秘密。 1 什么是协同过滤 协同过滤是利用集体智慧的一个典型方法。要理解什么是协同过滤 (Collaborative Filtering, 简称 CF)&#xff0c;首先想一个简…

移动平台对 meta 标签的定义

下面介绍一些有关标记的例子及解释。 一、meta 标签分两大部分&#xff1a;HTTP 标题信息&#xff08;http-equiv&#xff09;和页面描述信息&#xff08;name&#xff09;。 1、http-equiv 属性的 Content-Type 值&#xff08;显示字符集的设定&#xff09; 说明&#xff1a;设…

微信改成右滑删除_手机文件数据恢复,怎样恢复已过期的微信附件呢?

手机文件数据恢复&#xff0c;怎样恢复已过期的微信附件呢&#xff1f;我们在恢复手机删除的文件之前&#xff0c;很多人都想知道&#xff0c;为什么自己的文件删除了可以被恢复&#xff0c;既然能被恢复&#xff0c;是我彻底删除不了手机的文件吗&#xff1f;文件真的消失了吗…