简体   繁体   中英

Json.NET Case-insensitive Property Deserialization

Json.NET lists "Case-insensitive property deserialization" as one of the advertised features. I have read that an attempt will first be made to match the case of the property specified and if a match is not found a case-insensitive search is performed. This does not appear to be the default behavior however. See the following example:

var result =
    JsonConvert.DeserializeObject<KeyValuePair<int, string>>(
        "{key: 123, value: \"test value\"}"
    );

// result is equal to: default(KeyValuePair<int, string>)

If the JSON string is altered to match the case of the properties ("Key" and "Value" vs "key" and "value") then all is well:

var result =
    JsonConvert.DeserializeObject<KeyValuePair<int, string>>(
        "{Key: 123, Value: \"test value\"}"
    );

// result is equal to: new KeyValuePair<int, string>(123, "test value")

Is there a way to perform to case-insensitive deserialization?

That's a bug.

Case-insensitive property deserialization refers to Json.NET being able to map a JSON property with the name "Key" to either a .NET class's "Key" or "key" member.

The bug is KeyValuePair requires its own JsonConverter but misses out of the case insensitive mapping.

https://github.com/JamesNK/Newtonsoft.Json/blob/fe200fbaeb5bad3852812db1e964473e1f881d93/Src/Newtonsoft.Json/Converters/KeyValuePairConverter.cs

Use that as a base and add the lower case "key" and "value" to the case statement when reading JSON.

One efficient way I found was to use GetValue with StringComparer parameter.

So for example,

JObject contact;
String strName = contact.GetValue('Name');

You are trying to access 'Name' property as case insensitive, you can use

JObject contact;
String strName = contact.GetValue("ObjType", StringComparison.InvariantCultureIgnoreCase);

You can use a custom Contract resolver on incoming property name, which you can change the incoming property into a preferable format that will matches your C# object class property format. I have made three custom contract resolver, that will change the incoming property name into Title case / Lower case / upper case:

public class TitleCaseContractResolver : DefaultContractResolver
{
    protected override string ResolvePropertyName(string propertyName)
    {
        //Change the incoming property name into Title case
        var name = string.Concat(propertyName[0].ToString().ToUpper(), propertyName.Substring(1).ToLower());
        return base.ResolvePropertyName(name);
    }
}

public class LowerCaseContractResolver : DefaultContractResolver
{
    protected override string ResolvePropertyName(string propertyName)
    {
        //Change the incoming property name into Lower case
        return base.ResolvePropertyName(propertyName.ToLower());
    }
}

public class UpperCaseContractResolver : DefaultContractResolver
{
    protected override string ResolvePropertyName(string propertyName)
    {
        //Change the incoming property name into Upper case
        return base.ResolvePropertyName(propertyName.ToUpper());
    }
}

Then create a new JsonSerializerSetting object and put your custom contract resolver into the property ContractResolver. Then add the JsonSerializerSetting object into the second parameter in the JsonConvert.DeserializeObject(jsonString, jsonSerializerSetting)

        var serializerSetting = new JsonSerializerSettings()
        {
            ContractResolver = new TitleCaseContractResolver()
        };
        var result = JsonConvert.DeserializeObject<YourType>(jsonString, serializerSetting);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM