如何将IConfigurationRoot或IConfigurationSection转换为JObject / JSON

时间:2019-01-10 13:27:08

标签: asp.net .net asp.net-mvc asp.net-core .net-core

我的Program.cs中包含以下代码:

var configuration = new ConfigurationBuilder()
                .SetBasePath(Directory.GetCurrentDirectory())
                .AddJsonFile("clientsettings.json", optional: true, reloadOnChange: true)
                .AddJsonFile($"clientsettings.{host.GetSetting("environment")}.json", optional: true, reloadOnChange: true)
                .AddEnvironmentVariables()
                .Build();

我想将构建配置的结果转换为JObject \ Json以发送给客户端。我该怎么做? 而且我不想为自己的设置创建自定义类。

4 个答案:

答案 0 :(得分:1)

由于配置实际上只是一个键值存储,其中键具有某种格式来表示路径,因此将其序列化回JSON并不是那么简单。

您可以做的是递归地遍历配置子级并将其值写入JObject。看起来像这样:

public JToken Serialize(IConfiguration config)
{
    JObject obj = new JObject();
    foreach (var child in config.GetChildren())
    {
        obj.Add(child.Key, Serialize(child));
    }

    if (!obj.HasValues && config is IConfigurationSection section)
        return new JValue(section.Value);

    return obj;
}

请注意,这在输出外观上极为有限。例如,数字或布尔值(它们是JSON中的有效类型)将表示为字符串。而且由于数组是通过数字键路径(例如key:0key:1)表示的,因此您将获得作为索引字符串的属性名称。

让我们以以下JSON为例:

{
  "foo": "bar",
  "bar": {
    "a": "string",
    "b": 123,
    "c": true
  },
  "baz": [
    { "x": 1, "y": 2 },
    { "x": 3, "y": 4 }
  ]
}

这将通过以下关键路径在配置中表示:

"foo"      -> "bar"
"bar:a"    -> "string"
"bar:b"    -> "123"
"bar:c"    -> "true"
"baz:0:x"  -> "1"
"baz:0:y"  -> "2"
"baz:1:x"  -> "3"
"baz:1:y"  -> "4"

这样,上述Serialize方法的结果JSON看起来像这样:

{
  "foo": "bar",
  "bar": {
    "a": "string",
    "b": "123",
    "c": "true"
  },
  "baz": {
    "0": { "x": "1", "y": "2" },
    "1": { "x": "3", "y": "4" }
  }
}

因此,这将不允许您取回原始表示。话虽这么说,当再次使用Microsoft.Extensions.Configuration.Json读取结果JSON时,它生成相同的配置对象。因此,您可以使用它来将配置存储为JSON。

如果您想要更漂亮的东西,则必须添加逻辑来检测数组和非字符串类型,因为这两者都不是配置框架的概念。


  

我想将appsettings.jsonappsettings.{host.GetSetting("environment")}.json合并为一个对象[并将其发送给客户端]

请记住,特定于环境的配置文件通常包含不应该离开计算机的机密。对于环境变量尤其如此。如果要传输配置值,请确保在构建配置时不要包括环境变量。

答案 1 :(得分:1)

通过IConfiguration方法生成的Build()对象将包含您的所有配置源,并将根据添加配置源的顺序所定义的优先级顺序进行合并。

在您的情况下,这将是:

  • clientsettings.json
  • clientsettings.env.json
  • 环境变量

您无需担心手动合并源文件或加载文件的麻烦,

为了改善poke的答案,我想到了这一点:

    private JToken Serialize(IConfiguration config)
    {
        JObject obj = new JObject();

        foreach (var child in config.GetChildren())
        {
            if (child.Path.EndsWith(":0"))
            {
                var arr = new JArray();

                foreach (var arrayChild in config.GetChildren())
                {
                    arr.Add(Serialize(arrayChild));
                }

                return arr;
            }
            else
            {
                obj.Add(child.Key, Serialize(child));
            }
        }

        if (!obj.HasValues && config is IConfigurationSection section)
        {
            if (bool.TryParse(section.Value, out bool boolean))
            {
                return new JValue(boolean);
            }
            else if (decimal.TryParse(section.Value, out decimal real))
            {
                return new JValue(real);
            }
            else if (long.TryParse(section.Value, out int integer))
            {
                return new JValue(integer);
            }

            return new JValue(section.Value);
        }

        return obj;
    }

以上代码说明了booleanlongdecimal等数据类型。

longdecimal是可用于整数的最大数据类型,因此将包含任何较小的值,例如shortfloat

该代码还将正确构建数组,因此最终在一个json文件中以类似的方式表示所有配置。

答案 2 :(得分:0)

配置数据由KeyValuePair<string, string>的展平集合表示。您可以从中创建字典并将其序列化为JSON。但是,这可能不会给您想要的结果:

Configuration.AsEnumerable().ToDictionary(k => k.Key, v => v.Value);

此外,请记住,此配置对象将包含环境变量,您肯定希望将其发送给客户端。

更好的选择可能是先将配置绑定到POCO,然后将其序列化为JSON:

var appConfig = new AppConfig();
Configuration.Bind(appConfig);
var json = JsonConvert.SerializeObject(appConfig);

public class AppConfig
{
    // Your settings here

    public string Foo { get; set; }

    public int Bar { get; set; }
}

答案 3 :(得分:0)

您是否真的想将所有环境变量(.AddEnvironmentVariables()),连接字符串以及appsettings中的所有其他内容发送给客户端???我建议您不要这样做。

相反,创建一个类(例如ClientConfigOptions),使用services.Configure<ClientConfigOptions>(configuration.GetSection("clientConfig"))配置其绑定并将其发送给客户端。

使用这种方法,您还可以使用Actions调整ClientConfigOptions,从不同的appsetting路径复制一些值,等等。