C# Academy · Lekcja

Zachowania potoku

Dodawaj logikę przekrojową za pomocą zachowań.

Lekcja 3 z 413 kroki

Zachowania potoku to bezpłatna lekcja C# Academy na CoddyKit. To lekcja 3 z 4. Możesz przeczytać całą lekcję poniżej za darmo — a potem ćwiczyć ją interaktywnie w przeglądarce z wbudowanym edytorem kodu i tutorem AI dostępnym 24/7. To część ścieżki edukacyjnej C# Academy, a Twój postęp synchronizuje się między webem a aplikacją CoddyKit. Kurs C# Academy zawiera 4 lekcji w sumie.

Aspekty przekrojowe

Logowanie, walidacja, pomiary czasu i transakcje dotyczą wielu handlerów. Powielanie tego kodu w każdym handlerze jest monotonne i podatne na błędy.

Zachowania pipeline'u MediatR pozwalają otoczyć każdy request wspólną logiką.

// One behavior runs around all handlers

IPipelineBehavior

Zachowanie implementuje IPipelineBehavior<TRequest, TResponse>. Jego metoda Handle otrzymuje request oraz delegat next, który wywołuje pozostałą część pipeline'u.

public class LoggingBehavior<TRequest, TResponse>
    : IPipelineBehavior<TRequest, TResponse>
    where TRequest : notnull
{
    public async Task<TResponse> Handle(
        TRequest request,
        RequestHandlerDelegate<TResponse> next,
        CancellationToken ct)
    {
        // before
        var response = await next();
        // after
        return response;
    }
}

Delegat next

next() wywołuje kolejne zachowanie albo właściwy handler, jeśli jest to ostatni element. Kod przed wywołaniem działa podczas przechodzenia w głąb pipeline'u, a kod po wywołaniu - podczas powrotu.

// [Behavior A in] -> [Behavior B in] -> [Handler]
//               <- [Behavior B out] <- [A out]

Zachowanie rejestrujące

Konkretne zachowanie rejestrujące zapisuje nazwę requestu przy wejściu oraz czas, który upłynął, przy wyjściu.

public async Task<TResponse> Handle(
    TRequest request,
    RequestHandlerDelegate<TResponse> next,
    CancellationToken ct)
{
    var name = typeof(TRequest).Name;
    _logger.LogInformation("Handling {Name}", name);
    var sw = Stopwatch.StartNew();
    var response = await next();
    _logger.LogInformation("{Name} took {Ms}ms", name, sw.ElapsedMilliseconds);
    return response;
}

Rejestrowanie zachowania

Należy zarejestrować otwarte zachowanie generyczne w DI. MediatR zastosuje je do każdego requestu.

builder.Services.AddTransient(
    typeof(IPipelineBehavior<,>),
    typeof(LoggingBehavior<,>));

Zachowanie walidujące

Popularnym zastosowaniem jest walidacja requestów za pomocą FluentValidation. Zachowanie uruchamia wszystkie walidatory przed wykonaniem handlera i zgłasza wyjątek, jeśli którykolwiek z nich zakończy się niepowodzeniem.

public async Task<TResponse> Handle(
    TRequest request,
    RequestHandlerDelegate<TResponse> next,
    CancellationToken ct)
{
    var context = new ValidationContext<TRequest>(request);
    var failures = _validators
        .Select(v => v.Validate(context))
        .SelectMany(r => r.Errors)
        .Where(f => f is not null)
        .ToList();
    if (failures.Count != 0)
        throw new ValidationException(failures);
    return await next();
}

Przerywanie pipeline'u

Zachowanie może całkowicie pominąć handler, zwracając wynik bez wywołania next() - jest to przydatne przy buforowaniu wyników zapytań lub odrzucaniu nieprawidłowych requestów.

if (_cache.TryGet(key, out TResponse cached))
    return cached;          // handler never runs
var response = await next();
_cache.Set(key, response);
return response;

Kolejność zachowań

Zachowania są wykonywane w kolejności rejestracji. Należy umieścić logowanie najbardziej na zewnątrz, następnie walidację, a potem transakcje, aby każde zachowanie prawidłowo otaczało kolejne.

services.AddTransient(typeof(IPipelineBehavior<,>), typeof(LoggingBehavior<,>));
services.AddTransient(typeof(IPipelineBehavior<,>), typeof(ValidationBehavior<,>));
services.AddTransient(typeof(IPipelineBehavior<,>), typeof(TransactionBehavior<,>));

Zachowanie transakcyjne

Należy objąć handlery komend transakcją bazy danych, aby cała operacja została atomowo zatwierdzona albo wycofana.

await using var tx = await _db.Database.BeginTransactionAsync(ct);
try
{
    var response = await next();
    await tx.CommitAsync(ct);
    return response;
}
catch
{
    await tx.RollbackAsync(ct);
    throw;
}

Stosowanie tylko do określonych requestów

Należy użyć interfejsu znacznikowego i ograniczenia generycznego, aby zachowanie dotyczyło tylko requestów, które wyraźnie je włączają - na przykład tylko komendy mogą otrzymywać obsługę transakcji.

public interface ITransactional { }
public record CreateOrderCommand(...) : IRequest<int>, ITransactional;

// where TRequest : ITransactional

Dlaczego zachowania są lepsze od middleware

W przeciwieństwie do middleware zachowania uruchamiają się dla każdej wiadomości, mają dostęp do typowanego requestu i odpowiedzi oraz działają nawet wtedy, gdy request jest przekazywany poza HTTP, np. z zadania w tle.

// Strongly typed, transport-independent cross-cutting logic

Szybki test

Proszę potwierdzić sposób działania zachowań.

Podsumowanie

Poznali Państwo zachowania pipeline'u:

  • IPipelineBehavior<TRequest, TResponse> otacza każdy request wspólną logiką.
  • Delegat next przesuwa request dalej w pipeline'ie; pominięcie go przerywa działanie handlera.
  • Typowe zastosowania to logowanie, walidacja, transakcje i buforowanie.
  • Zachowania są wykonywane w kolejności rejestracji i są silnie typowane.

Następnie: powiadomienia i zdarzenia.

Bezpłatny start

Ucz się C# dzięki korepetycjom AI — za darmo

Pisz i uruchamiaj kod w przeglądarce, otrzymuj natychmiastową pomoc od korepetytora AI dostępnego 24/7 i kontynuuj naukę w sieci lub w aplikacji.

Kursy
93
Lekcje
346

Często zadawane pytania

Czy lekcja „Zachowania potoku” jest bezpłatna?

Tak — pełny tekst „Zachowania potoku” jest dostępny za darmo tutaj w sieci. Aby ćwiczyć ją interaktywnie (wbudowany edytor kodu i tutor AI dostępny 24/7) i odblokować resztę kursu C# Academy, przejdź na CoddyKit PRO. Kurs C# Academy zawiera 4 lekcji w sumie.

Co nauczysz się w „Zachowania potoku”?

Dodawaj logikę przekrojową za pomocą zachowań. Ćwiczysz C# Academy z praktycznym kodem, który uruchamiasz bezpośrednio w przeglądarce, a tutor AI dostępny 24/7 odpowiada na Twoje pytania podczas pracy nad lekcją.

Czy potrzebuję doświadczenia, aby zacząć C# Academy?

Nie wymagamy żadnego doświadczenia. C# Academy w CoddyKit jest strukturyzowany dla początkujących i zaawansowanych użytkowników, więc możesz zacząć tutaj lub od początku i uczyć się w swoim tempie. To lekcja 3 z 4.

Ile czasu zajmuje lekcja „Zachowania potoku”?

Większość lekcji CoddyKit trwa około 5–10 minut. Każda lekcja to mały, interaktywny krok, dzięki czemu robisz systematyczne postępy i zawsze wracasz dokładnie do tego samego miejsca — na webie i w aplikacji.

Czy mogę pisać i uruchamiać kod w tej lekcji C# Academy?

Tak. Każda lekcja C# Academy zawiera wbudowany edytor kodu, więc piszesz i uruchamiasz prawdziwy kod bezpośrednio w przeglądarce i od razu otrzymujesz sprzężenie zwrotne od AI — bez konfiguracji na komputerze.

Wszystkie lekcje w tym kursie

  1. Koncepcje CQRS
  2. Polecenia i programy obsługi z MediatR
  3. Zachowania potoku
  4. Powiadomienia i zdarzenia
← Powrót do C# Academy