Pagination for ASP.NET Core.
Supports both offset and keyset pagination for Entity Framework Core.
This package provides an easy to use service that auto reads pagination related params from the query string of the request to paginate EF Core data.
Keyset pagination support uses MR.EntityFrameworkCore.KeysetPagination.
Keyset pagination (also known as cursor/seek pagination) is much more efficient and has stable performance over large amounts of data, but it's harder to work with than offset pagination.
Offset | Keyset | |
---|---|---|
Performance | worse over large data | stable over large data |
Duplicate/Skipped data | always possible if data gets updated between page navigations | no duplication/skipping |
Pages | can access random pages | can only go to first/previous/next/last |
We recommend keyset pagination over offset, unless you have a requirement for wanting to randomly access pages.
Add pagination services:
services.AddPagination();
You can configure some default options here:
services.AddPagination(options =>
{
options.PageQueryParameterName = "p";
// ...
});
Check the PaginationOptions
class to see what you can configure.
And then just inject IPaginationService
in your controller/page and use it. The returned result is either a KeysetPaginationResult<>
or an OffsetPaginationResult<>
, each containing all the info you need for this pagination result.
Do a keyset pagination:
var usersPaginationResult = await _paginationService.KeysetPaginateAsync(
_dbContext.Users,
b => b.Descending(x => x.Created),
async id => await _dbContext.Users.FindAsync(id));
Note: Check MR.EntityFrameworkCore.KeysetPagination for more info about keyset pagination.
Do a keyset pagination and map to dto:
// Using AutoMapper for example:
var usersPaginationResult = await _paginationService.KeysetPaginateAsync(
_dbContext.Users,
b => b.Descending(x => x.Created),
async id => await _dbContext.Users.FindAsync(id),
query => query.ProjectTo<UserDto>(_mapper.ConfigurationProvider));
// Using manual select:
var usersPaginationResult = await _paginationService.KeysetPaginateAsync(
_dbContext.Users,
b => b.Descending(x => x.Created),
async id => await _dbContext.Users.FindAsync(id),
query => query.Select(user => new UserDto(...)));
Do an offset pagination:
var usersPaginationResult = await _paginationService.OffsetPaginateAsync(
_dbContext.Users.OrderByDescending(x => x.Created));
Do an offset pagination and map to dto:
// Using AutoMapper for example:
var usersPaginationResult = await _paginationService.OffsetPaginateAsync(
_dbContext.Users.OrderByDescending(x => x.Created),
query => query.ProjectTo<UserDto>(_mapper.ConfigurationProvider));
// Using manual select:
var usersPaginationResult = await _paginationService.OffsetPaginateAsync(
_dbContext.Users.OrderByDescending(x => x.Created),
query => query.Select(x => new UserDto(...)));
There's additional support for doing an offset pagination over in memory list of data:
// Assume we have an in memory list of orders.
var orders = new List<Order>();
// This does efficient offset pagination over the orders list.
var result = _paginationService.OffsetPaginate(orders);
There's a helper PaginationActionDetector
class that can be used with reflection, for example in ASP.NET Core conventions, which can tell you whether the action method returns a pagination result or not. This is what the MR.AspNetCore.Pagination.Swashbuckle package uses to configure swagger for those apis.
This is a support package for Swashbuckle.
Use it when you're using Swashbuckle (swagger). Actions that return keyset/offset pagination results will automatically have the query parameters (page, before, after, etc) show up in swagger ui.
When you're configuring swagger:
builder.Services.AddSwaggerGen(c =>
{
// ...
c.ConfigurePagination();
});
Check the samples folder for project samples.
- Basic: A quick example of using keyset and offset pagination (using razor pages).
- ApiWithSwashbuckle: A sample that uses the Swashbuckle support package.