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

heo*_*xfy 8 .net asp.net asp.net-mvc .net-core asp.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();
Run Code Online (Sandbox Code Playgroud)

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

我的答案: 合并

public static JObject GetSettingsObject(string environmentName)
    {
        object[] fileNames = { "settings.json", $"settings.{environmentName}.json" };


        var jObjects = new List<object>();

        foreach (var fileName in fileNames)
        {
            var fPath = Directory.GetCurrentDirectory() + Path.DirectorySeparatorChar + fileName;
            if (!File.Exists(fPath))
                continue;

            using (var file = new StreamReader(fPath, Encoding.UTF8))
                jObjects.Add(JsonConvert.DeserializeObject(file.ReadToEnd()));
        }


        if (jObjects.Count == 0)
            throw new InvalidOperationException();


        var result = (JObject)jObjects[0];
        for (var i = 1; i < jObjects.Count; i++)
            result.Merge(jObjects[i], new JsonMergeSettings
            {
                MergeArrayHandling = MergeArrayHandling.Merge
            });

        return result;
    }
Run Code Online (Sandbox Code Playgroud)

pok*_*oke 6

由于配置实际上只是一个键值存储,其中键具有某种格式来表示路径,因此将其序列化回 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;
}
Run Code Online (Sandbox Code Playgroud)

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

让我们以下面的 JSON 为例:

{
  "foo": "bar",
  "bar": {
    "a": "string",
    "b": 123,
    "c": true
  },
  "baz": [
    { "x": 1, "y": 2 },
    { "x": 3, "y": 4 }
  ]
}
Run Code Online (Sandbox Code Playgroud)

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

"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"
Run Code Online (Sandbox Code Playgroud)

因此,上述Serialize方法的结果 JSON将如下所示:

{
  "foo": "bar",
  "bar": {
    "a": "string",
    "b": "123",
    "c": "true"
  },
  "baz": {
    "0": { "x": "1", "y": "2" },
    "1": { "x": "3", "y": "4" }
  }
}
Run Code Online (Sandbox Code Playgroud)

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

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


我想合并appsettings.json,并appsettings.{host.GetSetting("environment")}.json以一个对象[和发送到客户端]

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


DrB*_*rBB 6

以下是 Tom 的解决方案,已转换为使用 System.Text.Json。

static internal JsonNode? Serialize(IConfiguration config)
{
    JsonObject obj = new();

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

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

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

    if (obj.Count() == 0 && config is IConfigurationSection section)
    {
        if (bool.TryParse(section.Value, out bool boolean))
        {
            return JsonValue.Create(boolean);
        }
        else if (decimal.TryParse(section.Value, out decimal real))
        {
            return JsonValue.Create(real);
        }
        else if (long.TryParse(section.Value, out long integer))
        {
            return JsonValue.Create(integer);
        }

        return JsonValue.Create(section.Value);
    }

    return obj;
}


// Use like this...
var json = Serialize(Config);
File.WriteAllText("out.json",
    json.ToJsonString(new JsonSerializerOptions() { WriteIndented = true}));
Run Code Online (Sandbox Code Playgroud)


Hen*_*ema 3

配置数据由扁平化的KeyValuePair<string, string>. 您可以从中创建一个字典并将其序列化为 JSON。然而,这可能不会给你想要的结果:

Configuration.AsEnumerable().ToDictionary(k => k.Key, v => v.Value);
Run Code Online (Sandbox Code Playgroud)

另外,请记住,此配置对象将包含环境变量,您绝对不想将这些发送到客户端。

更好的选择可能是首先将配置绑定到 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; }
}
Run Code Online (Sandbox Code Playgroud)

  • 我不想为此目的创建自定义类。 (2认同)