Custom Json Serialization of class

There are two different approaches for your problem.

You should choose the first one if you are going to change your classes more often because the first approach prevents that you forget to serialize a newly added property. Furthermore it is much more reusable if you want to add another classes you want to be serialized the same way.

If you have only these two classes and it’s most likely that they’re not going to change you can choose the second approach to keep your solution simple.

1. Use a custom converter to select all int properties

The first approach is to use a custom JsonConverter which serializes a class or struct by only including properties which have type int. The code might look like this:

class IntPropertyConverter : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        // this converter can be applied to any type
        return true;
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        // we currently support only writing of JSON
        throw new NotImplementedException();
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        if (value == null)
        {
            serializer.Serialize(writer, null);
            return;
        }

        // find all properties with type 'int'
        var properties = value.GetType().GetProperties().Where(p => p.PropertyType == typeof(int));

        writer.WriteStartObject();

        foreach (var property in properties)
        {
            // write property name
            writer.WritePropertyName(property.Name);
            // let the serializer serialize the value itself
            // (so this converter will work with any other type, not just int)
            serializer.Serialize(writer, property.GetValue(value, null));
        }

        writer.WriteEndObject();
    }
}

Then you have to decorate your class with a JsonConverterAttribute:

[JsonConverter(typeof(IntPropertyConverter))]
public class UrlStats
{
    // ...
}

Disclaimer: This code has been tested only very roughly.


2. Choose properties individually

The second solution looks a bit simpler: You can use the JsonIgnoreAttribute to decorate the attributes you want to exclude for serialization. Alternatively you can switch from “blacklisting” to “whitelisting” by explicitly including the attributes you want to serialize. Here is a bit of sample code:

Blacklisting: (I’ve reordered the properties for a better overview)

[JsonObject(MemberSerialization.OptOut)] // this is default and can be omitted
public class UrlStats
{
    [JsonIgnore] public string URL { get; set; }
    [JsonIgnore] public List<Stats> TotalPages { get; set; }
    [JsonIgnore] public List<Stats> TotalTitles { get; set; }
    [JsonIgnore] public List<Stats> DuplicateTitles { get; set; }
    [JsonIgnore] public List<Stats> OverlengthTitles { get; set; }

    public int TotalPagesFound { get; set; }
    public int TotalTitleTags { get; set; }
    public int NoDuplicateTitleTags { get; set; }
    public int NoOverlengthTitleTags { get; set; }
}

Whitelisting: (also reordered)

[JsonObject(MemberSerialization.OptIn)] // this is important!
public class UrlStats
{
    public string URL { get; set; }
    public List<Stats> TotalPages { get; set; }
    public List<Stats> TotalTitles { get; set; }
    public List<Stats> DuplicateTitles { get; set; }
    public List<Stats> OverlengthTitles { get; set; }

    [JsonProperty] public int TotalPagesFound { get; set; }
    [JsonProperty] public int TotalTitleTags { get; set; }
    [JsonProperty] public int NoDuplicateTitleTags { get; set; }
    [JsonProperty] public int NoOverlengthTitleTags { get; set; }
}

Leave a Comment