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?

- 125,747
- 31
- 299
- 300

- 11,426
- 28
- 107
- 176
3 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"
]
}

- 125,747
- 31
- 299
- 300
-
"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" My experience is slightly different: the OP derived from `List
`, whereas I have implemented `IList – Bob Sammers Nov 30 '18 at 16:17`, once in a base class, once in the serialized object directly to get my implementation of `IEnumerable`. In both cases, I get the added properties and collection objects as soon as I decorate with `[JsonObject]`. Could be down to a newer version of Json.NET (12.0.0).
The simplest workaround that comes to my mind is to expose internal elements as another property of derived class:
[JsonProperty]
public IEnumerable<T> Elements {
get
{
return this;
}
}

- 16,563
- 2
- 36
- 58
-
I get the error `Self referencing loop detected for property 'Elements' with type "T" `error, while trying this option. – Abhinav Galodha Aug 02 '18 at 19:09
If you don't want to write custom JsonConverter
or use JSON attributes (JsonObjectAttribute) then you could simply use extension methods:
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; }
}
public static class Extensions
{
public static string ToPagedJson<T>(this PagedResult<T> pagedResult)
{
return JsonConvert.SerializeObject(new
{
PageSize = pagedResult.PageSize,
PageIndex = pagedResult.PageIndex,
TotalItems = pagedResult.TotalItems,
TotalPages = pagedResult.TotalPages
Items = pagedResult
});
}
}

- 161
- 5