Loading...

Pagination in .NET Core / 5 / 6 MVC with Entity Framework Core

10/20/2021
Avatar
Author
Gal Ratner

Pagination is useful with large results sets. There are plenty of solutions out there to create next and previous buttons, but I couldn’t find anything that creates a nice Bootstrap paginator so I just wrote my own:


To use it first add a The PaginatedList class to your code. This is a Modified version of the one found on MSDN.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
 
namespace Messages.Utilities
{
    public class PaginatedList<T> : List<T>
    {
        public int PageIndex { get; private set; }
        public int TotalPages { get; private set; }
 
        public PaginatedList(List<T> items, int count, int pageIndex, int pageSize)
        {
            PageIndex = pageIndex;
            TotalPages = (int)Math.Ceiling(count / (double)pageSize);
 
            this.AddRange(items);
        }
 
        public bool HasPreviousPage
        {
            get
            {
                return (PageIndex > 1);
            }
        }
 
        public bool HasNextPage
        {
            get
            {
                return (PageIndex < TotalPages);
            }
        }
 
        public static async Task<PaginatedList<T>> CreateAsync(
            IQueryable<T> source, int pageIndex, int pageSize)
        {
            var count = await source.CountAsync();
            var items = await source.Skip(
                (pageIndex - 1) * pageSize)
                .Take(pageSize).ToListAsync();
            return new PaginatedList<T>(items, count, pageIndex, pageSize);
        }
 
        public static PaginatedList<T> Create(
            List<T> source, int pageIndex, int pageSize)
        {
            var count = source.Count();
            var items = source.Skip(
                (pageIndex - 1) * pageSize)
                .Take(pageSize).ToList();
            return new PaginatedList<T>(items, count, pageIndex, pageSize);
        }
    }
}

Next add the _Pagination partial view to your shared views folder

<nav aria-label="Blog Pages">
    <ul class="pagination justify-content-center">
        <li class="page-item @(Model.PageIndex <= 1 ? "disabled" : string.Empty)"><a class="page-link" asp-route-pageNumber="1">First</a></li>
        <li class="page-item @(!Model.HasPreviousPage ? "disabled" : string.Empty)"><a class="page-link" asp-route-pageNumber="@(Model.PageIndex - 1)">Previous</a></li>
 
        @for (int i = Model.PageIndex - 3; i <= Model.PageIndex - 1; i++)
        {
            @if (i < 1)
                continue;
            <li class="page-item"><a class="page-link" asp-route-pageNumber="@i">@i</a></li>
        }
 
        @for (int i = Model.PageIndex; i <= Model.PageIndex + 3; i++)
        {
            @if (i > Model.TotalPages)
                break;
            <li class="page-item @(Model.PageIndex == i ? "active" : string.Empty)"><a class="page-link" asp-route-pageNumber="@i">@i</a></li>
        }
 
        <li class="page-item @(!Model.HasNextPage ? "disabled" : string.Empty)"><a class="page-link" asp-route-pageNumber="@(Model.PageIndex + 1)">Next</a></li>
        <li class="page-item @(Model.PageIndex >= Model.TotalPages ? "disabled" : string.Empty)"><a class="page-link" asp-route-pageNumber="@(Model.TotalPages)">Last</a></li>
    </ul>
</nav>

Now you are ready to use the PaginatedList from your controller

[Route("Blog/")]
public async Task<IActionResult> Index(int? pageNumber)
{
     int pageSize = 20;
     return View(PaginatedList<BlogPost>.Create(await _cache.GetBlogPostsAync(), pageNumber ?? 1, pageSize));
}

And finally add the paginator to your view

<partial name="~/Views/Shared/_Paginator.cshtml" />

The result should be a nice Bootstrap paginatior with page numbers, next, previous, first and last buttons.


Did you find this post useful? Visit my software consulting firm Inverted Software



Related Tags:

No Comments Yet.

Leave a Comment
Top