I'm trying to deserialize json into an object with a property of type Dictionary<string,string>
. I specify the comprarer for the Dictionary as StringComparer.OrdinalIgnoreCase
.
Here's this class:
class DictionaryTest
{
public Dictionary<string, string> Fields { get; set; }
public DictionaryTest()
{
Fields = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
}
}
But when the deserialization happens, the comparer is changed to the generic one. Hence, I cannot access the keys of my dictionary in a case-insensitive way.
var points = new Dictionary<string, string>
{
{ "James", "9001" },
{ "Jo", "3474" },
{ "Jess", "11926" }
};
var testObj = new DictionaryTest{Fields = points};
var dictionaryJsonText = JsonSerializer.Deserialize<DictionaryTest>(JsonSerializer.Serialize(testObj, options:new JsonSerializerOptions()
{
IgnoreNullValues = true,
WriteIndented = false,
PropertyNamingPolicy = null,
Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping,
DictionaryKeyPolicy = JsonNamingPolicy.CamelCase,
PropertyNameCaseInsensitive = true
}));
string nameJsonText = "", nameJsonText2="";
//Because of the naming policy specified above, the keys are camelCase.
//So keys are james, jo and jess
//I expect to be able to access either james, or James as keys.
dictionaryJsonText?.Fields.TryGetValue("James", out nameJsonText);
dictionaryJsonText?.Fields.TryGetValue("james", out nameJsonText2);
Console.WriteLine($"Name with system.text.json is: {nameJsonText}");
Console.WriteLine($"Name with system.text.json is: {nameJsonText2}");
Console.WriteLine($"Comparer is {dictionaryJsonText?.Fields.Comparer}");
So how can I go about deserializing json into a class like the one below and maintain its case-insesitivity? Any suggestions? I'm using .net5.
And I should mention that this code would work perfectly fine using Newtonsoft
. The comparer will remain as OrdinalIgnoreCase and case-insensitivity is retained.
Currently there isn't a way to do what you want. But, you can implement the functionality yourself.
You could create a custom JsonConverter
for this specific case. For example:
public sealed class CaseInsensitiveDictionaryConverter<TValue>
: JsonConverter<Dictionary<string, TValue>>
{
public override Dictionary<string, TValue> Read(
ref Utf8JsonReader reader,
Type typeToConvert,
JsonSerializerOptions options)
{
var dic = (Dictionary<string, TValue>)JsonSerializer
.Deserialize(ref reader, typeToConvert, options);
return new Dictionary<string, TValue>(
dic, StringComparer.OrdinalIgnoreCase);
}
public override void Write(
Utf8JsonWriter writer,
Dictionary<string, TValue> value,
JsonSerializerOptions options)
{
JsonSerializer.Serialize(
writer, value, value.GetType(), options);
}
}
You can then bind it to the specific property by doing this:
class DictionaryTest
{
[JsonConverter(typeof(CaseInsensitiveDictionaryConverter<string>))]
public Dictionary<string, string> Fields { get; set; }
= new Dictionary<string, string>();
}
And that's it. You can just deserialize as normal:
var json = JsonSerializer.Serialize(new DictionaryTest
{
Fields =
{
{ "One", "Two" },
{ "Three", "Four" }
}
});
var dictionaryJsonText = JsonSerializer.Deserialize<DictionaryTest>(json);
The above example will produce a dictionary with case-insensitive keys.