Skip to content

TailoredApps.Shared.MediatR.PagedRequest

NuGet License: MIT


Description

This library provides a base PagedAndSortedRequest<TResponse, TQuery, TModel> class for MediatR requests that require pagination and sorting. It standardizes paging (Page, Count) and sorting (SortField, SortDir) parameters across all list queries in the application.

The class is tightly integrated with TailoredApps.Shared.Querying — requires TQuery to inherit from QueryBase and TResponse to implement IPagedResult<TModel>.


Instalacja

dotnet add package TailoredApps.Shared.MediatR.PagedRequest

Przykład użycia

Definicja query filter, response i request

using TailoredApps.Shared.Querying;
using TailoredApps.Shared.MediatR.PagedRequest;

// 1. Filter dziedziczy po QueryBase
public class ProductFilter : QueryBase
{
    public string NameContains { get; set; }
    public decimal? MinPrice { get; set; }
    public decimal? MaxPrice { get; set; }
    public bool? InStock { get; set; }
}

// 2. Response implementuje IPagedResult<TModel>
public class ProductListResponse : IPagedResult<ProductDto>
{
    public ICollection<ProductDto> Results { get; set; }
    public int Count { get; set; }
}

// 3. Request dziedziczy PagedAndSortedRequest
public class GetProductsQuery
    : PagedAndSortedRequest<ProductListResponse, ProductFilter, ProductDto>
{
    // Wszystkie parametry paginacji/sortowania są odziedziczone
    // Można dodać własne właściwości:
    public bool IncludeArchived { get; set; } = false;
}

Handler

public class GetProductsQueryHandler
    : IRequestHandler<GetProductsQuery, ProductListResponse>
{
    private readonly IProductRepository _repo;

    public GetProductsQueryHandler(IProductRepository repo) => _repo = repo;

    public async Task<ProductListResponse> Handle(
        GetProductsQuery request,
        CancellationToken ct)
    {
        var query = _repo.AsQueryable();

        // Aplikacja filtrów
        if (!string.IsNullOrWhiteSpace(request.Filter?.NameContains))
            query = query.Where(p => p.Name.Contains(request.Filter.NameContains));

        if (request.Filter?.MinPrice.HasValue == true)
            query = query.Where(p => p.Price >= request.Filter.MinPrice.Value);

        // Sortowanie
        if (request.IsSortingSpecified)
        {
            query = request.SortDir == SortDirection.Asc
                ? query.OrderBy(request.SortField)
                : query.OrderByDescending(request.SortField);
        }

        var totalCount = await query.CountAsync(ct);

        // Paginacja
        if (request.IsPagingSpecified)
            query = query.Skip((request.Page!.Value - 1) * request.Count!.Value)
                         .Take(request.Count.Value);

        var items = await query.Select(p => p.ToDto()).ToListAsync(ct);

        return new ProductListResponse
        {
            Results = items,
            Count = totalCount
        };
    }
}

Wywołanie z kontrolera

[HttpGet]
public async Task<IActionResult> GetProducts([FromQuery] GetProductsQuery query)
{
    // GET /api/products?page=1&count=20&sortField=Price&sortDir=Asc&filter.nameContains=shirt
    var result = await _mediator.Send(query);
    return Ok(result);
}

API Reference

Typ Rodzaj Opis
PagedAndSortedRequest<TResponse, TQuery, TModel> Klasa bazowa Bazowy request MediatR z paginacją i sortowaniem
Page Właściwość int? Numer strony (1-based)
Count Właściwość int? Liczba elementów na stronie
IsPagingSpecified Właściwość bool true gdy Page i Count mają wartość
SortField Właściwość string Nazwa pola do sortowania
SortDir Właściwość SortDirection? Kierunek sortowania (Asc/Desc)
IsSortingSpecified Właściwość bool true gdy SortField i SortDir są ustawione
Filter Właściwość TQuery Obiekt filtra dziedziczący po QueryBase
IsSortBy(string) Metoda Sprawdza czy sortowanie jest po danym polu (case-insensitive)

🤖 AI Agent Prompt

## TailoredApps.Shared.MediatR.PagedRequest — Instrukcja dla agenta AI

Używasz PagedAndSortedRequest jako bazowej klasy dla stronicowanych requestów MediatR.

### Definicja
```csharp
// Filter
public class MyFilter : QueryBase { public string Name { get; set; } }

// Response  
public class MyListResponse : IPagedResult<MyDto>
{
    public ICollection<MyDto> Results { get; set; }
    public int Count { get; set; }
}

// Request
public class GetMyItemsQuery : PagedAndSortedRequest<MyListResponse, MyFilter, MyDto> { }

Parametry URL (ASP.NET Core binding)

?page=1&count=20&sortField=Name&sortDir=Asc&filter.name=test

W handlerze

if (request.IsPagingSpecified)
    query = query.Skip((request.Page!.Value - 1) * request.Count!.Value).Take(request.Count.Value);

if (request.IsSortingSpecified)
    query = request.SortDir == SortDirection.Asc ? query.OrderBy(...) : query.OrderByDescending(...);

Zasady

  • TQuery musi dziedziczyć po QueryBase
  • TResponse musi implementować IPagedResult
  • IsPagingSpecified = Page i Count mają wartość — sprawdzaj przed Skip/Take
  • IsSortBy("Name") — sprawdza case-insensitive ```