using System.Collections;
using System.Collections.Generic;
using System.Runtime.Serialization.Formatters;
using System.ComponentModel.DataAnnotations;
using System.Globalization;
using System.Collections.ObjectModel;
using System.Text.Json.Serialization;
public sealed class DictionaryConverter : JsonConverter<IDictionary<string, object>>
public override IDictionary<string, object> Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
if (reader.TokenType != JsonTokenType.StartObject)
throw new JsonException(string.Format("Unexpected token {0}", reader.TokenType));
IDictionary<string, object> output = new Dictionary<string, object>();
while (reader.Read() && reader.TokenType != JsonTokenType.EndObject)
string propertyName = reader.GetString()!;
switch (reader.TokenType)
case JsonTokenType.Number:
if (reader.TryGetInt64(out var l))
else if (reader.TryGetDecimal(out var d))
using var doc = JsonDocument.ParseValue(ref reader);
propertyValue = doc.RootElement.ToString();
throw new JsonException(string.Format("Cannot parse number: {0}", propertyValue));
case JsonTokenType.String:
if (reader.TryGetDateTime(out var dt))
propertyValue = reader.GetString();
case JsonTokenType.False:
propertyValue = reader.GetBoolean();
throw new JsonException(string.Format("Unexpected token {0}", reader.TokenType));
if (propertyValue == null)
throw new JsonException("null value");
output.Add(propertyName, propertyValue);
public override void Write(Utf8JsonWriter writer, IDictionary<string, object> value, JsonSerializerOptions options) =>
JsonSerializer.Serialize(writer, value, options.CopyAndRemoveConverter(GetType()));
public static class JsonSerializerExtensions
public static JsonSerializerOptions CopyAndRemoveConverter(this JsonSerializerOptions options, Type converterType)
var copy = new JsonSerializerOptions(options);
for (var i = copy.Converters.Count - 1; i >= 0; i--)
if (copy.Converters[i].GetType() == converterType)
copy.Converters.RemoveAt(i);
public static void Test()
var dictionary = new Dictionary<string, object>()
{"date", new DateTime(2021, 3, 3, 10, 10, 10) },
var options = new JsonSerializerOptions
Converters = { new DictionaryConverter() },
var json = JsonSerializer.Serialize(dictionary, options);
var dictionary2 = JsonSerializer.Deserialize<IDictionary<string, object>>(json, options);
Assert.IsTrue(dictionary2 != null);
Assert.IsTrue(dictionary.Keys.SequenceEqual(dictionary2!.Keys));
Assert.IsTrue(dictionary.Values.SequenceEqual(dictionary2!.Values));
public static void Main()
Console.WriteLine("Environment version: {0} ({1})", System.Runtime.InteropServices.RuntimeInformation.FrameworkDescription , GetNetCoreVersion());
Console.WriteLine("System.Text.Json version: " + typeof(JsonSerializer).Assembly.FullName);
Console.WriteLine("Failed with unhandled exception: ");
public static string GetNetCoreVersion()
var assembly = typeof(System.Runtime.GCSettings).GetTypeInfo().Assembly;
var assemblyPath = assembly.Location.Split(new[] { '/', '\\' }, StringSplitOptions.RemoveEmptyEntries);
int netCoreAppIndex = Array.IndexOf(assemblyPath, "Microsoft.NETCore.App");
if (netCoreAppIndex > 0 && netCoreAppIndex < assemblyPath.Length - 2)
return assemblyPath[netCoreAppIndex + 1];