Rory Claasen

KeyValuePair Json Converter

2 min read

During one of my recent projects, I was unable to serialize a C++ std::map<std::string, std::string> before sending to a C# client.

To solve this I sent the data as a JSON array of key-value pairs. For the C# client to deserialize the JSON array, I created a custom JsonConverter for KeyValuePair<TKey, TValue>. This converter allows you to serialize and deserialize a JSON array of key-value pairs into a Dictionary<TKey, TValue>.

KeyValuePairConverter.cs
using System;
using System.Collections.Generic;
using System.Text.Json;
using System.Text.Json.Serialization;
public class KeyValuePairConverter<TKey, TValue> : JsonConverter<Dictionary<TKey, TValue>>
where TKey : notnull
{
public override bool CanConvert(Type typeToConvert)
{
if (base.CanConvert(typeToConvert))
{
return true;
}
if (typeToConvert.GetGenericTypeDefinition() == typeof(IDictionary<,>) ||
typeToConvert.GetGenericTypeDefinition() == typeof(IReadOnlyDictionary<,>))
{
var genericArguments = typeToConvert.GetGenericArguments();
return genericArguments[0] == typeof(TKey) && genericArguments[1] == typeof(TValue);
}
return false;
}
public override Dictionary<TKey, TValue>? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
if (reader.TokenType != JsonTokenType.StartArray)
{
throw new JsonException("Expected the JSON object to start with an array.");
}
var keyPairConverter = (JsonConverter<KeyValuePair<TKey, TValue>>)options.GetConverter(typeof(KeyValuePair<TKey, TValue>));
var dictionary = new Dictionary<TKey, TValue>();
while (reader.Read())
{
if (reader.TokenType == JsonTokenType.EndArray)
{
return dictionary;
}
var pair = keyPairConverter.Read(ref reader, typeof(KeyValuePair<TKey, TValue>), options);
if (pair.Key is null)
{
throw new JsonException("Failed to read the key-value pair from JSON.");
}
dictionary.Add(pair.Key, pair.Value);
}
throw new JsonException("Failed to read the JSON object.");
}
public override void Write(Utf8JsonWriter writer, Dictionary<TKey, TValue> value, JsonSerializerOptions options)
{
writer.WriteStartArray();
var keyPairConverter = (JsonConverter<KeyValuePair<TKey, TValue>>)options.GetConverter(typeof(KeyValuePair<TKey, TValue>));
foreach (var pair in value)
{
keyPairConverter.Write(writer, pair, options);
}
writer.WriteEndArray();
}
}