Web API stanowi fundament współczesnych aplikacji, które mogą działać zarówno na stronach internetowych, jak i w aplikacjach mobilnych. W ramach platformy ASP.NET Core 9, tworzenie takich API staje się prostsze, a jednocześnie bardziej wydajne dzięki dostępności wielu narzędzi i frameworków. W tej części książki przyjrzymy się kluczowym koncepcjom związanym z budowaniem API, zasadom, które należy przestrzegać oraz najlepszym praktykom w tym zakresie.

Tworzenie usług biznesowych poprzez API, czyli pojęcie Business as a Service (BaaS), to jeden z kluczowych trendów współczesnej inżynierii oprogramowania. Główne założenie tego podejścia jest takie, że logika biznesowa, zasady i reguły działania aplikacji są zarządzane centralnie, niezależnie od tego, czy aplikacja działa w przeglądarkach internetowych, na urządzeniach mobilnych, czy w innych aplikacjach. Taki sposób organizacji pozwala na efektywne zarządzanie zmianami i umożliwia łatwą integrację z różnymi platformami, zapewniając jednocześnie spójność działania systemu. W tym kontekście web API pełnią rolę interfejsu do komunikacji z usługą, udostępniając ją różnym aplikacjom.

Wspomniany proces zarządzania logiką biznesową w jednym miejscu jest możliwy dzięki wykorzystaniu modelu REST (Representational State Transfer), który stanowi bazę dla wielu nowoczesnych rozwiązań API. REST to styl architektoniczny, który promuje stateless (bezwzględną niezależność) oraz skalowalność usług internetowych. Dzięki stosowaniu prostych, ale skutecznych metod HTTP, możliwe jest zrealizowanie podstawowych operacji na zasobach, takich jak ich tworzenie, odczyt, modyfikowanie i usuwanie (CRUD).

Ważnym elementem, który pomaga w efektywnej wymianie danych między klientem a serwerem, są tzw. metody HTTP, zwane także czasem „czasownikami HTTP”. Każda z metod definiuje rodzaj operacji na zasobach, który chcemy wykonać. Do najczęściej używanych należą:

  • GET – używana do pobierania danych, na przykład gdy chcemy uzyskać listę użytkowników.

  • POST – służy do tworzenia nowych zasobów na serwerze.

  • PUT – pozwala na aktualizowanie zasobów, np. zmiana danych użytkownika.

  • DELETE – służy do usuwania zasobów.

  • PATCH – stosowana do częściowej modyfikacji istniejących zasobów.

Odpowiedni dobór metod HTTP jest kluczowy dla przejrzystości i efektywności integracji systemów, co ułatwia zarówno rozwój aplikacji, jak i przyszłe zmiany. Chociaż nie ma jednej „sztywnej” zasady co do wyboru metody w każdym przypadku, warto dążyć do jak najdokładniejszego odzwierciedlenia intencji operacji na danych w wybranej metodzie.

Zasady stosowania protokołu REST

W kontekście projektowania RESTful API, jednym z głównych założeń jest komunikacja stateless, co oznacza, że każdy żądanie wysyłane przez klienta do serwera musi zawierać wszystkie informacje potrzebne do przetworzenia tego żądania. Serwer nie przechowuje żadnych informacji o stanie klienta między kolejnymi żądaniami. Taki sposób komunikacji pozwala na łatwiejszą skalowalność oraz utrzymanie systemu.

Dodatkowo, w modelu REST każdemu zasobowi przypisywana jest unikalna lokalizacja w postaci URL. Zasoby te mogą przybierać formę obiektów fizycznych, konceptualnych lub po prostu danych, a dostęp do nich odbywa się poprzez odpowiednie wywołanie metod HTTP. Wszelkie operacje CRUD wykonywane są za pomocą tych metod, co zapewnia spójność i jednoznaczność API.

Kolejnym aspektem RESTful API są kody odpowiedzi HTTP, które pozwalają na komunikowanie wyników wykonania danego żądania. Statusy odpowiedzi są zgrupowane w pięciu głównych klasach:

  • 100-199: odpowiedzi informacyjne,

  • 200-299: odpowiedzi sukcesu,

  • 300-399: odpowiedzi przekierowań,

  • 400-499: odpowiedzi błędów klienta,

  • 500-599: odpowiedzi błędów serwera.

Poprawne stosowanie kodów statusu pozwala na odpowiednią obsługę sytuacji wyjątkowych i usprawnia integrację API z innymi systemami.

Korzystanie z narzędzi do testowania API

Aby efektywnie testować i sprawdzać działanie API, warto korzystać z narzędzi takich jak Postman. Dzięki temu narzędziu możliwe jest szybkie sprawdzenie, czy nasze API działa zgodnie z oczekiwaniami, czy poprawnie obsługuje różne metody HTTP oraz jak reaguje na różne kody błędów. Zainstalowanie i skonfigurowanie Postman jest bezpłatne, a jego interfejs jest intuicyjny, co pozwala na łatwą weryfikację działania API na każdym etapie jego tworzenia.

Korzystanie z takich narzędzi jest również przydatne w późniejszej fazie integracji, gdy API musi być testowane w kontekście innych systemów, które będą je wykorzystywać. Możliwość ścisłej kontroli parametrów wysyłanych w żądaniach, jak również monitorowania odpowiedzi, jest niezbędna, by upewnić się, że API spełnia wszystkie wymagania funkcjonalne i techniczne.

Aspekty bezpieczeństwa

Warto pamiętać, że tworzenie i udostępnianie web API wiąże się również z koniecznością zapewnienia odpowiedniego poziomu bezpieczeństwa. W szczególności istotne jest zarządzanie autentykacją i autoryzacją, co zapewnia, że tylko upoważnieni użytkownicy mogą korzystać z określonych zasobów. Standardowe metody, takie jak OAuth, JWT (JSON Web Tokens) czy Basic Authentication, są powszechnie stosowane do zapewnienia odpowiedniego poziomu ochrony.

Bezpieczne komunikowanie się z API powinno również obejmować stosowanie HTTPS, by zaszyfrować dane przesyłane między klientem a serwerem, zapobiegając ich przechwyceniu przez osoby trzecie.

Jak działa komunikacja w czasie rzeczywistym za pomocą SignalR na przykładzie TaskManagerHub?

Implementacja komunikacji w czasie rzeczywistym między klientem a serwerem za pomocą SignalR opiera się na klasie Hub, która jest podstawą do obsługi połączeń i interakcji. W przykładowym projekcie TaskManagerHub dziedziczy po klasie Hub, dzięki czemu automatycznie uzyskuje dostęp do mechanizmów zarządzania połączeniami i przesyłania danych. Dwie główne metody tej klasy – CreateTask oraz CompleteTask – są wywoływane przez klientów i jednocześnie pozwalają na wysyłanie informacji do wszystkich podłączonych klientów. Parametrem obu metod jest obiekt klasy TaskModel, który stanowi model reprezentujący zadanie, zawierający unikalny identyfikator, nazwę zadania oraz status jego ukończenia.

Model TaskModel jest prostą klasą posiadającą kilka właściwości i konstruktorów ułatwiających tworzenie instancji z różnymi danymi. Kluczową kwestią jest, że zadania przesyłane między klientem a serwerem są serializowane do formatu JSON, co umożliwia ich łatwą transmisję w postaci tekstowej przez protokół WebSocket lub inne dostępne strategie transportu. Warto zwrócić uwagę, że SignalR nie obsługuje przesyłania danych binarnych, takich jak obrazy czy dźwięki – komunikacja ogranicza się do tekstu.

W implementacji metody CreateTask występują dwa istotne elementy: zapisywanie zadania w repozytorium oraz powiadamianie wszystkich klientów o nowym zadaniu za pomocą metody SendAsync. Ta metoda jest kluczowa, ponieważ umożliwia wywołanie określonej metody po stronie klienta (tu reprezentowanej przez stałą ClientConstants.NOTIFY_TASK_MANAGER), dostarczając jednocześnie aktualne dane zadania. Korzystanie z nazw metod zapisanych w stałych zamiast w postaci tekstowych literałów to dobre praktyki programistyczne, które zapobiegają błędom literowym i ułatwiają późniejszą konserwację kodu.

Konfiguracja serwera wymaga dodania odpowiednich usług SignalR do kontenera aplikacji oraz zmapowania endpointu Huba w pliku Program.cs. Ważne jest zachowanie kolejności, ponieważ wywołanie AddSignalR musi poprzedzać budowę aplikacji, a MapHub powinno być wykonane po zmapowaniu stron Razor. Endpoint Huba definiuje się analogicznie do standardowych endpointów REST API, co umożliwia klientowi ustanowienie połączenia poprzez znany adres URL. Klient z kolei korzysta z JavaScriptowego SDK SignalR, co pozwala na bezpośrednią komunikację i obsługę zdarzeń w czasie rzeczywistym.

Na poziomie klienta, w projekcie wykorzystującym Razor Pages, interakcje realizowane są poprzez prostą stronę HTML z formularzem do dodawania zadań i dwoma listami wyświetlającymi zadania w statusie „nieukończone” oraz „ukończone”. Brak konieczności zmian w pliku kodu C# po stronie klienta świadczy o tym, że cała logika komunikacji i synchronizacji z serwerem realizowana jest w JavaScript. To rozwiązanie ułatwia zrozumienie podstawowych mechanizmów SignalR i pozwala skupić się na interakcji w czasie rzeczywistym.

Należy mieć na uwadze, że chociaż w omawianym przykładzie użyto Razor Pages, SignalR doskonale współpracuje również z podejściem SPA (Single Page Application), umożliwiając integrację z nowoczesnymi frameworkami frontendowymi takimi jak Angular, React czy Vue.js. Dzięki temu możliwe jest tworzenie bogatych, responsywnych aplikacji, które komunikują się z serwerem na bieżąco, bez konieczności przeładowywania strony. Architektura taka pozwala na wyraźne oddzielenie warstwy frontendowej od backendowej, co zwiększa skalowalność i elastyczność rozwiązań.

Ważne jest, aby czytelnik rozumiał, że SignalR to warstwa abstrakcji nad różnymi protokołami transportowymi, dzięki której programista nie musi martwić się o szczegóły implementacyjne połączenia sieciowego – może skupić się na logice biznesowej i komunikacji między klientami a serwerem. Zrozumienie tej abstrakcji pozwala efektywniej projektować systemy reagujące na zdarzenia w czasie rzeczywistym. Ponadto, znajomość ograniczeń, takich jak brak wsparcia dla transmisji danych binarnych, jest kluczowa dla odpowiedniego planowania funkcjonalności aplikacji.

Praktyka korzystania z klas Hub i metod takich jak SendAsync oraz konsekwentne stosowanie wzorców dobrych praktyk programistycznych (np. używanie stałych zamiast tekstów do nazw metod) jest fundamentem utrzymania czytelności i łatwości rozwoju aplikacji wieloużytkownikowych działających w czasie rzeczywistym. Takie podejście pozwala na szybkie rozbudowywanie funkcjonalności i adaptowanie aplikacji do rosnących wymagań bez ryzyka wprowadzenia błędów.

Jak wykorzystać mechanizmy cache w aplikacjach i poprawić wydajność?

W klasie CacheController zastosowano mechanizm zarządzania pamięcią podręczną za pomocą interfejsu IDistributedCache, który umożliwia abstrahowanie procesu połączenia z serwerem Redis. Przykładem tego jest deklaracja prywatnej właściwości klasy _cache typu IDistributedCache, która odpowiada za operacje na pamięci podręcznej. W konstruktorze klasy, wstrzykiwana jest instancja tego interfejsu, co pozwala na efektywne zarządzanie danymi w pamięci cache przez całe życie obiektu klasy CacheController.

Pierwsza z metod, Get, odpowiada za pobieranie danych z pamięci podręcznej. Za pomocą _cache.GetStringAsync(key), realizowana jest próba pobrania wartości przypisanej do klucza. Jeżeli wartość istnieje, zostaje ona zwrócona. W przeciwnym razie, zwrócony zostaje status 404, wskazujący na brak danych w cache.

Metoda Post natomiast służy do zapisywania nowych danych w pamięci podręcznej. Otrzymuje ona obiekt typu MyData, a jego właściwość Key jest używana jako klucz pamięci podręcznej. Następnie obiekt jest serializowany do formatu JSON za pomocą JsonSerializer.Serialize(data), a opcje wygasania danych są określane przez DistributedCacheEntryOptions. Do pamięci Redis zapisuje się te dane poprzez metodę await _cache.SetStringAsync(cacheKey, serializedData, options). Ważnym aspektem jest ustawienie czasu wygaśnięcia danych w pamięci podręcznej za pomocą metod SetSlidingExpiration i SetAbsoluteExpiration.

SetSlidingExpiration ustala czas, przez który element może być nieużywany, zanim zostanie usunięty z pamięci podręcznej, przy czym każdorazowy dostęp do danych resetuje ten czas. Z kolei SetAbsoluteExpiration określa maksymalny czas życia elementu w cache, niezależnie od tego, jak często jest on odczytywany. Te dwa podejścia umożliwiają bardzo elastyczne zarządzanie danymi w pamięci podręcznej, co ma kluczowe znaczenie w kontekście zwiększania wydajności aplikacji.

Kiedy aplikacja jest już uruchomiona, można skonfigurować serwer Redis przy pomocy Dockera. Aby to zrobić, w terminalu należy wpisać polecenie:

css
docker run --name redis -d -p 6379:6379 redis

Po uruchomieniu serwera, możemy wywołać aplikację za pomocą dotnet run, a następnie używać narzędzi takich jak Postman, by testować różne operacje związane z pamięcią podręczną. Przykładowo, w celu odczytu danych z cache, należy wykonać zapytanie typu GET z odpowiednim kluczem, np. /api/Cache/DataInCache. Jeżeli klucz nie istnieje w pamięci, zostanie zwrócony status 404.

Aby dodać dane do pamięci podręcznej, wystarczy wykonać zapytanie POST z ciałem w formacie JSON, np.:

json
{
"key": "DataInCache", "value": "Value in cache" }

Po wykonaniu zapytania, serwer zwróci status 201, informujący o udanym dodaniu danych do cache. Kolejne zapytanie GET już zwróci odpowiedź z zapisanymi danymi.

Redis Insight, narzędzie do zarządzania Redisem, umożliwia również wizualizację danych przechowywanych w cache. Po skonfigurowaniu połączenia z serwerem Redis, możemy łatwo zobaczyć dane zapisane w pamięci, co jest przydatne do diagnozowania ewentualnych problemów z cache'em.

Warto zaznaczyć, że mechanizm pamięci podręcznej, zwłaszcza przy użyciu Redis, jest jednym z fundamentów nowoczesnych aplikacji, poprawiającym ich wydajność i skalowalność. W prawdziwych scenariuszach produkcyjnych cache często współpracuje z bazą danych, gdzie przed wykonaniem zapytania do bazy sprawdzane jest, czy dane znajdują się już w cache. Jeśli tak, zapytanie do bazy jest zbędne, co znacznie przyspiesza działanie aplikacji.

Cache to potężne narzędzie, które nie tylko przyspiesza dostęp do danych, ale również zwiększa dostępność aplikacji, zmniejszając obciążenie serwerów baz danych. Aby jeszcze bardziej poprawić odporność aplikacji, warto rozważyć implementację mechanizmów odpornościowych, takich jak wzorce retry (ponawiania prób) czy circuit breaker, które pozwalają aplikacjom radzić sobie z tymczasowymi awariami i zapewniają ciągłość działania nawet w obliczu problemów z infrastrukturą.

Optymalizacja aplikacji za pomocą pamięci podręcznej to temat niezwykle istotny, który ma szerokie zastosowanie w rzeczywistych projektach. Integracja Redis w takich systemach jest jednym z najbardziej popularnych rozwiązań, które znacząco poprawiają doświadczenie użytkowników i zapewniają płynne działanie aplikacji, nawet w warunkach dużego obciążenia.

Jak skutecznie wdrożyć logowanie w aplikacjach ASP.NET Core?

Logowanie w aplikacjach jest nieodzownym elementem, który pozwala na śledzenie działania oprogramowania oraz ułatwia diagnozowanie i monitorowanie błędów. Jako fundament każdej dobrze zaprojektowanej aplikacji, logowanie daje wgląd w jej zachowanie, pomaga w usuwaniu usterek oraz optymalizowaniu jej działania. W szczególności, interfejs ILogger w ASP.NET Core umożliwia logowanie różnych poziomów informacji, które mogą być przydatne zarówno w procesie rozwoju, jak i podczas utrzymania aplikacji na produkcji.

ILogger dostarcza kilka metod, które umożliwiają logowanie informacji o różnych poziomach szczegółowości:

  • Trace – szczegółowe informacje, które zwykle są przydatne tylko w przypadku diagnozowania problemów.

  • Debug – informacje pomocne przy debugowaniu aplikacji.

  • Information – komunikaty informacyjne, które pokazują postęp aplikacji.

  • Warning – sytuacje potencjalnie szkodliwe, ale nie błędne.

  • Error – błędy, które uniemożliwiają poprawne działanie aplikacji.

  • Critical – krytyczne błędy, które powodują całkowitą awarię aplikacji.

Interfejs ILogger udostępnia także szereg metod pomocniczych, które pozwalają na logowanie w bardziej wygodny sposób:

  • LogTrace(string message, params object[] args) – logowanie komunikatów śledzących.

  • LogDebug(string message, params object[] args) – logowanie komunikatów debugujących.

  • LogInformation(string message, params object[] args) – logowanie komunikatów informacyjnych.

  • LogWarning(string message, params object[] args) – logowanie komunikatów ostrzegawczych.

  • LogError(string message, params object[] args) – logowanie komunikatów o błędach.

  • LogCritical(string message, params object[] args) – logowanie komunikatów o krytycznych błędach.

Przykładowo, poniższy fragment kodu ilustruje, jak można wykorzystać interfejs ILogger w praktyce:

csharp
public class MyService { private readonly ILogger _logger; public MyService(ILogger<MyService> logger) { _logger = logger; } public void DoWork() { _logger.LogInformation("Starting work."); try { // Wykonaj jakąś pracę } catch (Exception ex) { _logger.LogError(ex, "An error occurred while doing work."); } _logger.LogInformation("Finished work."); } }

W tym przykładzie korzystamy z metod LogInformation i LogError, aby zapisać ważne informacje na temat postępu aplikacji oraz ewentualnych błędów. Metody te przyjmują różne argumenty, co pozwala na precyzyjne logowanie szczegółów zdarzeń. Warto również zauważyć, że parametr ILogger<MyService> oznacza, że logi będą powiązane z klasą MyService, co może być pomocne przy analizowaniu logów i identyfikowaniu źródła problemów.

Logger w ASP.NET Core jest zbudowany w sposób umożliwiający centralną konfigurację, co ułatwia zarządzanie logowaniem w większych aplikacjach. Wykorzystanie klasy ILoggerFactory pozwala na tworzenie instancji ILogger z różnymi kategoriami, dzięki czemu możliwe jest przypisanie logów do konkretnych części aplikacji. Interfejs ILoggerFactory oferuje następujące metody:

  • CreateLogger(string categoryName) – tworzy instancję ILogger dla podanej kategorii.

  • AddProvider(ILoggerProvider provider) – dodaje dostawcę logów (np. do zapisywania logów w plikach, konsoli, zewnętrznych usługach takich jak Azure Application Insights czy Elasticsearch).

  • Dispose() – usuwa fabrykę logów i zwalnia zasoby.

Dzięki tym metodom, konfiguracja logowania w aplikacji staje się bardziej elastyczna i skalowalna. Można stworzyć wiele loggerów, z których każdy będzie odpowiadał za logowanie w określonym obszarze aplikacji.

Podstawowa różnica między korzystaniem z ILogger a ILoggerFactory polega na centralizacji logowania. Przy użyciu ILoggerFactory możemy utworzyć logery dla różnych części aplikacji, które będą korzystać z tych samych ustawień konfiguracyjnych. Oznacza to, że wszystkie logi będą centralnie zarządzane, a ich formatowanie i zapis będą spójne w całej aplikacji.

Konfiguracja logowania w ASP.NET Core

Logowanie w aplikacjach ASP.NET Core jest konfigurowane głównie w metodzie Program.cs, gdzie dodaje się odpowiednie dostawców logów. W poniższym przykładzie logowanie jest skonfigurowane do zapisu w konsoli, a także do zapisu informacji debugowych i zdarzeń systemowych:

csharp
var builder = WebApplication.CreateBuilder(args); // Dodaj usługi do kontenera builder.Services.AddControllers(); // Konfiguracja logowania builder.Logging.ClearProviders(); // Opcjonalnie: usunięcie domyślnych dostawców builder.Logging.AddConsole(); // Logowanie do konsoli builder.Logging.AddDebug(); // Logowanie informacji debugowych builder.Logging.AddEventSourceLogger(); // Logowanie zdarzeń systemowych var app = builder.Build(); // Konfiguracja pipeline'a HTTP if (app.Environment.IsDevelopment()) { app.UseDeveloperExceptionPage(); } else { app.UseExceptionHandler("/Home/Error"); app.UseHsts(); } app.UseHttpsRedirection(); app.UseStaticFiles(); app.UseRouting(); app.UseAuthorization(); app.MapControllers(); app.Run();

W przykładzie tym widzimy, jak różni dostawcy logów są dodawani do aplikacji. Każdy z nich odpowiada za zapis logów w innym miejscu (np. konsola, debugowanie, zdarzenia systemowe). Dzięki temu wszystkie logi wygenerowane w aplikacji są równocześnie zapisywane w kilku źródłach, co umożliwia ich łatwiejszą analizę i monitorowanie.

Ważne uwagi

Przy wdrażaniu logowania w aplikacji, warto pamiętać, że logi powinny być odpowiednio dopasowane do poziomu krytyczności informacji. Zbyt szczegółowe logi mogą spowolnić aplikację, a ich nadmiar może sprawić, że istotne informacje zostaną przeoczone w natłoku danych. Z kolei zbyt mała ilość logów może utrudnić diagnozowanie problemów w przyszłości.

Kolejnym istotnym aspektem jest konfiguracja dostawców logów. W zależności od potrzeb aplikacji, warto rozważyć dodanie dodatkowych dostawców, takich jak logowanie do plików, zewnętrznych baz danych, czy usług monitorujących, jak np. Application Insights w przypadku aplikacji działających w chmurze. Dzięki temu logi będą miały bardziej trwałą i skalowalną architekturę.

Jakie podejście wybrać do renderowania UI w aplikacjach webowych?

Współczesne aplikacje webowe stają się coraz bardziej złożone i interaktywne, a ich wydajność oraz doświadczenie użytkownika zależą od technologii używanych do tworzenia warstwy interfejsu użytkownika (UI). Jednym z kluczowych elementów, który pozwala na wzbogacenie interfejsu webowego o dynamiczne elementy, jest JavaScript. Jednak pisanie i zarządzanie kodem JavaScript, szczególnie przy pracy z backendem, może okazać się skomplikowane, a jego integracja z serwerem – czasochłonna. W odpowiedzi na te wyzwania, powstały frameworki JavaScript, takie jak Angular czy React, które umożliwiają tworzenie bardziej zaawansowanych i dynamicznych interfejsów użytkownika.

Nie ma jednak potrzeby ograniczać się jedynie do technologii frontendowych. W tym kontekście, ASP.NET Core 9 pojawia się jako platforma, która oferuje pełne rozwiązania UI dla aplikacji webowych, będąc jednocześnie w pełni zintegrowaną z platformą .NET. Co więcej, ASP.NET Core 9 umożliwia nie tylko tworzenie klasycznych aplikacji webowych, ale także łączenie najlepszych cech technologii JavaScript z tradycyjnymi rozwiązaniami serwerowymi, przyjmując podejście hybrydowe.

Jednak zanim przejdziemy do bardziej szczegółowego omówienia opcji dostępnych w ASP.NET Core 9, warto zwrócić uwagę na kilka kluczowych kwestii związanych z architekturą systemów webowych, zwłaszcza w kontekście renderowania UI.

Modele renderowania UI

Podstawowe podejścia do tworzenia aplikacji webowych pod względem renderowania UI dzielą się na trzy główne modele: klient-server, server-side oraz model hybrydowy. Każde z tych podejść ma swoje zalety i wady, zależne głównie od potrzeb aplikacji i dostępnych zasobów.

W podejściu klient-server cała logika związana z renderowaniem strony jest realizowana po stronie klienta, w przeglądarce. HTML, CSS, JavaScript oraz inne zasoby są przetwarzane lokalnie, a interakcje użytkownika są obsługiwane przez skrypty. Oznacza to, że częste zapytania do serwera mogą być konieczne w celu uzyskania nowych danych do wyświetlenia, co może prowadzić do obciążenia serwera i wpływać na wydajność.

W modelu server-side cały proces renderowania strony odbywa się na serwerze, który następnie wysyła gotową stronę HTML do przeglądarki. Serwer nie tylko zarządza danymi, ale także odpowiada za logikę biznesową i bezpieczeństwo, umożliwiając abstrakcję poufnych informacji. Zaletą tego podejścia jest mniejsze obciążenie po stronie klienta, ale w przypadku awarii serwera cała aplikacja przestaje działać.

Model hybrydowy stawia na połączenie najlepszych cech obu podejść. Wykorzystuje JavaScript do dynamicznego renderowania interfejsu na kliencie, ale jednocześnie pozwala na interakcję z serwerem, dzięki czemu możliwe jest delegowanie części logiki biznesowej na stronę serwera. To podejście daje dużą elastyczność i umożliwia tworzenie bardziej interaktywnych aplikacji.

ASP.NET Core 9 i Razor Pages

ASP.NET Core 9 oferuje dwa główne modele renderowania serwerowego UI: Razor Pages oraz MVC. Razor Pages jest prostsze w implementacji i opiera się na modelu strony, gdzie każda strona aplikacji odpowiada za swoje UI oraz logikę biznesową. Model ten ułatwia tworzenie aplikacji, zapewniając prostą separację odpowiedzialności i testowalność. Razor Pages wykorzystuje Razor, język szablonów, który łączy HTML z kodem C#, oferując proste podejście do generowania dynamicznych stron.

Zaletą Razor Pages jest możliwość łatwego tworzenia oraz aktualizowania UI, a także rozdzielenie logiki biznesowej od samego interfejsu. System ten jest testowalny, co pozwala na wygodne przeprowadzanie testów jednostkowych.

Tworzenie aplikacji z Razor Pages

Aby rozpocząć pracę z Razor Pages, można użyć Visual Studio lub narzędzia wiersza poleceń .NET CLI. Tworzenie nowego projektu z wykorzystaniem Visual Studio jest proste: wystarczy wybrać szablon ASP.NET Core Web App i zainicjować projekt. Można także użyć CLI, aby utworzyć nowy projekt z wiersza poleceń, co daje większą kontrolę nad procesem tworzenia aplikacji.

Przykład polecenia CLI do utworzenia nowego projektu Razor Pages wygląda następująco:

bash
dotnet new razor -n MySecondWebRazor

To polecenie tworzy nowy folder z projektem Razor Pages, a w jego wnętrzu znajdą się wszystkie niezbędne pliki do dalszego rozwoju aplikacji.

Integracja z JavaScript

Chociaż Razor Pages i ASP.NET MVC oferują potężne możliwości renderowania UI po stronie serwera, nie oznacza to, że użytkownicy są ograniczeni tylko do tych technologii. ASP.NET Core 9 jest w pełni kompatybilny z popularnymi frameworkami JavaScript, takimi jak Angular czy React. Umożliwia to wykorzystanie pełni możliwości obu światów — serwerowego i klientowego — tworząc hybrydowe aplikacje, które wykorzystują moc serwera do obliczeń i przetwarzania danych, podczas gdy UI jest renderowane dynamicznie po stronie klienta.

Dzięki tej elastyczności, programiści mogą wybierać odpowiednie narzędzia w zależności od potrzeb projektu, łącząc najlepsze cechy różnych technologii.

Co warto dodać

W kontekście wyboru modelu renderowania UI, warto zwrócić uwagę na specyficzne wymagania aplikacji. Model client-side jest odpowiedni dla aplikacji, które wymagają dużej interaktywności i niezależności od serwera, ale może wymagać skomplikowanego zarządzania stanem i większych zasobów po stronie klienta. Server-side renderowanie z kolei jest lepszym rozwiązaniem w przypadku aplikacji, które muszą być wysoko skalowalne, zapewniać bezpieczeństwo danych i posiadać pełną kontrolę nad procesem renderowania.

Hybrydowe podejście jest szczególnie efektywne w dużych aplikacjach, które muszą obsługiwać dynamiczne interakcje, ale również wymagają stabilnego backendu. Warto rozważyć, który model najlepiej pasuje do specyfiki aplikacji oraz zasobów dostępnych w projekcie.