A C# class used to page through an array or list of items in ASP.NET applications.

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

namespace MyNamespace
{
    /// <summary>
    /// Pure Pagination Logic in C# / ASP.NET.
    /// Article: https://jasonwatmore.com/post/2018/10/17/c-pure-pagination-logic-in-c-aspnet
    /// Source: https://github.com/cornflourblue/JW.Pager/blob/master/Pager.cs
    /// </summary>
    public class Pager
    {
        /// <summary>
        /// Pager class constructor.
        /// </summary>
        /// <param name="totalItems">The total number of items to be paged</param>
        /// <param name="currentPage">The current active page, defaults to the first page.</param>
        /// <param name="pageSize">The number of items per page, defaults to 10.</param>
        /// <param name="maxPages">The maximum number of page navigation links to display, defaults to 10.</param>
        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;
        }

        /// <summary>
        /// The total number of items to be paged.
        /// </summary>
        public int TotalItems { get; private set; }

        /// <summary>
        /// The current active page, defaults to the first page.
        /// </summary>
        public int CurrentPage { get; private set; }

        /// <summary>
        /// The number of items per page, defaults to 10.
        /// </summary>
        public int PageSize { get; private set; }

        /// <summary>
        /// The total amount of pages in the set.
        /// </summary>
        public int TotalPages { get; private set; }

        /// <summary>
        /// The starting page number of the set.
        /// </summary>
        public int StartPage { get; private set; }

        /// <summary>
        /// The last page in the set of items that can be paged.
        /// </summary>
        public int EndPage { get; private set; }

        /// <summary>
        /// The start item index.
        /// </summary>
        public int StartIndex { get; private set; }

        /// <summary>
        /// The end item index.
        /// </summary>
        public int EndIndex { get; private set; }

        /// <summary>
        /// The enumerable of pages.
        /// </summary>
        public IEnumerable<int> Pages { get; private set; }
    }
}