Middleware w ASP.NET Core - jak działa potok żądań?

Bruno Krawczyk 24 lipca 2026
Obsługa żądań w ASP.NET Core z wykorzystaniem middleware. Dowiedz się, middleware co to jest i jak działa.

Spis treści

Kiedy aplikacja webowa zaczyna obsługiwać logowanie, błędy, nagłówki HTTP, CORS i logowanie zdarzeń, szybko pojawia się pytanie: middleware co to jest i dlaczego tak często mówi się o nim w .NET? To warstwa, która przechwytuje żądanie po drodze do właściwego kodu aplikacji, wykonuje określone zadania i może zmodyfikować także odpowiedź. Pokażę, jak działa ten mechanizm, gdzie naprawdę pomaga i jakie błędy najczęściej komplikują jego użycie.

Middleware porządkuje obsługę żądań w aplikacji webowej

  • Middleware działa pomiędzy klientem a kodem obsługującym endpoint.
  • Każdy element może wykonać kod przed i po wywołaniu kolejnego elementu potoku.
  • Typowe zastosowania to uwierzytelnianie, logowanie, obsługa błędów, CORS i kontrola dostępu.
  • Kolejność rejestracji middleware ma bezpośredni wpływ na działanie aplikacji.
  • Middleware nie zastępuje logiki biznesowej ani filtrów przypisanych do konkretnego kontrolera.

Middleware to warstwa pomiędzy żądaniem a aplikacją

Najprościej wyobrazić sobie middleware jako serię bramek, przez które przechodzi każde żądanie HTTP. Jedna bramka sprawdza, czy połączenie korzysta z HTTPS, druga zapisuje informacje do logów, kolejna rozpoznaje użytkownika, a ostatnia przekazuje żądanie do kontrolera lub endpointu.

Technicznie middleware jest komponentem, który otrzymuje obiekt żądania i odpowiedzi, zwykle reprezentowany przez HttpContext. Może wykonać własny kod, przekazać sterowanie dalej albo zakończyć obsługę bez uruchamiania kolejnych elementów.

To właśnie odróżnia middleware od zwykłej metody pomocniczej. Komponent działa na poziomie całego potoku HTTP, więc może objąć wiele endpointów jednocześnie. Dzięki temu nie trzeba kopiować tego samego kodu do każdego kontrolera.

Co dzieje się z żądaniem

Przepływ zazwyczaj wygląda tak:

  1. Klient wysyła żądanie HTTP.
  2. Pierwszy middleware odczytuje żądanie i wykonuje własną logikę.
  3. Komponent wywołuje kolejny element potoku.
  4. Żądanie trafia do endpointu, który generuje odpowiedź.
  5. Middleware mogą jeszcze zmienić odpowiedź przed wysłaniem jej do klienta.

Ten model pozwala obsługiwać zdarzenia w dwóch kierunkach. Kod umieszczony przed wywołaniem kolejnego komponentu działa podczas wejścia żądania, a kod po tym wywołaniu może zmierzyć czas odpowiedzi, dodać nagłówek albo zareagować na rezultat.

Jak działa potok middleware w aplikacji webowej

W ASP.NET Core aplikacja buduje potok przetwarzania żądań. Każdy element zna następny komponent, dlatego kolejność dodawania usług nie jest kosmetyką, lecz częścią logiki aplikacji.

app.Use(async (context, next) =>
{
    var start = DateTime.UtcNow;

    await next();

    var elapsed = DateTime.UtcNow - start;
    Console.WriteLine($"Czas obsługi: {elapsed.TotalMilliseconds} ms");
});

W tym przykładzie middleware mierzy czas obsługi. Najpierw zapamiętuje moment rozpoczęcia, potem wywołuje next(), a po zakończeniu dalszej obsługi oblicza czas całego żądania. To prosty przykład, ale dobrze pokazuje najważniejszą zasadę.

Middleware może zatrzymać żądanie

Nie każdy komponent musi wywołać następny. Jeśli użytkownik nie ma wymaganych uprawnień, middleware autoryzacyjny może zwrócić odpowiedź 401 lub 403 i zakończyć potok. Podobnie działa obsługa limitu zapytań, blokowanie niebezpiecznych żądań czy szybkie zwracanie odpowiedzi z pamięci podręcznej.

Taki mechanizm nazywa się często short-circuiting, czyli przerwaniem potoku. Trzeba używać go świadomie, bo przypadkowe zakończenie obsługi może sprawić, że routing, kontroler albo zapis logów już się nie wykonają.

Kolejność ma praktyczne znaczenie

Przykładowo uwierzytelnianie powinno poprzedzać autoryzację. Jeśli aplikacja sprawdzi uprawnienia, zanim rozpozna użytkownika, wynik będzie nieprawidłowy. Z kolei middleware obsługujący błędy powinien znajdować się odpowiednio wcześnie, aby mógł przechwycić wyjątki powstałe dalej w potoku.

W praktyce często spotyka się układ, w którym wcześniej pojawiają się obsługa wyjątków i przekierowanie do HTTPS, a później routing, uwierzytelnianie, autoryzacja i endpointy. Dokładna konfiguracja zależy od typu aplikacji, ale zasada pozostaje stała: elementy wcześniejsze wpływają na wszystkie kolejne.

Do czego wykorzystuje się middleware

Największą wartość middleware widać wtedy, gdy jedna reguła dotyczy wielu żądań. Zamiast implementować ją osobno w kontrolerach, umieszczam ją w jednym komponencie i jasno określam, gdzie ma działać.

Zastosowanie Co robi middleware Praktyczna korzyść
Obsługa wyjątków Przechwytuje błędy i zwraca spójny komunikat Klient nie otrzymuje szczegółów implementacji
Logowanie Zapisuje metodę, ścieżkę, status i czas odpowiedzi Łatwiej znaleźć wolne lub wadliwe endpointy
Uwierzytelnianie Rozpoznaje użytkownika na podstawie tokenu lub ciasteczka Kolejne elementy mogą korzystać z tożsamości
CORS Kontroluje, z jakich domen można wywoływać API Przeglądarka respektuje ustalone reguły dostępu
Nagłówki bezpieczeństwa Dodaje między innymi reguły ochrony przeglądarki Zmniejsza ryzyko typowych ataków webowych
Rate limiting Ogranicza liczbę żądań w określonym czasie Chroni API przed nadużyciem i przeciążeniem

Middleware dobrze nadaje się również do korelacji żądań. Aplikacja może nadać każdemu żądaniu identyfikator, a potem umieścić go w logach wszystkich usług. Przy systemie składającym się z API, kolejki i kilku usług taki correlation ID często oszczędza więcej czasu niż rozbudowany panel monitoringu.

Nie używałbym jednak middleware do każdej reguły. Jeśli logika dotyczy wyłącznie jednego endpointu, umieszczenie jej w globalnym potoku może utrudnić zrozumienie kodu. Middleware powinien obsługiwać przekrojowe problemy, a nie zastępować całą logikę biznesową.

Middleware w ASP.NET Core i aplikacjach .NET

W ASP.NET Core middleware można dodać za pomocą gotowych metod Use..., komponentu kończącego potok Run albo rozgałęzienia Map. Framework dostarcza wiele gotowych elementów, dlatego własny middleware warto pisać dopiero wtedy, gdy istniejące rozwiązania nie wystarczają.

app.UseExceptionHandler("/error");
app.UseHttpsRedirection();
app.UseAuthentication();
app.UseAuthorization();

app.MapControllers();

Ten fragment pokazuje typowy kierunek konfiguracji. Najpierw aplikacja przygotowuje bezpieczny transport i obsługę błędów, później rozpoznaje użytkownika oraz sprawdza jego uprawnienia, a na końcu przekazuje żądanie do kontrolerów.

Przeczytaj również: SignalR w ASP.NET Core - jak działa i kiedy go użyć

Własny komponent powinien mieć jedną odpowiedzialność

Dobry middleware robi jedną rzecz i robi ją przewidywalnie. Przykładowo komponent logujący nie powinien jednocześnie walidować danych, odpytywać bazy i podejmować decyzji biznesowych. Im więcej odpowiedzialności trafia do jednego elementu, tym trudniej go testować i bezpiecznie przestawiać w potoku.

W aplikacjach korzystających z Blazor Server middleware nadal działa na poziomie żądań HTTP, ale nie obsługuje każdej interakcji z komponentem tak samo jak klasyczne API. Po zestawieniu połączenia część komunikacji odbywa się przez trwały kanał, dlatego monitoring i autoryzację trzeba projektować z uwzględnieniem cyklu życia połączenia.

To ważne rozróżnienie. Middleware jest świetny do ochrony i obserwowania wejścia do aplikacji, ale nie powinien być jedynym miejscem, w którym zakłada się poprawność uprawnień. Reguły dostępu muszą być sprawdzane również tam, gdzie faktycznie wykonywana jest operacja.

Middleware, filtry i endpointy nie są tym samym

Te mechanizmy bywają wrzucane do jednego worka, ponieważ wszystkie mogą wykonać kod przed obsługą żądania. Różnią się jednak zakresem działania i momentem uruchomienia.

Mechanizm Zakres Kiedy go wybrać
Middleware Cały potok HTTP lub jego gałąź Logowanie, błędy, CORS, uwierzytelnianie
Filtr MVC Kontrolery, akcje lub ich grupy Reguły związane z wykonaniem akcji
Endpoint Konkretny adres i operacja Logika biznesowa oraz odpowiedź dla klienta
DelegatingHandler Wywołania wychodzące przez HttpClient Tokeny, retry i logowanie połączeń z innymi API

Przykład jest prosty: rejestrowanie czasu każdego żądania pasuje do middleware, a sprawdzenie konkretnego modelu wejściowego lepiej umieścić bliżej endpointu lub w filtrze. Takie rozdzielenie poprawia czytelność i ogranicza efekt uboczny, w którym niewielka zmiana wpływa na całą aplikację.

Podobny problem pojawia się przy diagnozowaniu błędów po stronie przeglądarki. Middleware może poprawnie zwrócić dane, ale nie naprawi literówki w kodzie frontendu. Przy analizie takich przypadków przydatne są również materiały o błędach wielkości liter w JavaScript, ponieważ problem często leży poza serwerowym potokiem.

Jak uniknąć problemów z middleware

Najczęstszy błąd polega na dodawaniu kolejnych komponentów bez sprawdzania ich wpływu na całą ścieżkę żądania. Każdy middleware zwiększa koszt obsługi, choć zwykle jest to niewielki narzut. Jeśli jednak komponent wykonuje zapytania do bazy, koszt może stać się odczuwalny przy dużym ruchu.

  • Nie blokuj kodu asynchronicznego przez niepotrzebne użycie .Result lub .Wait().
  • Nie zapisuj danych wrażliwych do logów, szczególnie tokenów, haseł i pełnych danych osobowych.
  • Nie zakładaj konkretnej kolejności, jeśli komponent ma działać w wielu aplikacjach.
  • Nie ukrywaj błędów za ogólnym statusem 500 bez identyfikatora pozwalającego odnaleźć zdarzenie w logach.
  • Nie wykonuj ciężkich operacji dla każdego żądania, jeśli można użyć cache albo przenieść pracę do tła.

Własny middleware warto testować co najmniej w trzech scenariuszach: poprawne przejście do następnego elementu, przerwanie potoku oraz wyjątek powstały dalej. Sprawdzam również, czy odpowiedź ma właściwy status, czy nagłówki nie są nadpisywane i czy komponent działa poprawnie przy żądaniach bez uwierzytelnienia.

Dużą różnicę robi też obserwowalność. Sam komunikat „błąd serwera” niewiele mówi, dlatego log powinien zawierać identyfikator żądania, ścieżkę, status i czas obsługi. Nie trzeba logować całego ciała żądania, bo często zwiększa to ryzyko wycieku danych bez realnej korzyści diagnostycznej.

Prosta reguła oceny, czy middleware ma sens

Jeżeli dana reguła dotyczy wielu endpointów, działa na poziomie HTTP i powinna być wykonywana według stałej kolejności, middleware jest zwykle dobrym wyborem. Jeżeli dotyczy jednej operacji, modelu biznesowego albo konkretnego kontrolera, lepiej umieścić ją bliżej miejsca, którego naprawdę dotyczy.

Najważniejsza rzecz nie polega na samym poznaniu definicji. Trzeba rozumieć, że middleware jest łańcuchem odpowiedzialności, a każda nowa bramka wpływa na czas, bezpieczeństwo i sposób diagnozowania aplikacji. Dobrze zaprojektowany potok upraszcza kod, natomiast przypadkowo zbudowany szybko staje się ukrytą warstwą problemów.

FAQ - Najczęstsze pytania

Kolejność rejestracji określa, które komponenty przetworzą żądanie jako pierwsze. Uwierzytelnianie powinno poprzedzać autoryzację, a obsługa wyjątków powinna znajdować się odpowiednio wcześnie, aby przechwycić błędy powstałe dalej w potoku.

Middleware może zakończyć obsługę, gdy na przykład użytkownik nie ma uprawnień, żądanie przekracza limit albo odpowiedź znajduje się w pamięci podręcznej. W takiej sytuacji może zwrócić status 401 lub 403, a kolejne elementy, w tym routing i kontroler, nie zostaną uruchomione.

Middleware działa w całym potoku HTTP lub jego gałęzi i nadaje się do logowania, CORS czy obsługi błędów. Filtr MVC dotyczy kontrolerów lub akcji, natomiast endpoint obsługuje konkretny adres i zawiera logikę biznesową oraz odpowiedź dla klienta.

Warto zapisywać identyfikator żądania, ścieżkę, status odpowiedzi i czas obsługi. Nie należy logować tokenów, haseł, pełnych danych osobowych ani całego ciała żądania, jeśli nie jest to konieczne diagnostycznie.

Oceń artykuł

Ocena: 0.00 Liczba głosów: 0

Tagi

middleware
asp.net core
cors
uwierzytelnianie
autoryzacja
Autor Bruno Krawczyk
Bruno Krawczyk
Mam na imię Bruno i od 8 lat zgłębiam tajniki programowania w ekosystemie .NET, chmury Azure oraz sztucznej inteligencji. Moja przygoda z technologią zaczęła się od ciekawości, jak złożone systemy mogą ułatwiać codzienne życie i rozwiązywać realne problemy. Dziś moją misją jest dzielenie się tą wiedzą, starając się przybliżyć nawet najbardziej skomplikowane zagadnienia w sposób zrozumiały i przystępny dla każdego. W moich artykułach na kursdotnet.pl skupiam się na praktycznych aspektach, analizuję najnowsze trendy i weryfikuję informacje, aby dostarczyć Wam treści, które są nie tylko dokładne i aktualne, ale przede wszystkim użyteczne w Waszej własnej ścieżce rozwoju technologicznego.

Udostępnij artykuł

Napisz komentarz