当前位置: 首页 > 科技观察

Dotnet核心技术Dotnet6.0深入探索

时间:2023-03-13 12:35:15 科技观察

本文转载自微信公众号“老王加”,老王加作者老王。转载本文请联系老王Plus公众号。大家都安装了Dotnet6.0了吗?打算开个专题系统的写一下Dotnet6.0各方面的特点和新的开发方式。也是因为最近关于6.0的讨论比较多,看到很多人怕困难的心理,所以打算写相关的内容。一旦你明白了,你就不会害怕了。要写的东西很多,所以我会分成几篇来写。今天是第一篇:ConfigurationManager,配置管理器。ConfigurationManager有什么用?引用微软官方的说法:ConfigurationManager是一种新的WebApplication模型,用于支持ASP.NetCore。该模型的主要作用是在某些特定场景下简化ASP.NETCore的启动代码(后面会讲到)。当然,如果我们看一下MSDN的文档,就会发现ConfigurationManager本身的实现是相当复杂的。幸运的是,在大多数情况下,这是一个半隐藏的东西,你可能没有意识到你已经使用过它。那么它有什么用呢?这得从.Net5.0的配置说起。.Net5.0中的ConfigurationConfiguration配置,从3.1到5.0,增加了很多很多的配置类型。如果你去MSDN,有几篇大文章。其中,我们接触最多的有两个:IConfigurationBuilder——这个接口主要用来增加配置源,并在builder上调用Build()读取每一个配置源,形成最终的配置IConfigurationRoot——就是上面的Build()配置完成后,我们从中读取配置值。在实际应用中,IConfigurationBuilder通常被用作配置源列表的包装器。最常用的方法是通过AddJsonFile()中将配置源添加到源列表中。看到AddJsonFile(),是不是想到了什么?简单的说,IConfigurationBuilder是这样的:publicinterfaceIConfigurationBuilder{IDictionaryProperties{get;}IListSources{get;}IConfigurationBuilderAdd(IConfigurationSourcesource);IConfigurationRootBuild();}和IConfigurationRoot,里面包含合并后的配置值。这种合并需要注意。多个配置源逐一添加时,对于同名项,后面的配置会覆盖前面的配置。在.Net5.0之前,IConfigurationBuilder和IConfigurationRoot接口分别由ConfigurationBuilder和ConfigurationRoot实现。使用时通常这样写:varbuilder=newConfigurationBuilder();//addstaticvaluebuilder.AddInMemoryCollection(newDictionary{{"MyKey","MyValue"},});//addfilebuilder。AddJsonFile("appsettings.json");IConfigurationRootconfig=builder.Build();stringvalue=config["MyKey"];//取一个值IConfigurationSectionsection=config.GetSection("SubSection");//取一个section这是在控制台程序中间。在ASP.NETCore中,通常不需要这样显式的new和Build(),但实际上调用了这个接口。在默认的ConfigurationBuilder实现中,调用Build()将遍历所有源,加载Provider程序,并将它们传递给一个新的ConfigurationRoot实例:Build(this);providers.Add(provider);}returnnewConfigurationRoot(providers);}然后,ConfigurationRoot依次遍历每个provider并加载配置值:;publicConfigurationRoot(IListproviders){_providers=providers;_changeTokenRegistrations=newList(providers.Count);foreach(IConfigurationProviderpinproviders){p.Load();_changeTokenRegistrations.oken(.)=>p.GetReloadToken(),()=>RaiseChanged()));}}//...}这种结构会有一个小问题。团队开发时,如果没有统一沟通,可能会在多个地方调用Build()。这当然没有错。不过一般情况下是没有必要的,毕竟这是读文件,会很慢。然而,在.Net5.0之前,已经这样做了。幸运的是,在.Net6.0中,微软也注意到了这个问题,引入了一个新的类型:ConfigurationManager。.Net6.0中的ConfigurationManagerConfigurationManager是.Net6.0中的一种新的配置类型。该类型还实现了两个接口:IConfigurationBuilder和IConfigurationRoot。那么,通过这两个接口的实现,我们就可以简化上一节中提到的.Net5.0中的通用模式。但是,仍然存在细微差别。这里IConfigurationBuilder将源保存为IList:可以在不了解ConfigurationManager的情况下添加和删除配置提供程序。privateclassConfigurationSources:IList{privatereadonlyList_sources=new();privatereadonlyConfigurationManager_config;publicConfigurationSources(ConfigurationManagerconfig){_config=config;}publicvoidAdd(IConfigurationSourcesource){_sources.Add(source/ource);_source.config)添加源}publicboolRemove(IConfigurationSourcesource){varremoved=_sources.Remove(source);//删除source_config.ReloadSources();//重新加载sourcereturnremoved;}//...}这样做可以确保ConfigurationManager正在改变source的配置数据设置IList时可以自动加载源代码。看一下ConfigurationManager.AddSource的定义:.OnChange()=>provider.GetReloadToken(),()=>RaiseChanged()));}RaiseChanged();}}这个方法会立即调用IConfigurationSource的Build()方法创建IConfigurationProvider并添加到源中列表。接下来,该方法调用IConfigurationProvider的Load()方法将数据加载到Provider中。这个方法解决了一个问题,就是当我们需要从不同的位置向IConfigurationBuilder添加各种源时,源只需要加载一次,它只会加载一次。上面的代码是增加源码。当我们需要Remove()源,或者简单地清除所有源Clear()时,我们需要调用ReloadSource():;foreach(varsourcein_sources){_providers.Add(source.Build(this));}foreach(varpin_providers){p.Load();_changeTokenRegistrations.Add(ChangeToken.OnChange(()=>p.GetReloadToken(),()=>RaiseChanged()));}}RaiseChanged();}当然,如果你看懂了上面的代码,你就会明白两件事:添加源是最小的代码,添加到列表中即可;删除或更改源代码会有点大,需要重新遍历加载所有源。如果需要对配置的source进行大量的操作,这个开销会比较高。但是,这种情况将非常罕见。总结。Net6.0引入了一个新的ConfigurationManager,用于优化配置的构建。ConfigurationManager还实现了ConfigurationBuilder和ConfigurationRoot。这是一个兼容性设置,主要是支持调用WebHostBuilder和HostBuilder中的配置。同时也兼容了之前代码中的调用方式。因此,在代码升级的时候,如果不想对相关配置调用的部分代码进行改动,是完全可以的。而如果你想做一些改变,改用ConfigurationManager,或者通过WebApplicationBuilder加载(ConfigurationManager会被自动调用),应用程序会有更好的性能。这是一份小礼物,相信也是微软权衡的结果。