Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I get json.net to serialize members of a class deriving from List<T>?

I created a class PagedResult<T> : List<T> that contains a few added members in order to work with one of our components. However, when I run json deserializer, it only serializes the list. If I markup the derived class with [JsonObject] and [JsonProperty] then it'll only serialize the members of the derived class and not the list. How do I get both?

like image 873
Sinaesthetic Avatar asked Jan 21 '14 17:01

Sinaesthetic


People also ask

Can JSON serialize a list?

Can JSON serialize a list? Json.NET has excellent support for serializing and deserializing collections of objects. To serialize a collection - a generic list, array, dictionary, or your own custom collection - simply call the serializer with the object you want to get JSON for.

How do you serialize JSON?

NET objects as JSON (serialize) To write JSON to a string or to a file, call the JsonSerializer. Serialize method. The JSON output is minified (whitespace, indentation, and new-line characters are removed) by default.

How do you serialize a JSON class in Python?

Use toJSON() Method to make class JSON serializable So we don't need to write custom JSONEncoder. This new toJSON() serializer method will return the JSON representation of the Object. i.e., It will convert custom Python Object to JSON string.

Can you serialize a list?

A List can be serialized—here we serialize (to a file) a List of objects.


1 Answers

By default, Json.Net will treat any class that implements IEnumerable as an array. You can override this behavior by decorating the class with a [JsonObject] attribute, but then only the object properties will get serialized, as you have seen. The list itself will not get serialized because it is not exposed via a public property (rather, it is exposed via the GetEnumerator() method).

If you want both, you can either do as @Konrad has suggested and provide a public property on your derived class to expose the list, or you can write a custom JsonConverter to serialize the whole thing as you see fit. An example of the latter approach follows.

Assuming that your PagedResult<T> class looks something like this:

class PagedResult<T> : List<T>
{
    public int PageSize { get; set; }
    public int PageIndex { get; set; }
    public int TotalItems { get; set; }
    public int TotalPages { get; set; }
}

You can make a converter for it like this:

class PagedResultConverter<T> : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        return (objectType == typeof(PagedResult<T>));
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        PagedResult<T> result = (PagedResult<T>)value;
        JObject jo = new JObject();
        jo.Add("PageSize", result.PageSize);
        jo.Add("PageIndex", result.PageIndex);
        jo.Add("TotalItems", result.TotalItems);
        jo.Add("TotalPages", result.TotalPages);
        jo.Add("Items", JArray.FromObject(result.ToArray(), serializer));
        jo.WriteTo(writer);
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        JObject jo = JObject.Load(reader);
        PagedResult<T> result = new PagedResult<T>();
        result.PageSize = (int)jo["PageSize"];
        result.PageIndex = (int)jo["PageIndex"];
        result.TotalItems = (int)jo["TotalItems"];
        result.TotalPages = (int)jo["TotalPages"];
        result.AddRange(jo["Items"].ToObject<T[]>(serializer));
        return result;
    }
}

(Notice also that the [JsonObject] and [JsonProperty] attributes are not required with this approach, because the knowledge of what to serialize is encapsulated into the converter class.)

Here is a demo showing the converter in action:

class Program
{
    static void Main(string[] args)
    {
        PagedResult<string> result = new PagedResult<string> { "foo", "bar", "baz" };
        result.PageIndex = 0;
        result.PageSize = 10;
        result.TotalItems = 3;
        result.TotalPages = 1;

        JsonSerializerSettings settings = new JsonSerializerSettings();
        settings.Converters.Add(new PagedResultConverter<string>());
        settings.Formatting = Formatting.Indented;

        string json = JsonConvert.SerializeObject(result, settings);
        Console.WriteLine(json);
    }
}

Output:

{
  "PageSize": 10,
  "PageIndex": 0,
  "TotalItems": 3,
  "TotalPages": 1,
  "Items": [
    "foo",
    "bar",
    "baz"
  ]
}
like image 90
Brian Rogers Avatar answered Sep 20 '22 17:09

Brian Rogers