Paging.NET
4.0.1-pre
dotnet add package Paging.NET --version 4.0.1-pre
NuGet\Install-Package Paging.NET -Version 4.0.1-pre
<PackageReference Include="Paging.NET" Version="4.0.1-pre" />
<PackageVersion Include="Paging.NET" Version="4.0.1-pre" />
<PackageReference Include="Paging.NET" />
paket add Paging.NET --version 4.0.1-pre
#r "nuget: Paging.NET, 4.0.1-pre"
#:package Paging.NET@4.0.1-pre
#addin nuget:?package=Paging.NET&version=4.0.1-pre&prerelease
#tool nuget:?package=Paging.NET&version=4.0.1-pre&prerelease
Paging.NET
Paging.NET is a lightweight and flexible library for server-side paging and incremental data loading. Large datasets can be handled more efficiently by retrieving items in smaller, predictable chunks, making data access easier to manage. The library set consists of the following NuGet packages:
Paging.NET: Core library containing the main paging models such asPagingInfoandPaginationSet.Paging.Queryable.NET: Extension library providingIQueryablesupport for paging, sorting, and filtering.Paging.MAUI: Add-on for .NET MAUI moble apps for implementing incremental loading and infinite scrolling scenarios.
Download and Install Paging.NET
This library is available on nuget.org:
| Package | Version | Downlods |
|---|---|---|
| Paging.NET | ||
| Paging.Queryable.NET | ||
| Paging.MAUI |
Getting Started
Paging or pagination is the process of splitting a collection into smaller subsets of items in order to improve performance and reduce the amount of data transferred at once. In practice, paging is usually combined with sorting, searching, and filtering.
In Paging.NET, the client sends a paging request as a PagingInfo, and the service responds with a PaginationSet<T>.
How to Use Paging.NET
Core Types
Paging.NET is built around two core models:
PagingInfois the paging request model. It specifies which page should be loaded, how many items should be returned, and which sorting, search, or filtering options should be applied.
| Property | Description |
|---|---|
FirstPageIndex |
The first valid page index for the request. Allowed values are 0 and 1. |
CurrentPage |
The currently selected page.<br/> The default value is PagingInfo.DefaultFirstPageIndex, which means it initially matches FirstPageIndex. |
ItemsPerPage |
Number of items returned per page. <br/>null disables paging and returns all items, 0 returns totals only, and positive values enable normal paging. The static PagingInfo.DefaultItemsPerPage defaults to null. |
SortBy |
Comma-separated sort expression such as "Name Asc" or "Year Desc, Name Asc". |
Sorting |
Dictionary-based sort definition as an alternative to SortBy string. |
Reverse |
Reverses the final sort order. |
Search |
Free-text search value that can be applied by the target data source. |
Filter |
Property-based filter values that can be applied by the target data source. |
PaginationSet<T>is the paged response model. It contains the items of the current page together with metadata describing the complete result set.
| Property | Description |
|---|---|
FirstPageIndex |
The first page index used for the request and response. |
CurrentPage |
The current page number of the returned result. This value is relative to FirstPageIndex. |
TotalPages |
Total number of pages available for the current filter and search criteria. |
TotalCount |
Total number of items matching the current filter and search criteria. |
TotalCountUnfiltered |
Total number of items before filter or search is applied. |
Items |
The items contained in the current page. |
Basic Example
The following example shows a simple request using the core models:
var pagingInfo = new PagingInfo
{
FirstPageIndex = PagingInfo.DefaultFirstPageIndex,
CurrentPage = 1,
ItemsPerPage = 10,
SortBy = "Name Asc",
Search = "Model Desc"
};
Paging Defaults and Modes
You can configure the global default page size once for your process:
Disable Paging By Default
PagingInfo.DefaultItemsPerPage = null; // null means return all items - no paging is used
Choose the First Page Index (0- or 1-based)
PagingInfo.DefaultFirstPageIndex is a global library default. Allowed values are 0 and 1.
If you want zero-based paging by default, set PagingInfo.DefaultFirstPageIndex = 0. You can still override
FirstPageIndex per request.
PagingInfo.DefaultFirstPageIndex = 0;
Or set it directly on a request:
var pagingInfo = new PagingInfo
{
FirstPageIndex = 0,
CurrentPage = 0,
ItemsPerPage = 10
};
FirstPageIndex is part of the PagingInfo contract and is serialized automatically when it differs from
PagingInfo.DefaultFirstPageIndex.
ItemsPerPage has three explicit modes:
null: disable paging and return all matching items0: return totals only and zero items> 0: return the requested page with the requested number of items
CurrentPage is interpreted relative to FirstPageIndex, which may be 0 or 1. FirstPageIndex is part of the
request and response contract and is serialized over JSON and query strings when it differs from PagingInfo.DefaultFirstPageIndex.
Service Example
A service can then use this request to return a page of Car items. The following example is intentionally kept as
pseudo code to illustrate the general flow:
public PaginationSet<Car> GetCars(PagingInfo pagingInfo)
{
var query = LoadCars();
// Apply search, filtering, sorting, grouping of data
// Apply Skip(...).Take(...) for the requested page
return new PaginationSet<Car>(pagingInfo, pageItems, totalCount, totalCount);
}
If you are working with an IQueryable<T>, the section below shows how Paging.Queryable.NET can perform all necessary steps
to create a PaginationSet<T> through CreatePaginationSet<TEntity>(..) extension method.
How to Use Paging.Queryable.NET
Paging.Queryable.NET provides extensions for applying paging directly to an IQueryable<T>.
This is useful for backend code working with Entity Framework or any other LINQ provider.
The main entry point is CreatePaginationSet<TEntity>(...). It applies the PagingInfo request to an
IQueryable<TEntity> and returns a PaginationSet<TEntity>.
The following example shows how a PaginationSet<Car> can be created directly from an IQueryable<Car>:
IQueryable<Car> queryable = dbContext.Cars;
var pagingInfo = new PagingInfo
{
CurrentPage = 1,
ItemsPerPage = 10,
SortBy = "Year Desc, Name Asc",
Search = "Model Desc",
Filter =
{
{ "Year", 2024 }
}
};
var paginationSet = pagingInfo.CreatePaginationSet<Car>(queryable);
In this example:
Searchis applied using the provided search predicate.Filterapplies additional property-based constraints.SortBydefines the ordering before paging is applied.- The result is returned as a
PaginationSet<Car>. ItemsPerPage = 0returns counts without materializing page items.ItemsPerPage = nullskipsSkip(...).Take(...)and returns all matching items.
Mapping Entities to DTOs
If entities should be mapped to DTOs, CreatePaginationSet<TEntity, TDto>(...) can be used to apply paging and map the
resulting page in one step:
IQueryable<Car> queryable = dbContext.Cars;
var pagingInfo = new PagingInfo
{
CurrentPage = 1,
ItemsPerPage = 10,
SortBy = "Year Desc, Name Asc",
Search = "Model Desc",
Filter =
{
{ "Year", 2024 }
}
};
var paginationSet = pagingInfo.CreatePaginationSet<Car, CarDto>(
queryable,
cars => cars.Select(car => new CarDto
{
Id = car.Id,
Name = car.Name,
Model = car.Model,
Price = car.Price,
Year = car.Year
}));
This overload returns a PaginationSet<CarDto> instead of PaginationSet<Car>, while preserving the paging metadata.
If preferred, sorting can also be defined with the Sorting property instead of SortBy:
var pagingInfo = new PagingInfo
{
CurrentPage = 1,
ItemsPerPage = 10,
Sorting = new Dictionary<string, SortOrder>
{
{ "Name", SortOrder.Asc },
{ "Year", SortOrder.Desc }
}
};
The Filter dictionary supports simple property-based filtering. For example:
var pagingInfo = new PagingInfo
{
Filter = new Dictionary<string, object?>
{
{ "Name", "Tesla" },
{ "Year", 2024 }
}
};
How to Use Paging.MAUI
Paging.MAUI provides helpers for incremental loading and infinite scrolling in .NET MAUI apps.
The central type is InfiniteScrollCollection<T>. It is typically used together with a PagingInfo instance that keeps
track of the next page to load.
The following example is based on the MAUI sample app:
private readonly PagingInfo pagingInfo = new PagingInfo
{
CurrentPage = 1,
ItemsPerPage = 30,
};
private PaginationSet<Car>? lastPaginationSet;
public InfiniteScrollCollection<CarDto> Cars { get; } = new InfiniteScrollCollection<CarDto>();
public async Task InitializeAsync(ICarService carService)
{
this.Cars.OnCanLoadMore = () => !this.lastPaginationSet.StopScroll(this.pagingInfo);
this.Cars.OnLoadMore = async () =>
{
var paginationSet = await carService.GetCarsAsync(this.pagingInfo);
this.lastPaginationSet = paginationSet;
this.pagingInfo.CurrentPage++;
return paginationSet.Items.Select(car => new CarDto
{
Id = car.Id,
Name = car.Name,
Model = car.Model,
Price = car.Price,
Year = car.Year
});
};
await this.Cars.LoadMoreAsync();
}
This pattern assumes normal paging with ItemsPerPage > 0. For totals-only or unpaged requests, StopScroll(...)
returns true immediately.
In XAML, InfiniteScrollBehavior can be attached to a ListView:
<ListView ItemsSource="{Binding Cars}">
<ListView.Behaviors>
<paging:InfiniteScrollBehavior
ItemsSource="{Binding Cars}"
IsLoadingMore="{Binding IsLoadingMore}"/>
</ListView.Behaviors>
</ListView>
When the user scrolls to the last item, the next page is loaded automatically as long as OnCanLoadMore returns true.
Contribution
If you find a bug or want to propose a new feature, feel free to create a new issue here. Please use the predefined issue templates when submitting a new issue.
Thank You
Your contribution is valuable! Open source software isn’t just something you can pick up for free — it represents the hard work and dedication of many people who often not even know each other. We sincerely appreciate the time, effort, and dedication shown by everyone who helps keep this plugin going forward.
Links
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net5.0 was computed. net5.0-windows was computed. net6.0 was computed. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 was computed. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 was computed. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
| .NET Core | netcoreapp2.0 was computed. netcoreapp2.1 was computed. netcoreapp2.2 was computed. netcoreapp3.0 was computed. netcoreapp3.1 was computed. |
| .NET Standard | netstandard2.0 is compatible. netstandard2.1 is compatible. |
| .NET Framework | net461 was computed. net462 was computed. net463 was computed. net47 was computed. net471 was computed. net472 was computed. net48 was computed. net481 was computed. |
| MonoAndroid | monoandroid was computed. |
| MonoMac | monomac was computed. |
| MonoTouch | monotouch was computed. |
| Tizen | tizen40 was computed. tizen60 was computed. |
| Xamarin.iOS | xamarinios was computed. |
| Xamarin.Mac | xamarinmac was computed. |
| Xamarin.TVOS | xamarintvos was computed. |
| Xamarin.WatchOS | xamarinwatchos was computed. |
-
.NETStandard 2.0
- System.Text.Json (>= 8.0.5)
-
.NETStandard 2.1
- System.Text.Json (>= 8.0.5)
NuGet packages (3)
Showing the top 3 NuGet packages that depend on Paging.NET:
| Package | Downloads |
|---|---|
|
Paging.Queryable.NET
Paging.Queryable is a lightweight library for seamless, incremental server-side data loading. |
|
|
Paging.Forms.NET
Paging.NET is a basic toolkit which provides incremental server-side data loads. |
|
|
Paging.MAUI
Paging.MAUI is a lightweight library for seamless, incremental server-side data loading. |
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 4.0.1-pre | 179 | 4/15/2026 |
| 3.2.13-pre | 151 | 4/15/2026 |
| 3.2.12-pr.3533863989 | 52 | 4/15/2026 |
| 3.2.11-pre | 141 | 4/15/2026 |
| 3.2.10-pre | 149 | 4/15/2026 |
| 3.2.9-pr.3533793184 | 61 | 4/15/2026 |
| 3.2.8-pre | 141 | 4/15/2026 |
| 3.2.7-pr.3533780164 | 49 | 4/15/2026 |
| 3.2.6-pr.3530218190 | 48 | 4/15/2026 |
| 3.2.5-pr.3530218190 | 56 | 4/14/2026 |
| 3.2.4-pre | 147 | 4/14/2026 |
| 3.1.14-pre | 212 | 1/9/2026 |
| 3.1.13-pre | 227 | 1/7/2026 |
| 3.1.12-pre | 170 | 1/7/2026 |
| 3.1.11-pre | 169 | 1/7/2026 |
| 3.1.10-pre | 248 | 12/22/2025 |
| 3.1.9 | 381 | 12/17/2025 |
| 3.1.2-pre | 496 | 12/8/2025 |
| 3.1.1-pre | 499 | 12/8/2025 |
| 3.0.33 | 455 | 5/9/2025 |
4.0
- Redesign paging semantics with explicit `ItemsPerPage` modes.
- Add `DefaultFirstPageIndex` to define 0-based or 1-based paging.
- Add `DefaultItemsPerPage` as the configurable global default page size.
3.2
- Update target framework to net9.0 and net10.0.
- Replace Newtonsoft.Json with System.Text.Json.ß
3.1
- Add support for nullable reference types.
3.0
- Drop support for Xamarin and .NET Framework.
- Add support for .NET MAUI.
2.2
- Maintenance updates.
2.0
- Add support for .NET standard.
1.0
- Initial release.