【问题标题】:How to pass a POCO class to .NET Core configuration如何将 POCO 类传递给 .NET Core 配置
【发布时间】:2018-08-29 04:19:52
【问题描述】:

我正在对 .NET Core 应用程序进行集成测试,并希望使用一些测试配置。我的配置是一个 POCO 类,它通过appsettings.json 配置,然后通过IOptions<T> 使用。在我的测试中,我想使用该类的一个实例。

代码如下:

 var mySettings = GetTestSettings(); // factory method returning POCO class 
 var configurationBuilder = new ConfigurationBuilder();

 // I am looking for something like 
 configurationBuilder.AddInMemoryObject("Settings", mySettings);

 // does not work, result is just string 
 configurationBuilder.AddInMemoryCollection("Settings",
        JsonConvert.SerializeObject(mySettings)); 

// requires filename
configurationBuilder.AddJsonFile("filename.json");

将 POCO 提供给配置的最简单方法是什么?

【问题讨论】:

  • 你想对设置做什么,例如在另一个类、控制器等中使用?这个 POCO 类是否也用于存储从 appsettings.json 文件加载的设置?
  • @SimplyGed 更新了我的问题。
  • 您只想将 IOptions 传递给您的测试类吗?这个答案解决了stackoverflow.com/a/40898882/2309376
  • 不,我用的是TestServer,应该注入这个配置。

标签: c# asp.net-core .net-core


【解决方案1】:

AddInMemoryCollection 采用 KeyValuePair 的集合,其中键是设置键,值是它的值。这个来自问题的电话

configurationBuilder.AddInMemoryCollection("Settings", JsonConvert.SerializeObject(mySettings));

实际上将“设置”作为键传递,将整个 JSON 作为一个设置值传递,这预计不起作用。

但总体方法是正确的,您应该使用AddInMemoryCollection 分机调用。在传递给此调用的集合中,设置键是配置中的完整路径,由冒号分隔。假设您有以下设置 POCO:

public class SomeSettings
{
    public string SomeKey1 { get; set; }
    public int SomeKey2 { get; set; }
}

它是从以下 JSON 加载的

{
    "SomeSettings": {
        "SomeKey1": "SomeData",
        "SomeKey2": 123
    } 
}

键是SomeSettings:SomeKey1SomeSettings:SomeKey2

然后您可以使用以下AddInMemoryCollection 调用添加此类配置:

configurationBuilder.AddInMemoryCollection(new Dictionary<string, string>
{
    { "SomeSettings:SomeKey1", "SomeData" },
    { "SomeSettings:SomeKey2", 123 },
});

现在,如果您想通过一次调用添加设置 POCO,您可以编写简单的扩展方法,该方法将使用反射枚举设置类属性并返回属性名称和值的键值对集合。

这是一个示例:

public static class ObjectExtensions
{
    public static IEnumerable<KeyValuePair<string, string>> ToKeyValuePairs(this Object settings, string settingsRoot)
    {
        foreach (var property in settings.GetType().GetProperties())
        {
            yield return new KeyValuePair<string, string>($"{settingsRoot}:{property.Name}", property.GetValue(settings).ToString());
        }
    }
}

public static class ConfigurationBuilderExtensions
{
    public static void AddInMemoryObject(this ConfigurationBuilder configurationBuilder, object settings, string settingsRoot)
    {
        configurationBuilder.AddInMemoryCollection(settings.ToKeyValuePairs(settingsRoot));
    }
}

在测试中:

var configurationBuilder = new ConfigurationBuilder();
var mySettings = GetTestSettings();
configurationBuilder.AddInMemoryObject(mySettings, "Settings");

这种简单的ObjectExtensions.ToKeyValuePairs 扩展方法将适用于像上面的SomeSettings 这样的普通POCO。但是,如果某些属性也是像这里这样的对象,它将不起作用:

public class InnerSettings
{
    public string SomeKey { get; set; }
}

public class OuterSettings
{
    public InnerSettings InnerSettings { get; set; }
}

但是我相信您有一个想法,并且可以根据需要进行必要的调整。

【讨论】:

  • 是的,谢谢你的回答。就我而言,我有嵌套对象,因此需要添加对它的支持。
【解决方案2】:

我最终得到了以下结果:

configurationBuilder.AddInMemoryCollection(ToDictionary(GetTestSettings()));

private static IEnumerable<KeyValuePair<string, string>> ToDictionary(object o) => 
    AddPropsToDic(JObject.FromObject(o), new Dictionary<string, string>(), "Settings");

private static Dictionary<string, string> AddPropsToDic(JObject jo, Dictionary<string, string> dic, string prefix)
{
    jo.Properties()
        .Aggregate(dic, (d, jt) =>
        {
            var value = jt.Value;
            var key = $"{prefix}:{jt.Name}";

            if (value.HasValues)
                return AddPropsToDic((JObject) jt.Value, dic, key);

            dic.Add(key, value.ToString());
            return dic;
        });
    return dic;
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-11-18
    • 2019-12-31
    • 1970-01-01
    • 1970-01-01
    • 2017-08-22
    • 1970-01-01
    • 2020-09-10
    相关资源
    最近更新 更多