A server is returning a JSON string value which is a URL query string:
{
"parameters": "key1=value1&key2=value2"
}
I have a property set up to receive this, and convert it into a Dictionary
as part of the deserialisation process:
Property with JsonConverter
attribute:
[JsonConverter(typeof(QueryStringToDictionaryJsonConverter))]
public Dictionary<string, string> Parameters { get; set; }
Converter:
public class QueryStringToDictionaryJsonConverter : JsonConverter<Dictionary<string, string>> {
public override Dictionary<string, string> Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) {
var queryString = reader.GetString();
if (string.IsNullOrEmpty(queryString)) return null;
return QueryHelpers.ParseQuery(queryString).ToDictionary(e => e.Key, e => string.Join(",", e.Value.ToArray()));
}
...
}
This should work.
But it's not even getting to my converter.
From what I can tell, JsonSerializer.DeserializeAsync<T>(myJson)
is seeing that the type of property is a Dictionary
, and so it tries to parse the value as such on its own, and fails (the resulting exception is an 'invalid cast' as it tries to GetEnumerable()
etc). A breakpoint in my converter never even gets hit.
I can get it to work by making the property an object
and then casting to a Dictionary
later where it's used, but that's an ugly solution.
Is there a way to force JsonSerializer.DeserializeAsync<T>(myJson)
to just use my converter, without it trying to be smart on its own?
(I'm using Microsoft's System.Text.Json in .NET Core 3)
OK, so this could be a bug in System.Text.Json
.
Here's the workaround I'm currently using for anyone else needing a solution.
First, I set up two properties for deserialisation, using [JsonPropertyName]
and [JsonIgnore]
:
[JsonPropertyName("parameters"), JsonConverter(typeof(QueryStringToDictionaryJsonConverter))]
public object ParametersObject { get; set; }
[JsonIgnore]
public Dictionary<string, string> Parameters => ParametersObject as Dictionary<string, string>;
And then in the JsonConverter
, I allow object
as the type:
public override bool CanConvert(Type typeToConvert) {
if (typeToConvert == typeof(object)) return true;
return base.CanConvert(typeToConvert);
}
Consumers of my deserialised class just use the Parameters
property, which will continue to work just fine if and when this bug is fixed and I change the class back to how I'd like it.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With