In my recent project, we have an Address class that is complex and has many properties in it. This class also has an ID property. We have a requirement where we need to replace this object with the ID string of the address wherever the address is used in any object when serialising to JSON. This will also need to be able to deserialise to the complex Address object from the ID string of the address.
Let’s say the Address class looks like this
public class Address
{
public string Id { get; set; }
public string Type { get; set; }
public string Street { get; set; }
//... Many other properties
}
And it’s used in User class
public class User
{
public string Id { get; set; }
public Address BillingAddress { get; set; }
public Address DeliveryAddress { get; set; }
}
When serialising the User object to JSON, instead of
{
"Id": "ABC123",
"BillingAddress": {
"Id": "1",
"Type": "Street Address",
"Street": "55 Market St"
},
"DeliveryAddress": {
"Id": "2",
"Type": "Postal Address",
"Street": "180 Pitt St"
}
}
We want it to be this
{
"Id": "ABC123",
"BillingAddress": "1",
"DeliveryAddress": "2"
}
Our solution is to add a custom JSON converter for Address class
public class AddressConverter : JsonConverter
{
private readonly IReadOnlyList<Address> _addresses;
public AddressConverter(IReadOnlyList<Address> addresses = new List<Address>())
{
_addresses = addresses;
}
public override bool CanConvert(Type objectType)
{
return objectType == typeof(Address);
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
var address = (Address)value;
writer.WriteValue(address.Id);
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
var addressId = reader.Value?.ToString() ?? string.Empty;
var addressToConvert = _addresses.FirstOrDefault(x => x.Id == addressId);
if (addressToConvert == null)
throw new Exception($"No address found matching the ID {addressId}");
return addressToConvert;
}
}
To use this converter, you can add it to the JSON serialiser settings
public string SerialiseUser(User user)
{
return JsonConvert.SerializeObject(user, Formatting.Indented, new JsonSerializerSettings
{
Converters = new List<JsonConverter>
{
new AddressTypeConverter()
}
})
}
public User DeserialiseUser(string userJson, IReadOnlyList<Address> addresses)
{
return JsonConvert.DeserializeObject<User>(userJson, new JsonSerializerSettings
{
Converters = new List<JsonConverter>
{
new AddressTypeConverter(addresses)
}
})
}