read

This is a built upon a complete idea my buddy Josh Newman came up with. We found it very hard to find any documentation or complete ideas for server-side pagination that handled nicely with any application layer. It’s really an easy concept.. we needed three things: total amount of records, page size, and the page number. We will leave the responsibility of handling the little bits of math for the application to send up to the request. The API should continue to be dumb and predictable.

To reduce the transactions on the database we used EntityFramework Extended to Future()` our queries so they get called in one transactions rather than two. This is not required but will help with the load.

In order to return a set of results and the total amount of records for pagination we will need to return a KeyValuePair<int, List<WhateverReturnModel>> from our data access methods.

Our API will return a result set like normal and a response header of x-paging-total with the total amount of records so we can start paging!

#Step One: Create a pagination request model

public class PagedRequest
{
   private int? _pageNumber;
   private int? _pageSize;
   private int? _pageSkip;

   public int PageNumber
   {
       get { return this._pageNumber ?? 1; }
       set { this._pageNumber = value; }
   }

   public int PageSize
   {
       get { return this._pageSize ?? 15; }
       set { this._pageSize = value; }
   }
}

#Step Two: Setup PagedResult return method

protected KeyValuePair<int, List<T>> PagedResult<T>(int count, List<T> list)
  {
      return new KeyValuePair<int, List<T>>(count, list);
  }

#Step Three: Setup the API endpoint return method

protected HttpResponseMessage OkPaged<T>(KeyValuePair<int, List<T>> content)
  var response = new HttpResponseMessage(HttpStatusCode.OK)
  {
      Content = new ObjectContent<Object>(content.Value, this.GetConfiguration().Formatters.JsonFormatter)
  };

  response.Headers.Add("x-paging-total", content.Key.ToString());

  return response;
}

#Step Four: Write your method We’re using repository classes to handle our accessing of data

this.PageSkip is a helper method. You can replace this with: (pageNumber - 1) * pageSize

public KeyValuePair<int, List<WhateverModel>> DoSomething([FromUri] PagedRequest paged) {
    var records = yourContext.YourTable.Where(t => true);

    var count = records.FutureCount() // this will not execute right away.. only when it is finally called

    var data = yourContext.YourTable
        .Where(t => t.Something)
        .OrderBy(i => i.Anything)
        .Skip(this.PageSkip(paged.PageNumber, paged.PageSize))
        .Take(paged.PageSize)
        .Future() // again this will not execute right away

    return this.PagedResult(count, data.ToList()); // now both queries will execute in one call
}

#Step Five: Setup your API endpoint

public HttpResponseMessage DoAnotherThing() {
    var test = new WhateverClass.DoSomething();
    return this.Paged(test);
}

That’s it. If you were to use Postman and hit that API endpoint you would get a result set of 15 records and a response header called x-paging-total with the amount of records available to page.

Please tweet me if you have any questions! Good luck.

Blog Logo

Taylor Jones


Published

Image

taylorqj

A collection of software development, thoughts, and vices.

Back to Overview