October 17 2018

C# - Pure Pagination Logic in C# / ASP.NET

Below is a pure pagination function written in C# that you can use to paginate any array or list of items in ASP.NET Core and standard ASP.NET applications.

It's available as a NuGet package at https://www.nuget.org/packages/JW.Pager, you can add it to your ASP.NET Core project with the .NET Core CLI by running dotnet add package JW.Pager. For standard ASP.NET projects you can use the NuGet package manager console in visual studio to run Install-Package JW.Pager.

Source code for the C# pagination logic is available on GitHub at https://github.com/cornflourblue/JW.Pager

For an example ASP.NET Core Razor Pages project that uses the pagination package check out ASP.NET Core Razor Pages - Pagination Example

For the same pagination logic written in JavaScript check out JavaScript - Pure Pagination Logic in Vanilla JS


C# / ASP.NET Pager Class Usage

The C# pagination logic is contained in a single Pager class that takes the following constructor arguments:

  • totalItems (required) - the total number of items to be paged
  • currentPage (optional) - the current active page, defaults to the first page
  • pageSize (optional) - the number of items per page, defaults to 10
  • maxPages (optional) - the maximum number of page navigation links to display, defaults to 10

After creating an instance of the Pager class with new Pager(...), it populates a bunch of properties on the class instance with all the information needed to display the current page of items in the view and the page navigation links.

Below are some example inputs and outputs to give you a better idea of how the Pager class works, you can tinker with them in the example ASP.NET Core Razor Pages project linked to above.

var pager = new Pager(totalItems: 150);

// pager instance property values
pager.TotalItems;   // 150
pager.CurrentPage;  // 1
pager.PageSize;     // 10,
pager.TotalPages;   // 15
pager.StartPage;    // 1
pager.EndPage;      // 10
pager.StartIndex;   // 0
pager.EndIndex;     // 9
pager.Pages;        // [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ]

var pager = new Pager(totalItems: 150, currentPage: 7);

// pager instance property values
pager.TotalItems;   // 150
pager.CurrentPage;  // 7
pager.PageSize;     // 10,
pager.TotalPages;   // 15
pager.StartPage;    // 2
pager.EndPage;      // 11
pager.StartIndex;   // 60
pager.EndIndex;     // 69
pager.Pages;        // [ 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 ]

var pager = new Pager(totalPages: 150, currentPage: 7, pageSize: 15);

// pager instance property values
pager.TotalItems;   // 150
pager.CurrentPage;  // 7
pager.PageSize;     // 15,
pager.TotalPages;   // 10
pager.StartPage;    // 1
pager.EndPage;      // 10
pager.StartIndex;   // 90
pager.EndIndex;     // 104
pager.Pages;        // [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ]

var pager = new Pager(totalPages: 150, currentPage: 7, pageSize: 15, maxPages: 5);

// pager instance property values
pager.TotalItems;   // 150
pager.CurrentPage;  // 7
pager.PageSize;     // 15,
pager.TotalPages;   // 10
pager.StartPage;    // 5
pager.EndPage;      // 9
pager.StartIndex;   // 90
pager.EndIndex;     // 104
pager.Pages;        // [ 5, 6, 7, 8, 9 ]


C# / ASP.NET Pagination Logic

Below are the nuts and bolts of how the pagination logic is implemented in C# / ASP.NET.

using System;
using System.Collections.Generic;
using System.Linq;

namespace JW
{
    public class Pager
    {
        public Pager(
            int totalItems,
            int currentPage = 1,
            int pageSize = 10,
            int maxPages = 10)
        {
            // calculate total pages
            var totalPages = (int)Math.Ceiling((decimal)totalItems / (decimal)pageSize);

            // ensure current page isn't out of range
            if (currentPage < 1)
            {
                currentPage = 1;
            }
            else if (currentPage > totalPages)
            {
                currentPage = totalPages;
            }

            int startPage, endPage;
            if (totalPages <= maxPages) 
            {
                // total pages less than max so show all pages
                startPage = 1;
                endPage = totalPages;
            }
            else 
            {
                // total pages more than max so calculate start and end pages
                var maxPagesBeforeCurrentPage = (int)Math.Floor((decimal)maxPages / (decimal)2);
                var maxPagesAfterCurrentPage = (int)Math.Ceiling((decimal)maxPages / (decimal)2) - 1;
                if (currentPage <= maxPagesBeforeCurrentPage) 
                {
                    // current page near the start
                    startPage = 1;
                    endPage = maxPages;
                } 
                else if (currentPage + maxPagesAfterCurrentPage >= totalPages) 
                {
                    // current page near the end
                    startPage = totalPages - maxPages + 1;
                    endPage = totalPages;
                }
                else 
                {
                    // current page somewhere in the middle
                    startPage = currentPage - maxPagesBeforeCurrentPage;
                    endPage = currentPage + maxPagesAfterCurrentPage;
                }
            }

            // calculate start and end item indexes
            var startIndex = (currentPage - 1) * pageSize;
            var endIndex = Math.Min(startIndex + pageSize - 1, totalItems - 1);

            // create an array of pages that can be looped over
            var pages = Enumerable.Range(startPage, (endPage + 1) - startPage);

            // update object instance with all pager properties required by the view
            TotalItems = totalItems;
            CurrentPage = currentPage;
            PageSize = pageSize;
            TotalPages = totalPages;
            StartPage = startPage;
            EndPage = endPage;
            StartIndex = startIndex;
            EndIndex = endIndex;
            Pages = pages;
        }

        public int TotalItems { get; private set; }
        public int CurrentPage { get; private set; }
        public int PageSize { get; private set; }
        public int TotalPages { get; private set; }
        public int StartPage { get; private set; }
        public int EndPage { get; private set; }
        public int StartIndex { get; private set; }
        public int EndIndex { get; private set; }
        public IEnumerable<int> Pages { get; private set; }
    }
}

 

Web Development Sydney

Feel free to contact me if you're looking for a web developer in Sydney, I also provide remote contracting services for clients outside Sydney.

 


Sponsored by