Repository navigation
Migration Guide
This guide collects every breaking and behavioral change that affects callers of the libraries, organized by version. If you are upgrading across multiple major versions, work through the sections in order.
A new package, PagedListResult.DataModels, was introduced. The DTOs (PagedRequest, PagedResult<T>, the filter shapes) were moved out of PagedListResult and into the new package. The original PagedListResult package now references PagedListResult.DataModels and only contains the EF Core extensions.
If your project only references PagedListResult, no action is needed: NuGet brings the new dependency in transitively and the namespaces did not change.
If your project references the DTOs from a place that does not need EF Core (a Blazor WASM client, a shared contracts assembly, a code-generated client), switch its package reference from PagedListResult to PagedListResult.DataModels. The using directives stay the same — the namespaces were preserved.
The PredefinedRecords collection on PagedRequest was replaced by a PredefinedRecord object holding two members: the property name to match against and the identifier list.
new PagedRequest
{
Page = 1, PageSize = 10,
PredefinedRecords = new[] { "1", "2", "3" }
}new PagedRequest
{
Page = 1, PageSize = 10,
PredefinedRecord = new DataPredefinedFilterDefinition
{
PredefinedFieldName = "Id", // optional; falls back to the default primary key
PredefinedRecords = new[] { "1", "2", "3" }
}
}The previous PredefinedRecords collection was untyped: the library could only guess which property to match against. The new shape makes the binding explicit and lets the same request type pin records for any property, not just the entity's primary key.
-
In every place where you build a
PagedRequest, replacePredefinedRecords = ...with thePredefinedRecord = new DataPredefinedFilterDefinition { ... }form. -
If you used
[PaginationDefaultTopRecordPrimaryKey]to mark the property, you can omitPredefinedFieldNameand the resolver will continue to honor the attribute. -
Update your client code (TypeScript / Java / etc.) to send the new JSON shape:
There is no backward-compatibility shim for the old shape: a v3 server will reject the v2 JSON with a 400.
-
DataSearchDefinitiongainedSearchInAllFields(defaults tofalse), enabling search on non-string properties. - The XML / SOAP adapter was reorganized into
SoapXmlExtensions.ToSoapXmlPagedResult. The old extension methods carrying the same name were kept for one release. - A
Map<TDestination>extension was added toPagedResult<T>to clone the envelope while swapping the response items.
- v3.1.0.6767 — adds
SearchInAllFields. - v3.1.1.481 — internal package upgrades; no API changes.
- v3.1.2.7586 — fixes the predefined-records filter when the filter pipeline was used with multiple top-level filters.
- v3.1.3.4848 — drops a redundant
ToString()call onContains/DoesNotContainsover string properties; the resulting EF expressions translate without the wrapper.
The Web integration is independent from the data and EF Core packages. You can keep using PagedListResult without it. If you decide to adopt it, the changes below apply.
| Before | After |
|---|---|
JsonResult<T>(IPagedResult<T>) |
PagedOkResult<T>(IPagedResult<T>) |
XmlResult<T>(IPagedResult<T>) |
PagedXmlResult<T>(IPagedResult<T>) |
The old method names are kept as [Obsolete] shims for one release. Update your controllers as you touch them; mass renames can be done with a single regex.
Earlier preview drops of the Web integration recommended Results.Ok(IPagedResult) directly. With the upstream AggregatedGenericResultMessage.Web (now RzR.ResultMessage.Web) adapter (ResultToHttpResult.ToHttpResult<T>) only the Response collection is serialized, dropping the paging metadata.
The fix is to call the dedicated ToPagedHttpResult helper:
// before
return Results.Ok(paged);
// after
return paged.ToPagedHttpResult(ctx);Results.Ok(paged) still works because paged is a complete object, but ToPagedHttpResult adds 204 handling for null references and routes failures through the same ProblemDetails factory used by MVC. Prefer it for consistency.
The headers (X-Total-Count, Link, etc.) are emitted automatically for MVC controllers as soon as you call AddPagedListResultWeb. For minimal-API endpoints you must attach the endpoint filter explicitly:
app.MapGroup("/api").WithPagedResult().MapGet(...);If the headers are missing on a minimal-API endpoint, this is the most common cause.
ASP.NET Core defines Microsoft.AspNetCore.Http.IResult. The pagination library uses RzR.ResultMessage.Abstractions.IResult (re-exported through AggregatedGenericResultMessage, now RzR.ResultMessage). The two collide whenever you using both namespaces.
In PagedListResult.Web the collision is solved internally with the alias LibResult = RzR.ResultMessage.Abstractions.IResult. In your own code prefer one of:
using LibResult = RzR.ResultMessage.Abstractions.IResult;
// ... or use fully-qualified namesC# using aliases do not apply to closed generic types, so IResult<T> always needs a fully-qualified reference (or an explicit alias for the closed form).
PagedQuery<T> and PagedQueryWithFilters<T> moved from RzR.ResultMessage.Pagination.AspNetCore.MinimalApi to RzR.ResultMessage.Pagination.AspNetCore.Query.
- Find and replace
using RzR.ResultMessage.Pagination.AspNetCore.MinimalApi;withusing RzR.ResultMessage.Pagination.AspNetCore.Query;across your codebase. - No other code changes are required — the types themselves did not change shape, only the namespace.
The wrappers are now dual-host. In addition to their existing BindAsync(HttpContext) support for minimal APIs, they can be used directly as an MVC action parameter decorated with [FromPagedQuery], backed by the new IPagedQueryValidation interface (RzR.ResultMessage.Pagination.AspNetCore.Abstractions), which exposes IsValid and an IDictionary<string, string> Errors.
This is a niche option, not a replacement for the plain PagedRequest / PageRequestWithFilters parameter types, which remain preferred for MVC controllers — especially ones decorated with [ApiController], which already gives you automatic ModelState validation and a 400 response. The wrapper is useful on a controller without [ApiController], where you want to inspect request.IsValid / request.Errors yourself. See MVC Integration for the full pattern.
| Before | After |
|---|---|
AggregatedGenericResultMessage |
RzR.ResultMessage |
AggregatedGenericResultMessage.Web |
RzR.ResultMessage.Web |
These are relevant even if you never reference them directly — they are pulled in transitively, for example to implement IProblemDetailsResultFactory. Update any explicit package references and using directives to the new names.
The assembly version moved from 4.0.0.7837 to 5.0.0.8548. See the v5.0.0.8548 entry in docs/CHANGELOG.md for the full list of changes.
When you upgrade, double-check these defaults against your previous configuration:
| Option | Default |
|---|---|
PagedListResultWebOptions.MaxPageSize |
200 |
PagedListResultWebOptions.DefaultPageSize |
10 |
PagedListResultWebOptions.EmitLinkHeader |
true |
PagedListResultWebOptions.EmitTotalCountHeader |
true |
PagedListResultWebOptions.EmitServerTimingHeader |
false |
If you previously had a homemade middleware emitting these headers, remove it before turning on the toggles to avoid duplicate values.
PagedListResult is maintained by RzR. GitHub repository.
Start here
Reference
- Data Models Reference
- Expression Builders (Common)
- EntityFramework Core Extensions
- Query String Syntax
ASP.NET Core integration
- Web Integration Overview
- MVC Integration
- Minimal API Integration
- Configuration and Options
- Allow List Registry
- Response Headers and ProblemDetails
- OpenAPI and ApiExplorer
Operations