Is there a built-in method to convert .NET Configuration to JSON?

756 Views Asked by At

It's easy to convert JSON into configuration, e.g. with

using var stream = new MemoryStream(Encoding.UTF8.GetBytes(json));
var configuration = new ConfigurationBuilder().AddJsonStream(stream).Build();

which gives you an IConfigurationRoot.

Is there a method (preferably in one of the Microsoft.Extensions.Configuration packages) that does the reverse?

Context: I'm downloading a bunch of Azure App Configuration settings and want to export them as JSON. Similar functionality is available in the Azure Portal but I want to resolve key vault references as well.

I can probably do something like this:

// Convert to JSON
var jRoot = new JObject();
foreach (var setting in settings) {
    Add(jRoot, setting.Key, setting.Value);
}

with the Add method defined as

private void Add(JObject jObject, string key, string value) {
    var index = key.IndexOf(':');
    if (index == -1) {
        jObject[key] = value;
        return;
    }
    var prefix = key[..index];
    if (!jObject.ContainsKey(prefix)) {
        jObject[prefix] = new JObject();
    }
    Add((JObject)jObject[prefix], key[(index + 1)..], value);
}

which I'd probably need to extend to support arrays, but I was hoping I'd not have to reinvent the wheel.

1

There are 1 best solutions below

0
Glorfindel On

For now, I've expanded the Add method to support arrays:

private void Add(JToken jToken, string key, string value) {
    var components = key.Split(":", 3);
    if (components.Length == 1) {
        // Leaf node
        if (jToken is JArray jArray_) {
            jArray_.Add(value);
        } else {
            jToken[components[0]] = value;
        }
        return;
    }

    // Next level
    JToken nextToken;
    var nextTokenIsAnArray = int.TryParse(components[1], out _);
    if (jToken is JArray jArray) {
        var index = int.Parse(components[0]);
        if (jArray.Count == index) {
            nextToken = nextTokenIsAnArray ? new JArray() : (JToken)new JObject();
            jArray.Add(nextToken);
        } else {
            nextToken = jArray[index];
        }
    } else {
        nextToken = jToken[components[0]];
        if (nextToken == null) {
            nextToken = jToken[components[0]] = nextTokenIsAnArray ? new JArray() : (JToken)new JObject();
        }
    }

    Add(nextToken, key[(components[0].Length + 1)..], value);
}

which works for me, assuming arrays appear in the right order, e.g.

  • key "Foo:0", value "Bar"
  • key "Foo:1", value "Baz"

which gets serialized as

{ "Foo": ["Bar", "Baz"] }