Blog Dla Programistów C#/.NET

niedziela, 9 listopada 2025

Zaczynając pracę z ASP.NET Core, łatwo wpaść w typowe pułapki i popełnić błędy, które przerobiło już wielu początkujących. Najlepiej uczyć się na błędach – nie tylko swoich – i dzięki temu pisać lepszy kod. W tym artykule zebrałem 10 najczęstszych pułapek czyhających na nowych programistów ASP.NET Core. Sprawdź, czy sam nie popełniasz któregoś z tych błędów i dowiedz się, jak ich unikać. Dzięki tej wiedzy zaoszczędzisz sobie frustracji i przyspieszysz rozwój swoich umiejętności jako programista C#/.NET.

10 Pułapek w ASP.NET Core, w Które Wpada 9 na 10 Początkujących

Pułapka 1: Zbyt duża logika w kontrolerze


Kontrolery w ASP.NET Core powinny być możliwie "cienkie", czyli zawierać minimalną ilość kodu i logiki niezbędnej do obsługi żądania. Przeładowany logiką kontroler łamie zasadę pojedynczej odpowiedzialności i utrudnia utrzymanie aplikacji. W idealnej sytuacji akcja kontrolera jedynie weryfikuje podstawowe dane (np. czy ModelState jest poprawny), następnie deleguje wykonanie logiki biznesowej do serwisu/warstwy aplikacji i zwraca wynik (widok lub dane). Dzięki takiemu podejściu kontrolery stają się łatwiejsze w czytaniu i testowaniu, a także prostsze w rozbudowie w przyszłości.

Jak unikać? Staraj się przenosić logikę biznesową do oddzielnych klas (np. usług, menedżerów, warstwy domenowej), a w kontrolerze zostaw tylko to, co konieczne do obsługi żądania HTTP. W praktyce często stosuje się wzorce takie jak Services, MediatR czy CQRS, aby utrzymać kontrolery szczupłe.


Pułapka 2: Logika w widoku (Razor)


Umieszczanie logiki aplikacyjnej w warstwie widoku (np. w plikach Razor) to prosta droga do problemów z utrzymaniem kodu. Widok powinien służyć tylko prezentacji danych, a nie ich przetwarzaniu. Jeśli w widoku zaczynasz pisać instrukcje warunkowe, pętle czy wywoływać logikę biznesową, to znak że coś jest nie tak. Taki kod szybko staje się trudny do zrozumienia i tworzy tzw. spaghetti code.

Jak unikać? Całą logikę, która przygotowuje dane do wyświetlenia, umieść w warstwie aplikacji (np. w kontrolerze, serwisie lub ViewModelu), a do widoku przekaż już przetworzone, gotowe dane. Widok Razor powinien otrzymać model danych (lub ViewModel) i na jego podstawie tylko wyrenderować HTML. Dzięki temu szablony widoków pozostaną proste, a logikę łatwiej będzie testować i rozwijać w kodzie C# zamiast w składni Razor.


Pułapka 3: Brak użycia DTO (Data Transfer Objects)


Kolejnym częstym błędem jest zwracanie z aplikacji (do widoku lub poprzez API) pełnych obiektów domenowych zamiast ograniczonych modeli danych. Początkujący często przekazują do widoku cały obiekt np. encję z bazy danych, podczas gdy potrzebna jest tylko część informacji. To niepotrzebnie ujawnia szczegóły implementacyjne i może obciążać aplikację. Dużo lepszą praktyką jest wykorzystanie obiektów DTO – prostych klas transferowych zawierających tylko te pola, które są potrzebne odbiorcy danych. Użytkownik końcowy (czy to strona WWW, czy klient API) i tak nie potrzebuje wszystkich pól z bazy – przekazuj mu wyłącznie to, co konieczne.

Jak unikać? Tworząc warstwę komunikacji (widok, API), zdefiniuj dedykowane klasy DTO lub ViewModel z odpowiednimi polami. W kontrolerze przed zwróceniem wyniku zamapuj (ręcznie lub automatycznie) dane z modelu domenowego do DTO. Dzięki temu masz pełną kontrolę nad tym, co wychodzi z twojej aplikacji na zewnątrz, łatwiej utrzymać kompatybilność API i zabezpieczyć się przed przypadkowym ujawnieniem wrażliwych danych.


Pułapka 4: Złe przekazywanie danych do widoku


ASP.NET Core daje wiele sposobów przekazywania danych z kontrolera do widoku, co początkujących czasem wpędza w maliny. Typowa sytuacja: chcemy przekazać do widoku więcej informacji niż jeden model (np. jakiś dodatkowy komunikat, listy do dropdownów, itp.). Niedoświadczony programista często skorzysta z ViewBag lub ViewData dodając tam luźno powiązane wartości. To działa, ale szybko wprowadza bałagan i ryzyko literówek oraz braku kontroli typów. Dużo lepszym rozwiązaniem jest stworzenie ViewModelu – specjalnej klasy, która zawiera wszystkie potrzebne na widoku dane – i przekazanie do widoku instancji tej klasy. Taki podejście porządkuje kod i zapewnia silne typowanie danych w widoku.

Jak unikać? Zamiast korzystać z wielu pól ViewBag/ViewData, zdefiniuj jedną klasę ViewModel zawierającą właściwości na wszystkie informacje potrzebne w widoku. W kontrolerze utwórz obiekt ViewModel, wypełnij go danymi (np. wynikiem z bazy, listami wyboru, itp.), a następnie przekaż do widoku. W Razorze ustaw ten ViewModel jako model widoku (@model YourViewModel) i korzystaj z jego silnie typowanych właściwości. Kod stanie się czytelniejszy i mniej podatny na błędy.


Pułapka 5: Brak walidacji danych użytkownika


Aplikacja webowa bez solidnej walidacji danych wejściowych prędzej czy później napotka poważne problemy. Nigdy nie ufaj danym od użytkownika – zawsze sprawdzaj ich poprawność po stronie serwera zanim je przetworzysz czy zapiszesz. Brak walidacji może prowadzić do nieprzewidzianych wyjątków (np. gdy pola są puste lub mają zły format) albo wręcz do dziur bezpieczeństwa (np. wstrzyknięcie złośliwego kodu). ASP.NET Core ułatwia walidację dzięki mechanizmom takim jak atrybuty danych ([Required], [Range] etc.) oraz automatyczne sprawdzanie ModelState. Wystarczy z nich skorzystać.

Jak unikać? Zawsze, gdy przyjmujesz dane od użytkownika (formularze, JSON przez API itp.), zdefiniuj reguły walidacji. Możesz użyć wbudowanych atrybutów z przestrzeni System.ComponentModel.DataAnnotations lub skorzystać z biblioteki FluentValidation dla bardziej złożonych scenariuszy. W kontrolerze (szczególnie przy akcjach [HttpPost]) sprawdzaj if (!ModelState.IsValid) ... i reaguj odpowiednio – np. zwróć ten sam widok z komunikatami błędów lub odpowiedź HTTP 400 z informacjami, co jest nie tak. Dzięki temu użytkownik otrzyma jasny komunikat, a twoja aplikacja pozostanie stabilna nawet przy niepoprawnych danych wejściowych.


Pułapka 6: Nieodpowiednie kontrolki formularza


Nawet poprawnie zwalidowane dane mogą sprawiać kłopot, jeśli wymuszasz na użytkowniku niewygodne metody ich wprowadzania. Częstym błędem jest wybór niewłaściwych kontrolek formularza do danych. Na przykład początkujący często każą użytkownikowi wpisywać datę w zwykłym polu tekstowym, co jest niewygodne i podatne na błędy formatowania. Tymczasem ASP.NET (HTML5/Razor) oferuje specjalne kontrolki do takich celów – warto z nich korzystać.

Użycie zwykłego pola tekstowego zmusza użytkownika do ręcznego wpisania daty w odpowiednim formacie, co łatwo może skutkować błędami walidacji lub wprowadzeniem niepoprawnych danych.

Dzięki zastosowaniu w takim przypadku dedykowanej kontrolki wyboru daty (DatePicker)  użytkownik może wygodnie wybrać datę z kalendarza, minimalizując ryzyko pomyłki. Dobieraj kontrolki formularza odpowiednio do typu danych – dla pola daty użyj kontrolki daty (np. DatePicker), dla pól typu true/false wykorzystaj checkbox lub przełącznik, dla liczb możesz użyć pól typu number itp. W ten sposób interakcja z aplikacją będzie bardziej przyjazna, a dane łatwiejsze do poprawnej walidacji po stronie serwera.


Pułapka 7: Nieprawidłowe użycie HttpClient


Korzystanie z HttpClient do wykonywania zapytań HTTP jest powszechne, jednak początkujący często robią to w niewłaściwy sposób. Najczęstsza pułapka to tworzenie nowej instancji HttpClient za każdym razem przy użyciu new HttpClient() lub nawet w bloku using. Może się wydawać, że to poprawne podejście, ale w kontekście aplikacji webowej powoduje dwa poważne problemy. Po pierwsze, częste tworzenie nowych obiektów klienta HTTP i ich niewłaściwe zwalnianie obciąża zasoby – sockets nie są od razu zwalniane, co z czasem może wyczerpać pulę dostępnych połączeń. Po drugie, utrzymywanie HttpClient jako statycznego lub singletonu też bywa zdradliwe (np. kwestia odświeżania DNS).

Jak unikać? ASP.NET Core oferuje wbudowany mechanizm IHttpClientFactory do zarządzania instancjami HttpClient. Zarejestruj fabrykę w Startup/Program (np. services.AddHttpClient(...) dla konkretnych usług) i wstrzykuj do swoich serwisów gotowe, zarządzane przez fabrykę instancje HttpClient. Dzięki temu to framework zadba o ponowne wykorzystanie połączeń i poprawne zwalnianie zasobów, a ty unikniesz opisanych wyżej błędów. Krótko mówiąc – nie twórz HttpClient samodzielnie, pozwól aby robiła to za ciebie fabryka.


Pułapka 8: Wykonywanie długotrwałych zadań podczas obsługi żądania


Wyobraź sobie, że użytkownik wykonuje akcję w twojej aplikacji (np. wypełnia formularz), a po stronie serwera w ramach obsługi tego żądania uruchamiana jest jeszcze dodatkowa, czasochłonna operacja – na przykład generowanie raportu albo wysyłka e-maila z powiadomieniem. Początkujący często implementują to wprost, przez co użytkownik musi czekać, aż serwer wszystko skończy. To potrafi trwać nawet kilkanaście sekund, podczas których aplikacja wydaje się zawieszona. To niepotrzebne opóźnienie – jeśli wynik długiej operacji nie jest od razu potrzebny użytkownikowi, lepiej wykonać ją asynchronicznie w tle, już po zwróceniu odpowiedzi dla użytkownika.

Jak unikać? ASP.NET Core umożliwia uruchamianie zadań w tle na kilka sposobów. Możesz np. skorzystać z mechanizmu Hosted Service (tławe usługi) lub wprost z kolejki zadań tła. Rozwiązanie z BackgroundService polega na dodaniu własnej klasy dziedziczącej po BackgroundService lub użyciu wbudowanej kolejki (IHostedService). W praktyce: po otrzymaniu żądania HTTP szybko zwróć wynik użytkownikowi (np. komunikat "Zadanie przyjęte do realizacji"), a ciężką pracę zleć procesowi w tle. Dzięki temu request użytkownika nie będzie wisiał bez potrzeby, a aplikacja nadal wykona swoje zadanie. Użytkownik może zostać poinformowany o wyniku np. innym kanałem (email) lub przy kolejnym odświeżeniu strony. Podsumowując – oddziel długotrwałe operacje od bieżącego żądania, by nie blokować użytkownika i wątków serwera.


Pułapka 9: Ignorowanie wstrzykiwania zależności (Dependency Injection)


ASP.NET Core od podstaw wspiera Dependency Injection (DI), czyli wstrzykiwanie zależności, jednak początkujący czasem pomijają ten mechanizm i nadal tworzą obiekty "ręcznie" tam, gdzie nie trzeba. Przykładowo, w kontrolerze samodzielnie inicjują klasę serwisu zamiast ją wstrzyknąć. Takie podejście prowadzi do silnego powiązania kodu (ciężko podmienić zależność na inną implementację) i utrudnia testowanie – nie da się łatwo zamockować zależności, skoro są zahardkodowane w kodzie. Traci się też zalety zarządzania cyklem życia obiektów (transient/scoped/singleton) przez kontener DI.

Jak unikać? Wykorzystaj wbudowany kontener IoC w ASP.NET Core. Rejestruj swoje serwisy w Program.cs/Startup.cs (metoda Services.AddScoped/AddTransient/AddSingleton) zgodnie z potrzebnym zakresem żywotności, a następnie wstrzykuj je przez konstruktor tam, gdzie są potrzebne. Przykładowo, zamiast: 

var _repo = new ProductRepository(); 

wewnątrz kontrolera, zrób wstrzykiwanie przez konstruktor:

public ProductController(IProductRepository repo)
{
_repo = repo;
}

Kontener zadba o dostarczenie właściwej instancji. Kod stanie się luźniej powiązany, bardziej modularny i testowalny. Warto pamiętać, że w ASP.NET Core wszystko jest już skonfigurowane pod DI – nawet kontrolery mogą mieć zależności w konstruktorze, bo framework automatycznie je uzupełnia.


Pułapka 10: Brak logowania i globalnej obsługi błędów


Nawet doświadczonym programistom zdarzają się błędy w aplikacji – kluczowe jest to, jak sobie z nimi radzimy. Początkujący często nie implementują porządnego logowania i obsługi wyjątków, przez co w razie problemów aplikacja "sypie się" bez żadnego śladu lub prezentuje użytkownikom techniczny komunikat błędu. Brak logowania oznacza, że nie wiemy, co poszło nie tak na produkcji – diagnozowanie problemów staje się wtedy strzelaniem w ciemno. Z kolei brak globalnej obsługi błędów (np. strony błędów) może skutkować ujawnieniem wrażliwych informacji o aplikacji lub po prostu kiepskim doświadczeniem użytkownika.

Jak unikać? Włącz i skonfiguruj mechanizm logowania w ASP.NET Core. Framework posiada wbudowany logger (ILogger), który łatwo podłączyć – domyślnie logi są wypisywane do konsoli, ale warto skorzystać z bardziej rozbudowanych narzędzi jak Serilog czy NLog do logowania do plików, baz danych lub systemów monitorowania. Loguj istotne informacje, ostrzeżenia oraz błędy – dzięki temu w razie awarii przejrzysz logi i znajdziesz przyczynę. Ponadto, skonfiguruj globalny handler błędów: w środowisku produkcyjnym aplikacja nie powinna wyświetlać szczegółów wyjątku użytkownikowi. Upewnij się, że w Program.cs masz coś w stylu: 

if (!app.Environment.IsDevelopment()) 
{
app.UseExceptionHandler("/Error"); ...
}

Domyślny Developer Exception Page włączaj tylko lokalnie podczas developmentu – zapobiegniesz w ten sposób ujawnianiu stack trace'ów i danych debugowych. Zadbaj o przyjazną stronę błędu dla użytkownika oraz logowanie szczegółów wyjątku na zapleczu. Dzięki temu twoja aplikacja będzie bardziej profesjonalna i odporna na niespodzianki.


Podsumowanie


Początki z ASP.NET Core mogą być trudne, ale znając powyższe pułapki, masz szansę ich uniknąć. Każdy programista uczy się na błędach – ważne, by wyciągać wnioski i ciągle doskonalić swoje umiejętności. Stosując dobre praktyki (małe kontrolery, logika poza widokami, walidacja danych, DI, itd.), szybciej stworzysz aplikacje lepszej jakości i zaoszczędzisz sobie wielu frustracji.

Na koniec, jeśli na co dzień tworzyć lub chcesz tworzyć niezawodne aplikacje ASP.NET Core (zarówno MVC jak i Web API), to rozważ dołączenie do dobrej jakości szkolenia online, takiego jak "Szkoła ASP.NET Core". Znajdziesz tam ustrukturyzowaną wiedzę, praktyczne projekty i mentorskie wsparcie, dzięki czemu bezpiecznie ominiesz większość typowych błędów początkujących. 

Autor artykułu:
Kazimierz Szpin
Kazimierz Szpin
CTO & Founder - FindSolution.pl
Programista C#/.NET. Specjalizuje się w Blazor, ASP.NET Core, ASP.NET MVC, ASP.NET Web API, WPF oraz Windows Forms.
Autor bloga ModestProgrammer.pl
Dodaj komentarz

Wyszukiwarka

© Copyright 2025 modestprogrammer.pl | Sztuczna Inteligencja | Regulamin | Polityka prywatności. Design by Kazimierz Szpin. Wszelkie prawa zastrzeżone.