using System.Collections;
using System.Collections.Generic;
using System.Text.Json.Serialization;
using System.Text.Json.Nodes;
public static partial class JsonExtensions
readonly static JsonSerializerOptions defaultOptions = new () { Converters = { AlphabeticJsonNodeConverter.Instance } };
public static string ToAlphabeticJsonString(this JsonNode? node, JsonSerializerOptions? options = default)
options = defaultOptions;
options = new JsonSerializerOptions(options);
options.Converters.Insert(0, AlphabeticJsonNodeConverter.Instance);
return JsonSerializer.Serialize(node, options);
public class AlphabeticJsonNodeConverter : JsonConverter<JsonNode>
public static AlphabeticJsonNodeConverter Instance { get; } = new AlphabeticJsonNodeConverter();
public override bool CanConvert(Type typeToConvert) => typeof(JsonNode).IsAssignableFrom(typeToConvert) && typeToConvert != typeof(JsonValue);
public override void Write(Utf8JsonWriter writer, JsonNode? value, JsonSerializerOptions options)
writer.WriteStartObject();
foreach (var pair in obj.OrderBy(p => p.Key, StringComparer.Ordinal))
writer.WritePropertyName(pair.Key);
Write(writer, pair.Value, options);
writer.WriteStartArray();
foreach (var item in array)
Write(writer, item, options);
value.WriteTo(writer, options);
public override JsonNode? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) => JsonNode.Parse(ref reader);
public static void Test()
var jsonString = GetJson();
Test<JsonNode>(jsonString);
Test<JsonObject>(jsonString);
static void Test<TJsonNode>(string jsonString) where TJsonNode : JsonNode
var node = (TJsonNode)JsonNode.Parse(jsonString)!;
static void TestWrite<TJsonNode>(TJsonNode node) where TJsonNode : JsonNode
var options = new JsonSerializerOptions
var json2 = node.ToAlphabeticJsonString(options);
Console.WriteLine(json2);
var node2 = JsonSerializer.Deserialize<TJsonNode>(json2, options);
var json3 = JsonSerializer.Serialize(node2, new JsonSerializerOptions { WriteIndented = options.WriteIndented });
Assert.AreEqual(json2, json3);
static void TestWeirdValue()
var node = JsonValue.Create(new { ZProperty = "foo", AProperty = "bar" })!;
Console.WriteLine(node.GetValue<object>().GetType());
Console.WriteLine(node.GetType());
Console.WriteLine(node.ToJsonString());
static string GetJson() => @"
""Title"": ""example glossary"",
""GlossTerm"": ""Standard Generalized Markup Language"",
""Abbrev"": ""ISO 8879:1986"",
""Para"": ""A meta-markup language, used to create markup languages such as DocBook."",
""GlossSeeAlso"": [""GML"", ""XML""]
""GlossSee"": ""markup"",
""aGlossSee"": ""amarkup""
public static void Main()
Console.WriteLine("Environment version: {0} ({1}), {2}", System.Runtime.InteropServices.RuntimeInformation.FrameworkDescription , Environment.Version, Environment.OSVersion);
Console.WriteLine("System.Text.Json version: " + typeof(JsonSerializer).Assembly.FullName);
Console.WriteLine("Failed with unhandled exception: ");