I remember when I was just starting to develop an application. I covered the basic functionalities like the Create, Read, Update & Delete
(CRUD). Part of the "Read"
functionality is viewing all the list of the data that the user created. At first, everything seems fine but when the user put tons of data and they wanted to view them in the list, they're having hard time waiting for the list to be loaded. As a beginner, I wasn't aware that I made a mistake to not include the server-side pagination in my app!
We should always consider to implement server-side pagination especially if we can assume that the data we'll be showing in the list will become tons and tons after some months or even years. You don't want the users wait for so long to render all the data you have in the database.
Okay! enough with intro, let's implement the pagination in our ASP.NET Core Web API.
I would assume that you already have an app connected to the database using Entity Framework (Core). If you don't have yet, you should check this "Tutorial: Get started with EF Core in an ASP.NET MVC web app" on how to setup your app locally.
namespace BusinessLogic.Helpers
{
public class PaginatedData<T> : List<T>
{
public int PageIndex { get; private set; }
public int TotalPages { get; private set; }
public int TotalData { get; private set; }
public PaginatedData(IEnumerable<T> items, int count, int pageIndex, int pageSize)
{
PageIndex = pageIndex;
TotalPages = (int)Math.Ceiling(count / (double)pageSize);
TotalData = count;
this.AddRange(items);
}
public static PaginatedData<T> CreateList(IList<T> source, int pageIndex, int pageSize)
{
var count = source.Count();
var items = source.Skip((pageIndex - 1) * pageSize).Take(pageSize).ToList();
return new PaginatedData<T>(items, count, pageIndex, pageSize);
}
}
}
The pageSize
represents the size of the data that we want to fetch or data per page. Then we use the Skip
and Take
from LINQ to specify how many data to skip and to fetch. source.Skip((pageIndex - 1) * pageSize).Take(pageSize).ToList()
. Read more about Skip
and Take
here.
public async Task<PaginatedData<ProductDto>> PaginatedProducts(int pageIndex, int pageSize)
{
var products = await context.Products().ToList();
return PaginatedData<ProductDto>.CreateList(products, pageIndex, pageSize);
}
[HttpGet("pagination/{pageIndex}/{pageSize}")]
public async Task<IActionResult> PaginatedGetProduct(int pageIndex, int pageSize)
{
if (pageIndex < 0 || pageSize < 0)
return BadRequest();
var data = await productService.PaginatedCustomers(pageIndex, pageSize);
return Ok(new
{
data,
data.PageIndex,
data.TotalData,
data.TotalPages
});
}
Your frontend should have a functionality that calls this controller endpoint when the user clicks the pagination page or the row per page.
If you have some questions or comments, please drop it below 👇 :)
