You can do it using a JsonConverter.
It's useful for example when you consume some data from 3rd party services and they keep changing property names and then going back to previous property names. :D
The following code shows how to deserialize from multiple property names to the same class property decorated with a [JsonProperty(PropertyName = "EnrollmentStatusEffectiveDateStr")]
attribute.
The class MediCalFFSPhysician
is also decorated with the custom JsonConverter: [JsonConverter(typeof(MediCalFFSPhysicianConverter))]
Note that _propertyMappings
dictionary holds the possible property names that should be mapped to the property EnrollmentStatusEffectiveDateStr
:
private readonly Dictionary<string, string> _propertyMappings = new()
{
{"Enrollment_Status_Effective_Dat", "EnrollmentStatusEffectiveDateStr"},
{"Enrollment_Status_Effective_Date", "EnrollmentStatusEffectiveDateStr"},
{"USER_Enrollment_Status_Effectiv", "EnrollmentStatusEffectiveDateStr"}
};
Full code:
// See https://aka.ms/new-console-template for more information
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json.Serialization;
using System.Reflection;
using System.Text.Json;
internal class JSONDeserialization
{
private static void Main(string[] args)
{
var jsonPayload1 = $"{{\"Enrollment_Status_Effective_Dat\":\"2022/10/13 19:00:00+00\"}}";
var jsonPayload2 = $"{{\"Enrollment_Status_Effective_Date\":\"2022-10-13 20:00:00+00\"}}";
var jsonPayload3 = $"{{\"USER_Enrollment_Status_Effectiv\":\"2022-10-13 21:00:00+00\"}}";
var deserialized1 = JsonConvert.DeserializeObject<MediCalFFSPhysician>(jsonPayload1);
var deserialized2 = JsonConvert.DeserializeObject<MediCalFFSPhysician>(jsonPayload2);
var deserialized3 = JsonConvert.DeserializeObject<MediCalFFSPhysician>(jsonPayload3);
Console.WriteLine(deserialized1.Dump());
Console.WriteLine(deserialized2.Dump());
Console.WriteLine(deserialized3.Dump());
Console.ReadKey();
}
}
public class MediCalFFSPhysicianConverter : JsonConverter
{
private readonly Dictionary<string, string> _propertyMappings = new()
{
{"Enrollment_Status_Effective_Dat", "EnrollmentStatusEffectiveDateStr"},
{"Enrollment_Status_Effective_Date", "EnrollmentStatusEffectiveDateStr"},
{"USER_Enrollment_Status_Effectiv", "EnrollmentStatusEffectiveDateStr"}
};
public override bool CanWrite => false;
public override void WriteJson(JsonWriter writer, object value, Newtonsoft.Json.JsonSerializer serializer)
{
throw new NotImplementedException();
}
public override bool CanConvert(Type objectType)
{
return objectType.GetTypeInfo().IsClass;
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, Newtonsoft.Json.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;
}
}
[JsonConverter(typeof(MediCalFFSPhysicianConverter))]
public class MediCalFFSPhysician
{
[JsonProperty(PropertyName = "EnrollmentStatusEffectiveDateStr")]
public string EnrollmentStatusEffectiveDateStr { get; set; }
}
public static class ObjectExtensions
{
public static string Dump(this object obj)
{
try
{
return System.Text.Json.JsonSerializer.Serialize(obj, new JsonSerializerOptions { WriteIndented = true });
}
catch (Exception)
{
return string.Empty;
}
}
}
The output is this:
Adapted from: Deserializing different JSON structures to the same C# class