A set of .NET libraries that provide simple, reusable pagination support for ASP.NET Core applications backed by Entity Framework Core. The project is split into three focused NuGet packages so you can take only what you need.
| Package | Description |
|---|---|
Jaricardodev.Paginator.Model |
Core pagination model and interface |
Jaricardodev.Paginator.Persistence |
Entity Framework Core IQueryable extension for paginated queries |
Jaricardodev.Paginator.ServiceHost |
ASP.NET Core result filter that automatically appends an X-Pagination response header |
Client ββGET /products?page=2&pageSize=10βββΊ ASP.NET Core API
β
ββββββββββββΌβββββββββββββββ
β Controller / Service β
β β
β dbContext.Products β
β .ToPaginatedListAsyncβ βββ Persistence
β (page, pageSize) β
ββββββββββββ¬βββββββββββββββ
β PaginatedList<Product>
ββββββββββββΌβββββββββββββββ
β AddPaginationHeader β
β ResultFilter β βββ ServiceHost
β (adds X-Pagination hdr) β
ββββββββββββ¬βββββββββββββββ
β
Client βββ 200 OK βββββββββββββββββββββββββββββββββ
Body: [ ...products for current page... ]
Headers: X-Pagination: {"totalItemsCount":100,"totalPageCount":10}
dotnet add package Jaricardodev.Paginator.Modelor via the NuGet Package Manager Console:
Install-Package Jaricardodev.Paginator.Model| Type | Description |
|---|---|
IPaginatedList |
Interface that exposes TotalItemsCount and TotalPageCount |
PaginatedList<T> |
Generic list that implements both IList<T> and IPaginatedList |
using Jaricardodev.Paginator.Model.Capabilities;
// Create a paginated list manually
var page = new PaginatedList<string>();
page.Add("item1");
page.Add("item2");
page.TotalItemsCount = 50;
page.TotalPageCount = 5;
// Implicit conversion from List<T>
List<string> source = new List<string> { "a", "b", "c" };
PaginatedList<string> paginated = source; // implicit cast
paginated.TotalItemsCount = 3;
paginated.TotalPageCount = 1;| Member | Type | Description |
|---|---|---|
TotalItemsCount |
int |
Total number of items across all pages |
TotalPageCount |
int |
Total number of pages |
Implements IList<T> and IPaginatedList. All standard IList<T> members are available (Add, Remove, Contains, IndexOf, Insert, RemoveAt, Clear, indexer, etc.). In addition:
| Member | Description |
|---|---|
TotalItemsCount |
Total items in the full data set |
TotalPageCount |
Total pages in the full data set |
implicit operator PaginatedList<T>(List<T>) |
Converts a List<T> to PaginatedList<T> |
dotnet add package Jaricardodev.Paginator.Persistenceor via the NuGet Package Manager Console:
Install-Package Jaricardodev.Paginator.PersistenceDependency: Requires
Jaricardodev.Paginator.ModelandMicrosoft.EntityFrameworkCore(β₯ 5.0).
An extension method on IQueryable<T> that executes a paginated database query and returns a fully populated PaginatedList<T>.
using Jaricardodev.Paginator.Model.Capabilities;
using Jaricardodev.Paginator.Persistence.Extensions;
public class ProductService
{
private readonly AppDbContext _db;
public ProductService(AppDbContext db) => _db = db;
public async Task<PaginatedList<Product>> GetPageAsync(int page, int pageSize)
{
return await _db.Products
.AsNoTracking()
.Where(p => p.IsActive)
.OrderBy(p => p.Name)
.ToPaginatedListAsync(page, pageSize);
}
}The extension method:
- Executes a
COUNTquery to obtainTotalItemsCount. - Applies
Skip/Takefor the requested page. - Executes the data query asynchronously.
- Calculates
TotalPageCount = (int)Math.Ceiling((double)totalCount / itemsPerPage). - Returns a
PaginatedList<T>with all fields populated.
public static Task<PaginatedList<T>> ToPaginatedListAsync<T>(
this IQueryable<T> source,
int page,
int itemsPerPage)| Parameter | Description |
|---|---|
source |
The EF Core IQueryable<T> to paginate |
page |
1-based page number |
itemsPerPage |
Number of items per page |
dotnet add package Jaricardodev.Paginator.ServiceHostor via the NuGet Package Manager Console:
Install-Package Jaricardodev.Paginator.ServiceHostDependency: Requires
Jaricardodev.Paginator.Modeland the ASP.NET Core shared framework (Microsoft.AspNetCore.Appframework reference), plusNewtonsoft.Json(β₯ 13.0).
An ASP.NET Core IAsyncResultFilter that automatically adds an X-Pagination header to any response whose body implements IPaginatedList.
Register the filter globally in Program.cs (or Startup.cs):
using Jaricardodev.Paginator.ServiceHost.Filters;
// Program.cs (.NET 6+ minimal hosting)
builder.Services.AddControllers(options =>
{
options.Filters.Add<AddPaginationHeaderResultFilter>();
});For .NET 5 Startup.cs:
using Jaricardodev.Paginator.ServiceHost.Filters;
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers(options =>
{
options.Filters.Add(typeof(AddPaginationHeaderResultFilter));
});
}No changes are needed in your controllers. When the action result contains a PaginatedList<T>, the filter automatically adds the header:
[ApiController]
[Route("api/[controller]")]
public class ProductsController : ControllerBase
{
private readonly ProductService _service;
public ProductsController(ProductService service) => _service = service;
[HttpGet]
public async Task<ActionResult<PaginatedList<ProductDto>>> GetAll(
[FromQuery] int page = 1,
[FromQuery] int pageSize = 10)
{
var result = await _service.GetPageAsync(page, pageSize);
return Ok(result); // X-Pagination header is added automatically
}
}HTTP response example:
HTTP/1.1 200 OK
Content-Type: application/json
X-Pagination: {"totalItemsCount":100,"totalPageCount":10}
[...items for the requested page...]
Implements IAsyncResultFilter. When the ObjectResult value implements IPaginatedList, the filter serialises TotalItemsCount and TotalPageCount as JSON and adds the result as the X-Pagination response header.
This project is licensed under the MIT License.
