Sheinar
Sheinar

Reputation: 402

Serialize IEnumerable<IDictionary<string, object>> doesn't work with DefaultNamingStrategy

By default I use CamelCasePropertyNamesContractResolver in my project for serialize to json. But I want to change this strategy for one property.

public class ViewTable
{
    public int Id { get; set; }

    [JsonProperty(NamingStrategyType = typeof(DefaultNamingStrategy), ItemTypeNameHandling = TypeNameHandling.None, TypeNameHandling = TypeNameHandling.None)]
    public IEnumerable<IDictionary<string, object>> Rows { get; set; }
}

So when I serialize this object I expect to get such json:

"result": {
    "id": 15,
    "rows": [
      {
        "SessionData_Department": "",
        "SystemData_SerialNumber": "1"
      }
    ]
}

But I got:

"result": {
    "id": 15,
    "Rows": [   //There must be a lowercase!!!
      {
        "sessionData_Department": "", //There must be a uppercase!!!
        "systemData_SerialNumber": "1"
      }
    ]
}

I have such json settings in my project:

    var settings = GlobalConfiguration.Configuration.Formatters.JsonFormatter.SerializerSettings;
    settings.Formatting = Formatting.Indented;
    settings.ContractResolver = new CamelCasePropertyNamesContractResolver();
    settings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
    settings.TypeNameHandling = TypeNameHandling.Auto;

How can I tell json serializer use DefaultNamingStrategy for IDictionary?

Upvotes: 1

Views: 250

Answers (2)

AlbertK
AlbertK

Reputation: 13167

I'm not sure that there is a setting from out-of-the box. But you can do it by extending JsonConverter and using DefaultContractResolver:

public class RowsConverter : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        throw new NotImplementedException();
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        throw new NotImplementedException();
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        var settings = new JsonSerializerSettings()
        {
            ContractResolver = new DefaultContractResolver()
        };
        writer.WriteRawValue(JsonConvert.SerializeObject(value, settings));
    }
}

Then change Rows property to:

[JsonProperty(ItemConverterType = typeof(RowsConverter))]
public IEnumerable<IDictionary<string, object>> Rows { get; set; }

Upvotes: 1

FaizanHussainRabbani
FaizanHussainRabbani

Reputation: 3439

You will have to extend DefaultNamingStrategy:

public class CamelCaseDictionaryKeyNamingStrategy : DefaultNamingStrategy
{
    public CamelCaseDictionaryKeyNamingStrategy() : base() { this.ProcessDictionaryKeys = true; }

    public override string GetDictionaryKey(string key)
    {
        if (ProcessDictionaryKeys && !string.IsNullOrEmpty(key))
        {
            if (char.ToUpperInvariant(key[0]) != key[0])
            {
                var builder = new StringBuilder(key) { [0] = char.ToUpperInvariant(key[0]) };
                return builder.ToString();
            }
        }
        return key;
    }
}

Then use it like:

IDictionary<string, object> idict = new Dictionary<string, object>();

idict.Add("sessionData_Department", "1");
idict.Add("systemData_SerialNumber", "1");

IEnumerable<IDictionary<string, object>> row = new List<IDictionary<string, object>> { idict };


var val = new ViewTable
{
    Id = 15,
    Rows = row
};
var cc = new CamelCasePropertyNamesContractResolver
{
    NamingStrategy = new CamelCaseDictionaryKeyNamingStrategy()
};


JsonSerializerSettings config = new JsonSerializerSettings
{
    Formatting = Formatting.Indented,
    ContractResolver = cc,
    ReferenceLoopHandling = ReferenceLoopHandling.Ignore,
    TypeNameHandling = TypeNameHandling.Auto
};
string js = JsonConvert.SerializeObject(val, config);

Output:

enter image description here

I have updated Rows to:

public class ViewTable
{
    public int Id { get; set; }

    [JsonProperty(PropertyName = "rows", NamingStrategyType = typeof(DefaultNamingStrategy), ItemTypeNameHandling = TypeNameHandling.None, TypeNameHandling = TypeNameHandling.None)]
    public IEnumerable<IDictionary<string, object>> Rows { get; set; }
}

Upvotes: 0

Related Questions