简体   繁体   English

.Net Core 2.2 类库项目中未读取/检测到 App.config 值

[英]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.我正在.net core 2.2 中创建类库项目,它可以在 .net core 和 .net framework 中使用。

Since it is class library project, I have added app.config to read configuration values.由于是类库项目,所以添加了 app.config 来读取配置值。 Installed ConfigurationManger from Nuget package.从 Nuget 包安装 ConfigurationManger。 Below is app.config file下面是 app.config 文件

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

And the .Net code reads value like below, .Net 代码读取如下值,

INPUT_KEY = ConfigurationManager.AppSettings["InputKey"];

Added Nunit test project and added app.config there as well.The project builds successfully.添加了 Nunit 测试项目并在那里添加了 app.config。项目构建成功。 When I debug my test case the below line always returns null.当我调试我的测试用例时,下面的行总是返回 null。

  1. Tried copy always for both app.config(class library and test project) and set Nunit test project as startup project- Not working.始终尝试复制 app.config(类库和测试项目)并将 Nunit 测试项目设置为启动项目 - 不工作。
  2. Removed app.config[![enter image description here][1]][1] from class library project and kept only test project app.config- Not working.从类库项目中删除了 app.config[![enter image description here][1]][1] 并只保留了测试项目 app.config- 不工作。
  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.在 .csproj 文件中添加上述代码解决了我的问题。

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.由于我的要求是在 .net framework 和 .net core 中使用 dll,我必须使用 .Net Standard 而不是 .netcore 或 .netframework 创建项目。

Thanks @Panagiotis Kanavos for the suggestion.感谢@Panagiotis Kanavos 的建议。

You can view my post here你可以在这里查看我的帖子

Side note: This approach for json file旁注:这种方法用于 json 文件

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);
    }

}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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