Imagine having the following class
public class Person
{
public int Id {get; set;}
[JsonProperty("first_name")]
public string FirstName {get; set;}
[JsonProperty("last_name")]
public string LastName {get; set;}
}
I have two sources of JSON that I'm currently using to JsonConvert.DeserializeObject<Person>(source)
. This puts me in a pickle. Both sources must have identical property names in order for this to work. For the sake of this exercise, let's assume the followings for source
.
source 1:
{
"id" : 1,
"first_name": "Jon",
"last_name": "Doe"
}
source 2:
{
"id" : 1,
"firstName": "Jon",
"lastName": "Doe"
}
In this scenario, the second source isn't going to get deserialized into the Person
object because the property names don't match.
I'm not sure how to deserialize these two sources to the same object without having the need to create a new object, which I don't want to do.
To solve this using a custom JsonConverter
...
Implement a custom JsonConverter
that defines the field name mappings that can be different ...
public class PersonConverter : JsonConverter
{
private Dictionary<string, string> propertyMappings { get; set; }
public PersonConverter()
{
this.propertyMappings = new Dictionary<string, string>
{
{"firstName","first_name"},
{"lastName","last_name"},
};
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
throw new NotImplementedException();
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
object instance = Activator.CreateInstance(objectType);
var props = objectType.GetTypeInfo().DeclaredProperties.ToList();
JObject jo = JObject.Load(reader);
foreach (JProperty jp in jo.Properties())
{
if (!propertyMappings.TryGetValue(jp.Name, out var name))
name = jp.Name;
PropertyInfo prop = props.FirstOrDefault(pi =>
pi.CanWrite && pi.GetCustomAttribute<JsonPropertyAttribute>().PropertyName == name);
prop?.SetValue(instance, jp.Value.ToObject(prop.PropertyType, serializer));
}
return instance;
}
public override bool CanConvert(Type objectType)
{
return objectType.GetTypeInfo().IsClass;
}
public override bool CanWrite => false;
}
Add the JsonConverter
attribute on your object class, so your custom converter is used during deserializtion...
[JsonConverter(typeof(PersonConverter))]
public class RootObject
{
[JsonProperty("first_name")]
public string FirstName{ get; set; }
[JsonProperty("last_name")]
public string LastName { get; set; }
}
To use the custom converter...
string json_first_name = "{\"id\" : 1,\"first_name\": \"Jon\",\"last_name\": \"Doe\"}";
string json_firstname = "{\"id\" : 1,\"firstName\": \"Jon\",\"lastName\": \"Doe\"}";
var objFirst_Name = JsonConvert.DeserializeObject<RootObject>(json_first_name);
var objFirstName = JsonConvert.DeserializeObject<RootObject>(json_firstname);