Hello. When I try to serialize Dictionary with integer key, it throw System.NotSupportedException.
I think it makes sense to support Json serialization which Dictionary has ToString-able key. for example, when we run ToString for int or boolean, it return "123" or "true". I think that key is ToString-able key.
System.Text.Json Nuget Version : 4.6.0-preview8.19405.3
var dictionary = new Dictionary<int, string>
{
[5] = "five"
};
JsonSerializer.Serialize(dictionary);
"{"5": "five"}"
Error System.NotSupportedException Thrown
Actually, there is compatibility problem when I change Newtonsoft.Json to System.Text.Json. They return string as I expected. I think System.Text.Json don't have to be compatible but... you know.
Related: https://github.com/dotnet/corefx/issues/40120
Both "not supported exception" errors are limitations within the built-in serializer and is by design (at least for what is shipping in 3.0).
When serializing, only Dictionary
is supported today (i.e. TKeys that are string). Your dictionary is of which isn't supported.
https://github.com/dotnet/corefx/issues/40120#issuecomment-519648806
As @Gnbrkm41 mentioned, this is a known limitation and is a duplicate of https://github.com/dotnet/corefx/issues/40120
@namse, I have moved your comment to the existing issue. Please try the converter approach and let us know if your issue persists.
@ahsonkhan You mean, the converter approach is using JsonConverter to solve this problem, right?
@namse yes, Please take a look at https://github.com/dotnet/corefx/issues/36639#issue-429928740 for examples (of inheriting from JsonConverter & using it)
@ahsonkhan You mean,
the converter approachis using JsonConverter to solve this problem, right?
Yes.
The workaround for this is to use a custom converter that implements JsonConverter<T> where T is Dictionary<int, T>.
See https://github.com/dotnet/corefx/issues/36639#issue-429928740 for some examples (and also look at the built-in converters in source and ones in tests):
https://github.com/dotnet/corefx/tree/master/src/System.Text.Json/src/System/Text/Json/Serialization/Converters
https://github.com/dotnet/corefx/blob/master/src/System.Text.Json/tests/Serialization/CustomConverterTests.Dictionary.cs
I made JsonConverter which support Non-string Key Dictionary. Only serialization.
It can handle bool, number, and Enum.
public class NonStringKeyDictionaryJsonConverterFactory : System.Text.Json.Serialization.JsonConverterFactory
{
private static Type[] ConvertableTypes = new Type[]
{
typeof(bool),
typeof(byte),
typeof(char),
typeof(decimal),
typeof(double),
typeof(float),
typeof(int),
typeof(long),
typeof(sbyte),
typeof(short),
typeof(uint),
typeof(ulong),
typeof(ushort),
};
public static bool CanConvertImpl(Type typeToConvert)
{
if (typeToConvert.IsGenericType
&& typeToConvert.GetGenericTypeDefinition() == typeof(Dictionary<,>))
{
var keyType = typeToConvert.GenericTypeArguments[0];
return keyType.IsEnum || ConvertableTypes.Any(convertableType => keyType == convertableType);
}
var baseType = typeToConvert.BaseType;
if (!(baseType is null))
{
return CanConvertImpl(baseType);
}
return false;
}
public override bool CanConvert(Type typeToConvert)
{
return CanConvertImpl(typeToConvert);
}
public override JsonConverter CreateConverter(Type typeToConvert, JsonSerializerOptions options)
{
var converterType = typeof(NonStringKeyDictionaryJsonConverter<,>)
.MakeGenericType(typeToConvert.GenericTypeArguments[0], typeToConvert.GenericTypeArguments[1]);
var converter = (JsonConverter)Activator.CreateInstance(
converterType,
BindingFlags.Instance | BindingFlags.Public,
binder: null,
new object[] {
//_converterOptions, _namingPolicy
},
culture: null);
return converter;
}
}
public class NonStringKeyDictionaryJsonConverter<TKey, TValue>
: System.Text.Json.Serialization.JsonConverter<Dictionary<TKey, TValue>>
{
public override bool CanConvert(Type typeToConvert)
{
return NonStringKeyDictionaryJsonConverterFactory.CanConvertImpl(typeToConvert);
}
public override Dictionary<TKey, TValue> Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
throw new NotImplementedException();
}
public override void Write(Utf8JsonWriter writer, Dictionary<TKey, TValue> enumKeyDictionary, JsonSerializerOptions options)
{
var stringKeyDictionary = new Dictionary<string, object>(enumKeyDictionary.Count);
foreach (var (key, value) in enumKeyDictionary)
{
var stringKey = key.ToString();
stringKeyDictionary[stringKey] = value;
}
JsonSerializer.Serialize(writer, stringKeyDictionary, options);
}
}
It works, is it right pattern?
It works, is it right pattern?
cc @steveharter, @layomia - can you help verify the converter sample shared by @namse
Why is this not supported ? The key of the dictionary is a string. And its value an object. JsonSerializer.Deserialize<Dictionary<string, Dictionary<VoiceAction, string>>>(VoiceCommands);
Can you share an isolated repro along with the error/behavior you are seeing in your use case? Also, are you running on .NET Core 3.1?
I managed to make it work. I had to include the DictionaryTKeyEnumTValueConverter described here: https://docs.microsoft.com/en-us/dotnet/standard/serialization/system-text-json-converters-how-to#support-dictionary-with-non-string-key
Most helpful comment
@namse yes, Please take a look at https://github.com/dotnet/corefx/issues/36639#issue-429928740 for examples (of inheriting from JsonConverter & using it)