Overview
Pagination helps manage large datasets by returning data in smaller, manageable chunks. The pagination system provides:- PaginationRequest: Standard request parameters for pagination
- PaginatedResult: Standard response wrapper with pagination metadata
- Consistency: All APIs use the same pagination pattern
- Performance: Reduces memory usage and network transfer
PaginationRequest
ThePaginationRequest record defines standard pagination parameters.
BuildingBlocks/Pagination/PaginationRequest.cs
Properties
| Property | Type | Default | Description |
|---|---|---|---|
PageIndex | int | 0 | Zero-based page index (first page is 0) |
PageSize | int | 10 | Number of items per page |
Usage in Queries
IncludePaginationRequest in your query definition:
Usage in Controllers
Accept pagination parameters from query string:PaginatedResult
ThePaginatedResult class wraps paginated data with metadata.
BuildingBlocks/Pagination/PaginatedResult.cs
Properties
| Property | Type | Description |
|---|---|---|
PageIndex | int | Current page index (zero-based) |
PageSize | int | Number of items per page |
Count | long | Total number of items across all pages |
Data | IEnumerable<TEntity> | Items for the current page |
Computed Properties
You can easily compute additional pagination metadata:Implementation with Entity Framework
Here’s how to implement pagination in a query handler using Entity Framework:Key Implementation Points
- Count Before Pagination: Get total count before applying
SkipandTake - Order Results: Always order before pagination for consistent results
- Skip and Take: Use for offset-based pagination
- AsNoTracking: Use for read-only queries to improve performance
Response Format
Example Response:Interpreting the Response
- pageIndex: 0: This is the first page
- pageSize: 10: Each page contains 10 items
- count: 147: There are 147 total items
- data: Array of 10 items for this page
- Total Pages: Math.Ceiling(147 / 10) = 15 pages
- Has Next Page: Yes (page 0 of 15)
- Has Previous Page: No (this is the first page)
Advanced Pagination Patterns
Dynamic Page Size
Limit maximum page size to prevent performance issues:Cursor-Based Pagination
For large datasets or real-time data, consider cursor-based pagination:Search with Pagination
Combine full-text search with pagination:Best Practices
Always Order Results
Always Order Results
Always apply ordering before pagination to ensure consistent results across pages.
Count Efficiently
Count Efficiently
Use
LongCountAsync instead of loading all data and counting.Validate Page Parameters
Validate Page Parameters
Validate pagination parameters to prevent errors.
Use AsNoTracking for Read-Only Queries
Use AsNoTracking for Read-Only Queries
Improve performance by disabling change tracking for read-only queries.
Consider Caching for Expensive Counts
Consider Caching for Expensive Counts
For large tables, count operations can be expensive. Consider caching.
Client-Side Usage
Example of consuming paginated API from a client:Related Topics
CQRS Pattern
Learn how to use pagination in queries
Building Blocks Overview
Explore other shared components
