简体   繁体   中英

App.config values not read/detected in .Net Core 2.2 class library project

I am creating class library project in .net core 2.2 which can be used in both .net core and .net framework.

Since it is class library project, I have added app.config to read configuration values. Installed ConfigurationManger from Nuget package. Below is app.config file

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <appSettings>
    <add key="InputKey" value="12345" />
  </appSettings>
</configuration>

And the .Net code reads value like below,

INPUT_KEY = ConfigurationManager.AppSettings["InputKey"];

Added Nunit test project and added app.config there as well.The project builds successfully. When I debug my test case the below line always returns null.

  1. Tried copy always for both app.config(class library and test project) and set Nunit test project as startup project- Not working.
  2. Removed app.config[![enter image description here][1]][1] from class library project and kept only test project app.config- Not working.
  3. Set Class library as startup project- Not working.

截屏

<Target Name="CopyCustomContent" AfterTargets="AfterBuild"> 
<Copy SourceFiles="app.config" DestinationFiles="$(OutDir)\testhost.dll.config" /> 
</Target>

Adding above code in .csproj file resolved my issue.

Since my requirement is to use the dll in both .net framework and .net core, I have to create project using .Net Standard instead of .netcore or .netframework.

Thanks @Panagiotis Kanavos for the suggestion.

You can view my post here

Side note: This approach for json file

First install these 2 package

Install-Package Microsoft.Extensions.Options
Install-Package Microsoft.Extensions.DependencyInjection

In your code

public static void Main()
{
    var serviceCollection = new ServiceCollection();
    ConfigureServices(serviceCollection);
}

private static void ConfigureServices(IServiceCollection serviceCollection)
{
      var currentDir = ProjectPath.GetApplicationRoot();

     // build configuration
     varconfiguration = newConfigurationBuilder()
               .SetBasePath(currentDir)
               .AddJsonFile("appsettings.json",false)
               .Build();

     serviceCollection.AddOptions();
     serviceCollection.Configure<WebJobSettings>(configuration.GetSection("WebJobSettings"));
     // add app
     serviceCollection.AddTransient<WebJob>();
}

Then just read like this

public class WebJob
{
  private readonly IOptions<WebJobSettings> _webJobSettings;
  public WebJob(
    IOptions<WebJobSettings> webJobSettings)
  {
    _webJobSettings = webJobSettings;
  } 
}

Keep config files out of your unit tests in the first place! Use a mock instead to deliver the config values instead. This has several advantages:

  • You will be able to test different sets of config values instead of only those that are in the current config file
  • You will be able to test the config values against invalid input
  • You won't have to remember to always maintain another working copy of the config file
  • A cleaner architecture: Unit tests in general should not get in touch with physical files but only test the behaviour of a class

The code below is a recommendation on how you can use mocking to provide the config values for your unit test:

// The class that is accessed in order to get some config setting
public class AppConfig
{
    // The provider reads from a physical file when your lib is shipped but in your tests it will be mocked 
    private readonly AppConfigProvider provider;

    // Constructor used by your app or library
    public AppConfig() : this(new AppConfigProvider())
    {
    }

    // Constructor that can be used by your unit testing framework to inject a mock
    internal AppConfig(AppConfigProvider provider)
    {
        this.provider = provider;
    }

    public string InputKey => GetConfigValueOrThrow("InputKey");

    private string GetConfigValueOrThrow(string configKey)
    {
        string value = provider.GetSetting(configKey);

        if (value == null)
            throw new Exception($"A value for key {configKey} is missing in the App.config file.");

        return value;
    }
}

// Provider implementation that actually reads from the app.config file
internal class AppConfigProvider
{
    internal virtual string GetSetting(string configKey)
    {
        return ConfigurationManager.AppSettings[configKey];
    }
}

// In the test class the config values will be returned by a mock instead of a physical file. This example uses Moq as mocking framework.
public class AppConfigTest
{
    private Mock<AppConfigProvider> mock;
    private AppConfig appConfig;

    [SetUp]
    public void Setup()
    {
        mock = new Mock<AppConfigProvider>();
        appConfig = new AppConfig(mock.Object);
    }

    [Test]
    public void TestInputKeyWhenValueIsValid()
    {
        mock.Setup(provider => provider.GetSetting("InputKey")).Returns("12345");

        Assert.AreEqual("12345", appConfig.InputKey);
    }

}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM