0

I have the following use case, I want to serialize/deserialize my IPagedList of T using JSON.net (Newtonsoft.Json). This seems not to be working. It does not serialize everything, only the items (or with my own ContractResolver, the object with empty properties). I am using the X.PagedList nuget.

A test case:

var list = new List<int>(Enumerable.Range(1, 1000));
var paged = list.AsQueryable().ToPagedList(3, 10);


var json = JsonConvert.SerializeObject(paged); (output: [21,22,23,24,25,26,27,28,29,30])
var obj = JsonConvert.DeserializeObject<PagedList<int>>(json);

When I extend the DefaultContractResolver and override the CreateContract method, it deserializes to the IPagedList object but with no properties filled, and also no items.. I tried to override the CreateProperties but that didn't work as I expected.

protected override JsonContract CreateContract(Type objectType)
{
    if (typeof(IPagedList).IsAssignableFrom(objectType))
    {
        return CreateObjectContract(objectType);
    }
   return base.CreateContract(objectType);
}

So how can I successfully serialize/deserialize this class?

Ronald Meijboom
  • 1,534
  • 3
  • 17
  • 37
  • Have you confirmed that `paged` contains data via debugging? – Mark Atkinson Oct 18 '16 at 07:08
  • Yes it contains all the data I expect, IsLastPage, PageSize, HasNextPage etc. are all set. – Ronald Meijboom Oct 18 '16 at 07:13
  • It seems that the PagedList github repo is no longer maintained. It might be best to use the built in functions as per my suggestion below, where there is less chance of getting unexpected behavior. – Mark Atkinson Oct 18 '16 at 07:15
  • Possible duplicate: [Serialize custom properties on a class that implements IEnumerable](https://stackoverflow.com/questions/12129774/serialize-custom-properties-on-a-class-that-implements-ienumerable). – dbc Oct 18 '16 at 07:20
  • I am using x.PagedList, which is a fork of the PagedList and seems to be maintained. But the reason I want to use this nuget is that it makes it easy quickly create grid pages. – Ronald Meijboom Oct 18 '16 at 07:20
  • @dbc, seems to be correctly serializing the data, but deserilization does not work. Hope I can fix that. – Ronald Meijboom Oct 18 '16 at 08:22

2 Answers2

2

When you serialize IPagedList it serializes the contents/data of the requested page and not the meta data (i.e. FirstItemOnPage, HasNextPage, etc. properties) will be lost. So to overcome this issue you can create an anonymous class like the following which will have two properties

  • items holds current page contents
  • metaData holds super list metadata.

So change first part of your code to:

 var list = new List<int>(Enumerable.Range(1, 1000));
 var paged = list.AsQueryable().ToPagedList(3, 10);
 var pagedWithMetaData = new { items = paged, metaData = paged.GetMetaData() };

then serialize that object

//Serialize 
var json = JsonConvert.SerializeObject(pagedWithMetaData);

this will generate a sub-list with the metaData for your example it is like following:

{"items":[21,22,23,24,25,26,27,28,29,30],"metaData":{"PageCount":100,"TotalItemCount":1000,"PageNumber":3,"PageSize":10,"HasPreviousPage":true,"HasNextPage":true,"IsFirstPage":false,"IsLastPage":false,"FirstItemOnPage":21,"LastItemOnPage":30}}

now to deserialize you need to create three classes:

  • PaginationMetaData class to encapsulate the meta-data so when we deserialize the sub list it's metadata will be deserialzed to this type.

  • PaginationEntityClass where T : class class to encapsulate the anonymous class so when we deserialize the sub list its content and metadata will be deserialzed to this type.

  • PaginationEntityStruct where T : struct same as PaginationEntityClass but T here is a struct so it hold struct types instead of classes like your case for int.

So these three classes will as follow:

public class PaginationMetaData
{
   public int FirstItemOnPage { get; set; }
   public bool HasNextPage { get; set; }
   public bool HasPreviousPage { get; set; }
   public bool IsFirstPage { get; set; }
   public bool IsLastPage { get; set; }
   public int LastItemOnPage { get; set; }
   public int PageCount { get; set; }
   public int PageNumber { get; set; }
   public int PageSize { get; set; }
   public int TotalItemCount { get; set; }
}

public class PaginationEntityClass<T> where T : class
{
   public PaginationEntityClass()
   {
      Items = new List<T>();
   }
   public IEnumerable<T> Items { get; set; }
   public PaginationMetaData MetaData { get; set; }
}

public class PaginationEntityStruct<T> where T : struct
{
   public PaginationEntityStruct()
   {
      Items = new List<T>();
   }
   public IEnumerable<T> Items { get; set; }
   public PaginationMetaData MetaData { get; set; }
}

Now to deserialize you need just to deserialize to PaginationEntityStruct of integers then use the second constructor overload of StaticPagedList class (class comes with PagedList package) to recreate the subclass with metadata.

//Deserialize
var result = JsonConvert.DeserializeObject<PaginationEntityStruct<int>>(json);
StaticPagedList<int> lst = new StaticPagedList<int>(
                    result.Items, 
                    result.MetaData.PageNumber, 
                    result.MetaData.PageSize, 
                    result.MetaData.TotalItemCount);
0

Perhaps you could consider using the built in LINQ functions .skip() & .take().

As per my comment above it seems the repo for PagedList hasn't been maintained in a long while. Before knocking your head against the wall perhaps try the above built in functions.

PagedList github repo.

Samples for Skip & Take

Mark Atkinson
  • 458
  • 8
  • 14