.NetCore技术研究-ConfigurationManager在单元测试下的坑
最近在将原有代码迁移.NET Core, 代码的迁移基本很快,当然也遇到了不少坑,重构了不少,后续逐步总结分享给大家。今天总结分享一下ConfigurationManager遇到的一个问题。
先说一下场景:
迁移.NET Core后,已有的配置文件,我们希望做到兼容,比如说app.config和web.config,
这样配置文件尽可能地和.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.ConfigurationManager
2. 保证原有自定义Section配置相关的代码、读取配置的代码,迁移到.NET Core后编译通过
3. 修改配置文件、单元测试
一、添加Nuget:System.Configuration.ConfigurationManager
搜索System.Configuration.ConfigurationManager:找到Nuget包,并添加引用:

二、保证原有自定义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 个 ==========
三、修改配置文件、单元测试
添加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
.NetCore技术研究-ConfigurationManager在单元测试下的坑的更多相关文章
- .NetCore技术研究-一套代码同时支持.NET Framework和.NET Core
在.NET Core的迁移过程中,我们将原有的.NET Framework代码迁移到.NET Core.如果线上只有一个小型的应用还好,迁移升级完成后,只需要维护.NET Core这个版本的代码. 但 ...
- .NetCore技术研究-.NET Core迁移前的准备工作
前段时间迁移.NET Core做了大量的试水和评估,今天整理一下分享给大家.大致有以下几个部分: 1. .NET Core的由来 2. 为什么要迁移.NET Core 3. .NET Core3.X主 ...
- .NetCore技术研究-EntityFramework Core 3.0 Preview
前段时间.Net Core 3.0 发布了,Entity Framework Core 3.0 也发布了Preview版.假期用了一上午大致研究了一遍,同时又体验了一把Visual Studio 20 ...
- .NET Core技术研究系列-索引篇
随着.NET Core相关技术研究的深入,现在将这一系列的文章,整理到一个索引页中,方便大家翻阅查找,同时,后续也会不断补充进来. .NET Core技术研究-WebApi迁移ASP.NET Core ...
- 重复数据删除(De-duplication)技术研究(SourceForge上发布dedup util)
dedup util是一款开源的轻量级文件打包工具,它基于块级的重复数据删除技术,可以有效缩减数据容量,节省用户存储空间.目前已经在Sourceforge上创建项目,并且源码正在不断更新中.该工具生成 ...
- 伪AP检测技术研究
转载自:http://www.whitecell-club.org/?p=310 随着城市无线局域网热点在公共场所大规模的部署,无线局域网安全变得尤为突出和重要,其中伪AP钓鱼攻击是无线网络中严重的安 ...
- Azure IoT 技术研究系列2-起步示例之设备注册到Azure IoT Hub
上篇博文中,我们主要介绍了Azure IoT Hub的基本概念.架构.特性: Azure IoT 技术研究系列1-入门篇 本文中,我们继续深入研究,做一个起步示例程序:模拟设备注册到Azure IoT ...
- selenium相关技术研究(从1.0-3.0)
注: 以下内容引自http://www.cnblogs.com/hhudaqiang/p/6550135.html Selenium相关技术研究(从1.0-3.0) 好吧,最近看wxpython有点多 ...
- 【转】手把手教你读取Android版微信和手Q的聊天记录(仅作技术研究学习)
1.引言 特别说明:本文内容仅用于即时通讯技术研究和学习之用,请勿用于非法用途.如本文内容有不妥之处,请联系JackJiang进行处理! 我司有关部门为了获取黑产群的动态,有同事潜伏在大量的黑产群 ...
随机推荐
- JavaScript数据结构——树的实现
在计算机科学中,树是一种十分重要的数据结构.树被描述为一种分层数据抽象模型,常用来描述数据间的层级关系和组织结构.树也是一种非顺序的数据结构.下图展示了树的定义: 在介绍如何用JavaScript实现 ...
- Java连载14-补码简介&浮点型整数
一.补码简介 1.计算机中的符号数有三种表示方式,即为:原码.反码.补码.三种表示方法均有符号位和数值位,符号位都是0表示正数,符号位都是1表示负数. 2.计算机中的数字的存储方式:在计算机系统中,数 ...
- 63342 接口 奇遇 IDEA
今天遇到一件很奇怪的事情,本来是想做一些手机页面看看效果,用IDEA 打搭建了一个静态页面网站,可是手机死活就是访问不了,网上的配置方法试过也没有用,其中包括这篇很详细博客: http://fanni ...
- Scala函数式编程(三)
Scala既是一门面向对象(OOP)语言,又是一门函数式编程(FP)语言.作为一门支持函数式编程的语言,Scala鼓励面向表达式编程(EOP)模型.简单来说,EOP中每个语句都有返回值.这一模式很明显 ...
- 深入理解struts的运行机制
扫码关注公众号,不定期更新干活 在此申明本博文并非原创,原文:http://blog.csdn.net/lenotang/article/details/3336623,本文章是在此文章基础上进行优化 ...
- 浅谈 JavaScript 垃圾回收机制
github 获取更多资源 https://github.com/ChenMingK/WebKnowledges-Notes 在线阅读:https://www.kancloud.cn/chenmk/w ...
- Python爬虫视频教程
├─第1章_[第0周]网络爬虫之前奏 │ ├─第1节_"网络爬虫"课程内容导学 │ │ 第1部分_全课程内容导学.mp4 │ │ 第2部分_全课程内容导学(WS00单元)学习资料. ...
- Vue-Router中History模式
目录 history路由 官方示例 Express中间件 客户端兜底404 示例代码托管在:http://www.github.com/dashnowords/blogs 博客园地址:<大史住在 ...
- c中自增自减的妙用
#include <stdio.h> int main() { ; printf("%d,%d,%d,%d",i++;i--;++i;--i); /*运算从右往左运算 ...
- Redis----NoSql数据库笔记
介绍:Redis 是一个开源的使用 ANSI C 语言编写.遵守 BSD 协议.支持网络.可基于内存亦可持久化的日志型.Key-Value 数据库,并提供多种语言的 API的非关系型数据库. 传统数据 ...