9

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}");

enter image description here

enter image description here

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.

alamoot
  • 1,966
  • 7
  • 30
  • 50
Ben
  • 538
  • 1
  • 9
  • 24

2 Answers2

9

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.

Andy
  • 12,859
  • 5
  • 41
  • 56
-1

There seems to be an option to achieve this.

JsonSerializerOptions options = new JsonSerializerOptions
{
       PropertyNameCaseInsensitive = true
};

await JsonSerializer.DeserializeAsync<...>(stream, options)

JsonSerializerOptions.PropertyNameCaseInsensitive Property

leikür
  • 109
  • 1
  • 4
  • This will make the serializer agnostic to the case of property names in the JSON. For example, it could deserialize "SoMeNaMe" into a property on an object called `SomeName` without any additional property naming convention. However, if it deserializes a dictionary, it will not make lookups on that dictionary case insensitive. – steve16351 Jun 15 '23 at 08:06