.NetCore technology research -ConfigurationManager pit in unit testing

Recently in the original code migration .NET Core, migrate the code base quickly, of course, also encountered a lot of pits, a lot of remodeling, follow step by step summary to others. Today, share a summary of the problem encountered ConfigurationManager.

Let me talk about the scene:

   After migrating .NET Core, the existing configuration file, we want to be accommodating, for example app.config and web.config,

   Such profiles as much as possible and the .NET Framework is set as low as possible consistent. For example: appSettings , custom configSection and so on.

<?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>

 For the above configuration read a couple of the things we do

   1. 添加Nuget:System.Configuration.ConfigurationManager

   2. Section ensure that the original custom configuration related code, read code configuration, migration to .NET Core compiled by

   3. To modify the configuration files, unit testing

 First, add Nuget: System.Configuration.ConfigurationManager

   Search System.Configuration.ConfigurationManager: find Nuget package, and add a reference:

   

Second, ensure that the original configuration-related Section custom code, read the code configuration, .NET Core migration to compile

  Sample code, custom configuration class 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 configuration section while the corresponding analytic categories: CustomConfigHandler , implement interfaces: 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;
        }
    }
}

    At the same time, we wrote a simple configuration management class: CustomConfigManager , including configuration read method directly reads the configuration file:

        public static List<CustomConfig> GetCustomConfigs()
        {
            var sectionConfig = System.Configuration.ConfigurationManager.GetSection("CustomConfigs");
            if (sectionConfig != null)
            {
                return  sectionConfig as List<CustomConfig>;
            }

            return null;
        }

  

  Here we use .NET Standard 2.0 library project, compile the code:

1> ------ Rebuild All started: Project: ClassLibraryNetStandard, Configuration: Debug the CPU the Any ------
1> C: \ Program Files \ DOTNET \ sdk \ 3.0.100-preview3-010431 \ sdks \ Microsoft.NET.Sdk \ targets \ Microsoft.NET.RuntimeIdentifierInference.targets (151,5 ): message NETSDK1057: you are using .NET Core's preview. See the https://aka.ms/dotnet-core-preview
1> ClassLibraryNetStandard -> C: \ the Users \ *** \ Source \ Repos \ NETFrameworkTest \ ClassLibraryNetStandard \ bin \ Debug \ netstandard2.0 \ ClassLibraryNetStandard.dll
== ======== Rebuild all: a successful, 0 failed, 0 skipped ==========

   Third, modify the configuration file, unit testing

  Add MSTest unit test project:   

  

   Increase App.config configuration file:

   

   In the test method the test unit configured to read:

       [TestMethod]
        public void ConfigTest()
        {
            var configs = ClassLibraryNetStandard.CustomConfigManager.GetCustomConfigs();
            Assert.IsNotNull(configs);
        }

  Originally thought, certainly can get to the configuration, the actual acquisition of configs is null.

        One Console application for a class, the same configuration file is read, it is not a problem:

      

      Contrast looked at these two projects, found that in addition to the actual compiler generates different profile name, other are the same.

      The problem certainly lies in the unit test project. Google a bit: the following findings:       

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.

  Saying: MSTest to testhost.dll run, fetch the configuration file is testhost.dll.config

        It's too embarrassing, direct silent, but there are two solutions:

        1. app.config file directly in the unit test project will be changed to: testhost.dll.config

        2. Modify the unit test project file, compiled after the event configuration, dynamically generated copy testhost.dll.config

       

      After I tried, really can, problem solving, sharing one everyone.

 

 

Zhou Guoqing

2019/9/12

Guess you like

Origin www.cnblogs.com/tianqing/p/11514840.html