Global Pagination in WebAPI using ActionAttributeFilter

I like pagination, but only when it isn’t forced. In my perspective pagination should be opt-in not opt-out, so to speak.
Pagination should also, be easy to implement and not something we, as developers, should need to implement on a per entity basis.
The usual manual way to do this (also as described by the docs) is adding pageSize and pageNumber as query-parameters on individual actions.

This is fine for smaller things, but not very DRY.
What I ended up doing was to create an ActionFilter.
With an ActionFilter you can “plug” 2 places,

  1. OnActionExecuted – which is before the request hits the method
  2. OnActionExecuting – which is after the request has hit the method.

You can read about actionfilters here

Off to the code

So we need to create an ActionFilter, that will “plug” after the response has been attached to the HttpContext, where we look for specific query-parameters and then filter the response based on the query-parameters given.
Let’s list what we need to do.
1. Create a class that inherits from ActionFilterAttribute.
2. Look for specific query parameters.
3. Filter the response based on the query parameters.

1. Create a class that inherits from ActionFilterAttribute.

easy – we simply add a new class and inherit from ActionFilterAttribute and then override OnActionExecuted.

2. Look for specific query parameters.

Now, how do we get the query parameters? luckily the context object is full of good stuff!
context.Request.RequestUri.Query contains all of our queries and luckily there is a helper class to help us parse the query string.
using HttpUtility.ParseQueryString, we are able to .Get values based on the key (key-value pair)
So, to get, the value of “brand” from a request looking like the following

So for paging it would look something like this.

Note: I’m going the limit/offset route, instead of page/pagesize.
In the above we check for our specific query parameters (limit/offset) and set limit and offset accordingly

3. Filtering the response

Get the content from the response and Take & Skip the limit and offset (if needed).

4. Setting the newly filtered results as the “new” results of the request

Set the new result as the response content


Now we just need to apply the filter to our entire project.
This happens in the WebApiConfig.cs file.

The full PagingFilter can be seen here

Now we never have to think about pagination support for specific actions, it’s already handled through our attribute.
Do note that this comes with a cost. – We are already loading the entire dataset into memory and then paginating it.
in production system, where performance is key – please use native DB paging support.