Przejdź do treści

TailoredApps.Shared.MediatR

NuGet License: MIT


Opis

Biblioteka dostarcza gotowy zestaw pipeline behaviors dla MediatR, które pokrywają najczęstsze potrzeby aplikacji enterprise: logowanie, walidację, cache'owanie, fallback i retry. Zamiast ręcznie implementować te cross-cutting concerns w każdym handlerze, rejestrujesz je raz przez PipelineRegistration i masz je dla wszystkich requestów.

Behaviory działają w kolejności: Logging → Validation → Caching → Fallback → Retry → Handler.

Biblioteka wspiera mechanizm auto-discovery (przez Scrutor) — cache policies, fallback handlers i retry konfiguracje są skanowane i rejestrowane automatycznie ze wskazanego assembly.


Instalacja

dotnet add package TailoredApps.Shared.MediatR

Rejestracja w DI

// Program.cs
using TailoredApps.Shared.MediatR.DI;

// Rejestracja MediatR
builder.Services.AddMediatR(cfg =>
    cfg.RegisterServicesFromAssembly(typeof(Program).Assembly));

// Rejestracja pipeline behaviors
var pipeline = new PipelineRegistration(builder.Services);
pipeline.RegisterPipelineBehaviors();

// Opcjonalnie: auto-discovery cache policies, fallback, retry z assembly
pipeline.RegisterPipelineBehaviors(typeof(Program).Assembly);

Przykład użycia

Request + Handler

// Request
public class GetProductQuery : IRequest<ProductDto>
{
    public int ProductId { get; set; }
}

// Validator (automatycznie przechwycony przez ValidationBehavior)
public class GetProductQueryValidator : AbstractValidator<GetProductQuery>
{
    public GetProductQueryValidator()
    {
        RuleFor(x => x.ProductId).GreaterThan(0);
    }
}

// Handler
public class GetProductQueryHandler : IRequestHandler<GetProductQuery, ProductDto>
{
    private readonly IProductRepository _repo;

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

    public async Task<ProductDto> Handle(GetProductQuery request, CancellationToken ct)
    {
        var product = await _repo.GetByIdAsync(request.ProductId, ct);
        return product?.ToDto() ?? throw new NotFoundException($"Product {request.ProductId} not found");
    }
}

Cache Policy dla requestu

public class GetProductQueryCachePolicy : ICachePolicy<GetProductQuery, ProductDto>
{
    public string GetCacheKey(GetProductQuery request)
        => $"product:{request.ProductId}";

    public TimeSpan? SlidingExpiration => TimeSpan.FromMinutes(5);
    public TimeSpan? AbsoluteExpiration => null;
    public TimeSpan? AbsoluteExpirationRelativeToNow => TimeSpan.FromHours(1);
}

Fallback Handler

public class GetProductQueryFallback : IFallbackHandler<GetProductQuery, ProductDto>
{
    public Task<ProductDto> HandleFallbackAsync(
        GetProductQuery request,
        Exception exception,
        CancellationToken ct)
    {
        // Zwróć cached/default wartość gdy handler rzuci
        return Task.FromResult(ProductDto.Empty);
    }
}

API Reference

Typ Rodzaj Opis
LoggingBehavior<TRequest, TResponse> Pipeline Behavior Loguje czas wykonania i wyjątki; correlation ID per request
ValidationBehavior<TRequest, TResponse> Pipeline Behavior Wykonuje wszystkie IValidator<TRequest> (FluentValidation)
CachingBehavior<TRequest, TResponse> Pipeline Behavior Cache'uje odpowiedź zgodnie z ICachePolicy<TRequest, TResponse>
FallbackBehavior<TRequest, TResponse> Pipeline Behavior Przy wyjątku wywołuje IFallbackHandler<TRequest, TResponse>
RetryBehavior<TRequest, TResponse> Pipeline Behavior Ponawia request zgodnie z IRetryableRequest<TRequest, TResponse>
PipelineRegistration Klasa Rejestruje wszystkie behaviors + auto-discovery z assembly
IPipelineRegistration Interfejs Kontrakt PipelineRegistration
ICachePolicy<TRequest, TResponse> Interfejs Konfiguracja cache: klucz, TTL, sliding/absolute expiration
IFallbackHandler<TRequest, TResponse> Interfejs Handler fallbacku przy wyjątku
IRetryableRequest<TRequest, TResponse> Interfejs Konfiguracja retry dla requestu
ICache Interfejs Abstrakcja cache (wstrzykiwana do CachingBehavior)

🤖 AI Agent Prompt

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

Używasz biblioteki TailoredApps.Shared.MediatR z pipeline behaviors w projekcie .NET.

### Rejestracja
```csharp
builder.Services.AddMediatR(cfg => cfg.RegisterServicesFromAssembly(typeof(Program).Assembly));
var pipeline = new PipelineRegistration(builder.Services);
pipeline.RegisterPipelineBehaviors();
pipeline.RegisterPipelineBehaviors(typeof(Program).Assembly); // auto-discovery

Kolejność behaviors

Logging → Validation → Caching → Fallback → Retry → Handler

Walidacja (automatyczna)

// Validator automatycznie przechwycony — rzuca ValidationException gdy błąd
public class MyQueryValidator : AbstractValidator<MyQuery>
{
    public MyQueryValidator() { RuleFor(x => x.Id).GreaterThan(0); }
}

Cache Policy

public class MyCachePolicy : ICachePolicy<MyQuery, MyResponse>
{
    public string GetCacheKey(MyQuery r) => $"my:{r.Id}";
    public TimeSpan? SlidingExpiration => TimeSpan.FromMinutes(5);
    public TimeSpan? AbsoluteExpiration => null;
    public TimeSpan? AbsoluteExpirationRelativeToNow => TimeSpan.FromHours(1);
}

Zasady

  • Wszystkie FluentValidation validators są automatycznie wykrywane przez DI
  • Aby cache działał, zaimplementuj ICachePolicy i zarejestruj (auto-discovery)
  • LoggingBehavior loguje na poziomie DEBUG — włącz odpowiedni log level
  • Każdy request ma unikalne correlation ID w logach ```