Runtime: [System.Text.Json] DictionaryKeyPolicy for nested Dictionary does not work as expected when been set to JsonNamingPolicy.CamelCase

Created on 6 Feb 2020  路  5Comments  路  Source: dotnet/runtime

When I use System.Text.Json.JsonSerializer to serialize nested dictionary,
I found the key of the first level of the dictionary not set to camel case when I set DictionaryKeyPolicy to JsonNamingPolicy.CamelCase.

Any workaround?

System.Text.Json v4.7.0
.Net Core v3.1.1

Sample Code

```c#
var firstLevelDic = new Dictionary>();
var secondLevelDic = new Dictionary {
{ "FOO bar", "23" },
{ "FOObar", "23" },
{ "FooBar", "23" }
};

firstLevelDic.Add("FOO bar", secondLevelDic);
firstLevelDic.Add("FOObar", secondLevelDic);
firstLevelDic.Add("FooBar", secondLevelDic);

var options = new JsonSerializerOptions();
options.DictionaryKeyPolicy = JsonNamingPolicy.CamelCase;
options.WriteIndented = true;
var json = JsonSerializer.Serialize(firstLevelDic, options);

generated json
```json
{
  "FOO bar": {
    "foo bar": "23",
    "foObar": "23",
    "fooBar": "23"
  },
  "FOObar": {
    "foo bar": "23",
    "foObar": "23",
    "fooBar": "23"
  },
  "FooBar": {
    "foo bar": "23",
    "foObar": "23",
    "fooBar": "23"
  }
}

I tried Newtonsoft.Json, which works as expected
Sample Code
```C#
var firstLevelDic = new Dictionary>();
var secondLevelDic = new Dictionary {
{ "FOO bar", "23" },
{ "FOObar", "23" },
{ "FooBar", "23" }
};

firstLevelDic.Add("FOO bar", secondLevelDic);
firstLevelDic.Add("FOObar", secondLevelDic);
firstLevelDic.Add("FooBar", secondLevelDic);

DefaultContractResolver contractResolver = new DefaultContractResolver
{
NamingStrategy = new CamelCaseNamingStrategy()
{
ProcessDictionaryKeys = true
}
};

var settings = new JsonSerializerSettings
{
ContractResolver = contractResolver,
Formatting = Formatting.Indented
};

var json = Newtonsoft.Json.JsonConvert.SerializeObject(firstLevelDic, settings);

Result
```json
{
  "foo bar": {
    "foo bar": "23",
    "foObar": "23",
    "fooBar": "23"
  },
  "foObar": {
    "foo bar": "23",
    "foObar": "23",
    "fooBar": "23"
  },
  "fooBar": {
    "foo bar": "23",
    "foObar": "23",
    "fooBar": "23"
  }
}
area-System.Text.Json bug

Most helpful comment

This also applies if the dictionary values are an array of strings, Dictionary<string, string[]>, which is the case for the ValidationProblemDetails.Errors dictionary in ASP.NET core.

Here is an example that reproduces the problem.

var result = JsonSerializer.Serialize(new
{
    StringString = new Dictionary<string, string>
    {
        ["Key"] = "Value"
    },
    StringArray = new Dictionary<string, string[]>
    {
        ["Key"] = new []{ "Value" }
    }
}, options: new JsonSerializerOptions
{
    PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
    DictionaryKeyPolicy = JsonNamingPolicy.CamelCase,
    WriteIndented = true
});

Console.WriteLine(result);
/*
{
  "stringString": {
    "key": "Value"
  },
  "stringArray": {
    "Key": [
      "Value"
    ]
  }
}
*/

What is the code for the workaround?

All 5 comments

I am experiencing this bug also and would like a work-around. Perhaps writing my own converter that overrides an existing one?

A workaround could be using set options.DictionaryKeyPolicy to JsonNamingPolicy.CamelCase
and when creating dictionary use options.DictionaryKeyPolicy.ConvertName(featureName). That should convert key according to selected policy. If DictionaryKeyPolicy isn't set calling convert name will throw an exception.

This bug has been fixed for 5.0. The workaround is to implement custom dictionary converters as required. The policy can be obtained from options.DicitonaryKeyPolicy.

This also applies if the dictionary values are an array of strings, Dictionary<string, string[]>, which is the case for the ValidationProblemDetails.Errors dictionary in ASP.NET core.

Here is an example that reproduces the problem.

var result = JsonSerializer.Serialize(new
{
    StringString = new Dictionary<string, string>
    {
        ["Key"] = "Value"
    },
    StringArray = new Dictionary<string, string[]>
    {
        ["Key"] = new []{ "Value" }
    }
}, options: new JsonSerializerOptions
{
    PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
    DictionaryKeyPolicy = JsonNamingPolicy.CamelCase,
    WriteIndented = true
});

Console.WriteLine(result);
/*
{
  "stringString": {
    "key": "Value"
  },
  "stringArray": {
    "Key": [
      "Value"
    ]
  }
}
*/

What is the code for the workaround?

This also applies if the dictionary values are an array of strings, Dictionary<string, string[]>, which is the case for the ValidationProblemDetails.Errors dictionary in ASP.NET core.

Here is an example that reproduces the problem.

var result = JsonSerializer.Serialize(new
{
    StringString = new Dictionary<string, string>
    {
        ["Key"] = "Value"
    },
    StringArray = new Dictionary<string, string[]>
    {
        ["Key"] = new []{ "Value" }
    }
}, options: new JsonSerializerOptions
{
    PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
    DictionaryKeyPolicy = JsonNamingPolicy.CamelCase,
    WriteIndented = true
});

Console.WriteLine(result);
/*
{
  "stringString": {
    "key": "Value"
  },
  "stringArray": {
    "Key": [
      "Value"
    ]
  }
}
*/

What is the code for the workaround?

We have encountered this exact issue as well. Fortunately it was only a few areas of our code base that were impacted, but it would be nice if there was a solution to this.

Was this page helpful?
0 / 5 - 0 ratings