简体   繁体   English

在单元测试中反序列化 appsettings.json

[英]Deserialize appsettings.json in unit test

There are many examples out there that show how to deserialize your app settings within the Startup.cs class. I get that.许多示例展示了如何在Startup.cs class 中反序列化您的应用程序设置。我明白了。 But that's not what I'm asking.但这不是我要问的。 I'm working within a unit test constructor.我在单元测试构造函数中工作。

This question is close: Read appsettings json values in .NET Core Test Project But in reading it carefully, I'm not seeing a slam dunk answer.这个问题很接近: 阅读 appsettings json values in .NET Core Test Project但是仔细阅读,我没有看到灌篮高手的答案。

appsettings.json:应用设置.json:

{
  "AppSettings": {
    "myKey1": "myValue1",
    "myKey2": "myValue2",
  }
}

And:和:

public class AppSettings
{
    public string myKey1 { get; set; }
    public string myKey2 { get; set; }
}

I am able to get single values just fine:我能够很好地获得单个值:

var config = new ConfigurationBuilder()
              .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
              .Build();
var myValue1 = config.GetSection("AppSettings:myKey1 ").Value;

But what I'm not figuring out is how to get create an instance of AppSettings .但我不知道的是如何创建AppSettings的实例。 I've tried:我试过了:

var appSettings = config.GetValue<AppSettings>("AppSettings");

But that ends up null. And I've played around with trying to create my own instance of IServiceCollection so I could do something like you might in Startup.cs , but I'm not making any progress.但这最终是 null。我一直在尝试创建自己的IServiceCollection实例,这样我就可以像在Startup.cs中那样做一些事情,但我没有取得任何进展。

Short answer简答

var section = config.GetSection(nameof(AppSettings));
var settings = section.Get<AppSettings>

Long answer长答案

You can't just do config.Get<AppSettings> as implied by other answers.您不能像其他答案所暗示的那样只执行config.Get<AppSettings> That tries to bind the whole config file to that class, which doesn't work, resulting in silent failure (null members).这试图将整个配置文件绑定到那个 class,这不起作用,导致静默失败(空成员)。

You need to get the section first before deserializing to a settings object instance:在反序列化为设置 object 实例之前,您需要先获取该部分:

var section = config.GetSection(nameof(AppSettings));
var settings = section.Get<AppSettings>

You can use Bind instead of Get if desired:如果需要,您可以使用Bind而不是Get

var section = config.GetSection(nameof(AppSettings));
var settings = new AppSettings();
section.Bind(settings);

There are other overloads for if your section's name doesn't match your settings class's name.如果您的部分名称与您的设置类名称不匹配,还有其他重载。

Bonus: extension methods奖励:扩展方法

public static class IConfigurationExtensions
{
    public static T GetSection<T>(this IConfiguration config) where T : class, new()
    {
        IConfigurationSection section = config.GetSection(typeof(T).Name);
        return section.Get<T>();
    }
}

// Usage
var settings = config.GetSection<AppSettings>();

Going beyond the original question, you can inject these settings sections like this (using the extension method above):超越原来的问题,你可以像这样注入这些设置部分(使用上面的扩展方法):

public static class IServiceCollectionExtensions
{
    public static IServiceCollection AddSingletonConfigSection<T>(
        this IServiceCollection services, IConfiguration config) where T : class, new()
    {
        T section = config.GetSection<T>();
        services.AddSingleton<T>(section);
        return services;
    }

    public static IServiceCollection AddScopedConfigSection<T>(
        this IServiceCollection services, IConfiguration config) where T : class, new()
    {
        services.AddScoped<T>(_ => config.GetSection<T>());
        return services;
    }
}

// Usage
services.AddSingletonConfigSection<AppSettings>(config);
services.AddScopedConfigSection<AppSettings>(config);

I believe you would have to create a new instance of IConfiguration and then get its values like you already are doing.我相信你必须创建一个IConfiguration的新实例,然后像你已经在做的那样获取它的值。

public UnitTestConstructor(IConfiguration configuration){
      Configuration = configuration;
}

public IConfiguration Configuration { get; }

public TestOne(){
      var appSettingsValue = Configuration.GetValue<string>("AppSettings:MyValue");
}

You have to use the Microsoft.Extensions.Configuration.Binder extension, available as a separate package on NuGet .您必须使用Microsoft.Extensions.Configuration.Binder扩展,该扩展可作为NuGet上的单独包提供。

Specifically, use the Configuration.Bind() method:具体来说,使用Configuration.Bind()方法:

AppSettings appSettings;

config.Bind(appSettings);

Or even simpler:或者更简单:

var appSettings = config.Get<AppSettings>();

You could also bind it with help of DI:你也可以在 DI 的帮助下绑定它:

services.Configure<AppSettings>(_configuration.GetSection("AppSettings"));

Then in your service that needs these settings, just add AppSettings appSettings as a dependency to it and the dependency should auto-resolve.然后在需要这些设置的服务中,只需将AppSettings appSettings添加为它的依赖项,该依赖项就会自动解析。

听起来你想使用ConfigurationBinder.Get<T>() (而不是ConfigurationBinder.GetValue<T>()

I ended up just doing this.我最终只是这样做了。

public class AppSettings
{
    AppSettings(IConfigurationRoot config)
    {
            myKey1 = config.GetSection("AppSettings:MyKey1").Value;
            myKey2 = config.GetSection("AppSettings:MyKey2").Value;
    }

    public string myKey1 { get; set; }
    public string myKey2 { get; set; }
}

Not ideal but it gets the job done and I can move on.不理想,但它完成了工作,我可以继续前进。

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

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