最近在將原有代碼遷移.NET Core, 代碼的遷移基本很快,固然也遇到了很多坑,重構了很多,後續逐步總結分享給你們。今天總結分享一下ConfigurationManager遇到的一個問題。html
先說一下場景:web
遷移.NET Core後,已有的配置文件,咱們但願作到兼容,好比說app.config和web.config,app
這樣配置文件儘量地和.NET Framework是一套,儘量低保持一致。好比:appSettings、自定義configSection等等。單元測試
<?xml version="1.0" encoding="utf-8" ?> <configuration> <configSections> <section name="CustomConfigs" type="ClassLibraryNetStandard.CustomConfigHandler, ClassLibraryNetStandard"/> </configSections> <CustomConfigs> <CustomConfig name="service1" order="0" reflectconfig="ClassLibraryNetStandard.TestService, ClassLibraryNetStandard"/> <CustomConfig name="service2" order="1" reflectconfig="ClassLibraryNetStandard.TestService2, ClassLibraryNetStandard"/> </CustomConfigs> <appSettings> <add key="service" value="service1"/> </appSettings> </configuration>
對於上面配置讀取咱們作了如下幾個事情測試
1. 添加Nuget:System.Configuration.ConfigurationManagerspa
2. 保證原有自定義Section配置相關的代碼、讀取配置的代碼,遷移到.NET Core後編譯經過3d
3. 修改配置文件、單元測試xml
1、添加Nuget:System.Configuration.ConfigurationManagerhtm
搜索System.Configuration.ConfigurationManager:找到Nuget包,並添加引用:blog
2、保證原有自定義Section配置相關的代碼、讀取配置的代碼,遷移到.NET Core後編譯經過
示例代碼中,自定義配置類CustomConfig:
using System; using System.Collections.Generic; using System.Text; namespace ClassLibraryNetStandard { public class CustomConfig { public string Name { get; set; } public string ReflectConfig { get; set; } public int Order { get; set; } } }
同時對應的Section配置節解析類:CustomConfigHandler,實現接口:System.Configuration.IConfigurationSectionHandler
using System; using System.Collections.Generic; using System.Text; using System.Xml; namespace ClassLibraryNetStandard { public class CustomConfigHandler : System.Configuration.IConfigurationSectionHandler { public object Create(object parent, object configContext, XmlNode section) { var configs = new List<CustomConfig>(); //獲取配置文件中自定義節點值 foreach (XmlNode childNode in section.ChildNodes) { string name = null; var config = new CustomConfig(); if (childNode.Attributes["name"] != null) { name = childNode.Attributes["name"].Value; config.Name = name; if (childNode.Attributes["order"] != null) { config.Order = Convert.ToInt32(childNode.Attributes["order"].Value); } if (childNode.Attributes["reflectconfig"] != null) { config.ReflectConfig = childNode.Attributes["reflectconfig"].Value; } configs.Add(config); } } return configs; } } }
同時,咱們編寫了一個簡單的配置管理類:CustomConfigManager,其中有配置讀取方法,直接讀取配置文件:
public static List<CustomConfig> GetCustomConfigs() { var sectionConfig = System.Configuration.ConfigurationManager.GetSection("CustomConfigs"); if (sectionConfig != null) { return sectionConfig as List<CustomConfig>; } return null; }
這裏咱們使用了.NET Standard 2.0 library project,代碼編譯經過:
1>------ 已啓動所有從新生成: 項目: ClassLibraryNetStandard, 配置: Debug Any CPU ------
1>C:\Program Files\dotnet\sdk\3.0.100-preview3-010431\Sdks\Microsoft.NET.Sdk\targets\Microsoft.NET.RuntimeIdentifierInference.targets(151,5): message NETSDK1057: 你正在使用 .NET Core 的預覽版。請查看 https://aka.ms/dotnet-core-preview
1>ClassLibraryNetStandard -> C:\Users\***\source\repos\NETFrameworkTest\ClassLibraryNetStandard\bin\Debug\netstandard2.0\ClassLibraryNetStandard.dll
========== 所有從新生成: 成功 1 個,失敗 0 個,跳過 0 個 ==========
3、修改配置文件、單元測試
添加MSTest單元測試工程:
增長App.config配置文件:
在單元測試方法中測試配置的讀取:
[TestMethod] public void ConfigTest() { var configs = ClassLibraryNetStandard.CustomConfigManager.GetCustomConfigs(); Assert.IsNotNull(configs); }
本來覺得,確定能夠獲取到配置,實際獲取的configs是null。
換了個Console類的應用,一樣的配置文件讀取,一點沒有問題:
對比看了一下這兩個工程,發現除了實際編譯生成的配置文件名稱不一樣,其餘都同樣。
問題確定出在了單元測試工程上。Google了一下:有如下發現:
MSTest is running as testhost.dll, which means that ConfigurationManager is reading settings from testhost.dll.config when executing under .NET core.
It will look for testhost.dll.config where the testhost.dll is located as the accepted answer states.
What is not mentioned is that it will also look for testhost.dll.config in the location where you have your test dlls.
一句話:MSTest以testhost.dll運行,去取的配置文件是testhost.dll.config
這太尷尬了,直接無語,不過有兩個解決方案:
1. 直接在單元測試工程中將app.config文件改成:testhost.dll.config
2. 修改單元測試工程文件,配置編譯後事件,動態copy生成testhost.dll.config
試過以後,果然能夠了,問題解決,分享給你們。
周國慶
2019/9/12