Skip to content

Configuration and Options

RzR edited this page May 1, 2026 · 1 revision

Configuration and Options

The Web integration is registered with a single call:

builder.Services
    .AddPagedListResultWeb(options =>
    {
        options.MaxPageSize = 200;
        options.DefaultPageSize = 25;
        options.EmitLinkHeader = true;
        options.EmitTotalCountHeader = true;
        options.EmitServerTimingHeader = false;
    });

This page lists every option, every default value, every overload, and the order of registrations performed under the hood.

AddPagedListResultWeb(...)

Located in PagedListResultServiceCollectionExtensions. Returns a PagedListResultBuilder so you can chain ConfigurePageable<T>(...) calls.

The method performs the following registrations:

  1. services.Configure<PagedListResultWebOptions>(configure ?? _ => { }).
  2. services.TryAddSingleton<IPageableMetadataRegistry, PageableMetadataRegistry>() — the consumer can pre-register a custom implementation; the default one is only added if missing.
  3. services.TryAddSingleton<PagedResultActionFilter>().
  4. services.PostConfigure<MvcOptions>(o => ...) — adds:
    • PagedResultApplicationModelConvention (only if no instance is already registered);
    • ServiceFilterAttribute(typeof(PagedResultActionFilter)) (always added, runs for every action);
    • PagedRequestModelBinderProvider inserted at index 0 of o.ModelBinderProviders (only if no instance is already registered).
  5. return new PagedListResultBuilder(services).

PagedListResultWebOptions

Property Type Default Description
MaxPageSize int 200 Hard cap on PagedRequest.PageSize for inbound requests. Values exceeding the cap are silently clamped.
DefaultPageSize int 10 Used when the request omits pageSize.
EmitLinkHeader bool true Whether PagedResponseHeaderWriter should emit the RFC 5988 Link header. The header is only emitted on GET requests when PageCount > 0, regardless of this flag's value.
EmitTotalCountHeader bool true Toggles X-Total-Count, X-Page-Count, X-Page-Size, X-Current-Page.
EmitServerTimingHeader bool false Toggles Server-Timing: paged;dur=<ms> based on PagedExecDetailsResult.ExecutionTimeMs.
StatusCodeMapper Func<IResult, int, int>? null Optional callback that lets you remap the failure HTTP status code based on the result envelope and the default status code (400).
ProblemTypeBaseUri Uri? null Used by the upstream IProblemDetailsResultFactory when building the type field of the ProblemDetails document. When null, https://datatracker.ietf.org/doc/html/rfc9457 is used.
JsonSerializerOptions JsonSerializerOptions? null When non-null, used by ToPagedHttpResult for the success body serialization. When null, the defaults from ASP.NET Core's JSON pipeline apply.

The options are read on each request through IOptions<PagedListResultWebOptions> (so they participate in the configuration reloading mechanism if you use IOptionsMonitor in custom code).

AddPagedListResultApiExplorer()

Located in PagedListResultMvcBuilderExtensions. It is a thin IMvcBuilder extension that adds PagedResultApplicationModelConvention to MvcOptions if it is not already present. It is idempotent with the registration done by AddPagedListResultWeb, so calling both is safe.

builder.Services
    .AddControllers()
    .AddPagedListResultApiExplorer();

This is the call that makes Swagger / OpenAPI describe paged endpoints with the proper schemas. See OpenAPI and ApiExplorer.

WithPagedResult() / AddPagedResultEndpointFilter<TBuilder>()

Available only on net7.0 and newer. Defined in PagedResultEndpointRouteExtensions. Both attach PagedResultEndpointFilter to the endpoint or route group, returning the same TBuilder so they can be chained. They are functionally identical; WithPagedResult exists as a friendlier alias.

app.MapGroup("/api").WithPagedResult().MapGet(...);
app.MapGet("/items", ...).AddPagedResultEndpointFilter();

PagedListResultBuilder.ConfigurePageable<T>(...)

Returned by AddPagedListResultWeb. The builder exposes a single configuration method:

builder.Services
    .AddPagedListResultWeb()
    .ConfigurePageable<Product>(p =>
    {
        p.AllowSort("Id", "Name", "Price", "CreatedOn");
        p.AllowFilter("Status", "Price", "CreatedOn");
        p.AllowSearch("Name", "Description");
    });

It resolves the singleton IPageableMetadataRegistry from the service collection, builds a PageableMetadata instance through PageableMetadataBuilder<T>, and registers it under typeof(T). If you call ConfigurePageable<T> twice for the same type, the latest call wins.

See Allow List Registry for the full registry surface and the runtime behavior.

Replacing built-in services

Because every internal singleton is registered through TryAddSingleton, you can replace any of them by calling services.AddSingleton<...> before AddPagedListResultWeb:

services.AddSingleton<IPageableMetadataRegistry, MyDistributedRegistry>();
services.AddSingleton<IProblemDetailsResultFactory, MyProblemDetailsFactory>();
services.AddPagedListResultWeb();

The MVC option additions (the convention, the filter and the binder provider) check for existing instances of the same concrete type before adding, so you can also customize them in a PostConfigure<MvcOptions> callback after AddPagedListResultWeb if needed.

Clone this wiki locally