SignalR to biblioteka w platformie .NET, która umożliwia łatwe tworzenie aplikacji działających w czasie rzeczywistym, zapewniając nieprzerwaną komunikację między serwerem a klientem. Dzięki niej możliwe jest zbudowanie aplikacji, które reagują na zdarzenia użytkownika lub zmiany na serwerze natychmiastowo, bez konieczności odświeżania strony. To doskonałe narzędzie do tworzenia aplikacji, które wymagają szybkiej i efektywnej wymiany danych w czasie rzeczywistym, takich jak czaty, aplikacje do współpracy czy monitorowanie danych w czasie rzeczywistym.

W przypadku SignalR komunikacja pomiędzy klientem a serwerem odbywa się za pomocą stałego połączenia. Najczęściej wykorzystywaną technologią transportu jest WebSockets, który pozwala na pełną komunikację dwukierunkową (full-duplex), co oznacza, że zarówno klient, jak i serwer mogą wymieniać dane w obu kierunkach w tym samym czasie. Jeśli WebSockets nie jest wspierany przez środowisko, SignalR automatycznie przełącza się na inne techniki, takie jak Server-sent events lub long polling.

Transport jest realizowany za pomocą formatu JSON lub danych binarnych. W przypadku Server-sent events dane są przesyłane jedynie w jednym kierunku — od serwera do klienta, co oznacza, że klient nie może odpowiedzieć na te wiadomości bez nawiązania osobnego połączenia HTTP. Long polling to prostsza technika, w której klient wysyła zapytanie do serwera, ale zamiast natychmiastowej odpowiedzi serwer przetwarza zapytanie i odsyła odpowiedź dopiero po zakończeniu operacji.

SignalR abstraktuje te różne techniki transportu, umożliwiając deweloperowi skoncentrowanie się na logice aplikacji, zamiast na szczegółach komunikacji. Ważnym elementem w tej komunikacji jest Hub — komponent SignalR, który działa jak pośrednik pomiędzy serwerem a klientem. To w Hubie zdefiniowane są metody, które mogą być wywoływane na serwerze z poziomu klienta, lub odwrotnie, za pomocą zdalnych wywołań procedur (RPC).

RPC, choć stare, ma kluczowe znaczenie w nowoczesnych technologiach. Wykorzystywane w SignalR, pozwala na zdalne wywoływanie metod serwera przez klientów w sposób przejrzysty i efektywny. To samo podejście leży u podstaw innych nowoczesnych technologii, takich jak gRPC opracowane przez Google.

SignalR jest potężnym narzędziem, które nie tylko upraszcza proces komunikacji w czasie rzeczywistym, ale także pozwala na zaawansowane operacje, takie jak wysyłanie powiadomień do wszystkich, pojedynczych lub grupy klientów. Dzięki SignalR możliwe jest także tworzenie aplikacji, które komunikują się z innymi platformami, np. aplikacjami napisanymi w Javie lub JavaScript.

Zaczynając pracę z SignalR, warto poznać podstawowe komponenty aplikacji w czasie rzeczywistym. W klasycznej aplikacji internetowej mamy do czynienia z dwiema głównymi częścią: klientem i serwerem. W aplikacjach z wykorzystaniem SignalR te komponenty muszą współpracować, by zapewnić nieprzerwaną komunikację. Przykładem może być aplikacja do zarządzania zadaniami, w której użytkownicy mogą tworzyć, ukończać i przeglądać zadania w czasie rzeczywistym.

Zaimplementowanie tej aplikacji w oparciu o Razor Pages, JavaScript po stronie klienta oraz C# po stronie serwera umożliwi nie tylko naukę podstaw SignalR, ale także stworzenie realnej aplikacji, która wykorzystuje funkcjonalności w czasie rzeczywistym. W takiej aplikacji plik index-page.js będzie odpowiedzialny za zarządzanie interakcjami między klientem a serwerem, zaś plik signalr.js zapewni wsparcie dla SignalR na poziomie JavaScript.

Serwer, który będzie działał na platformie Razor Pages, pełni rolę orkiestratora, zarządzając komunikacją z klientem za pomocą Hubu. Implementacja tego komponentu, który odpowiada za zarządzanie połączeniami i metodami wywoływanymi w czasie rzeczywistym, jest kluczowa dla każdej aplikacji używającej SignalR. Na poziomie serwera Hub zapewnia bezbłędne zarządzanie połączeniami i umożliwia zarówno klientowi, jak i serwerowi na wykonywanie metod w sposób asynchroniczny.

Aby rozpocząć tworzenie aplikacji, konieczne jest przygotowanie odpowiedniego środowiska. Pierwszym krokiem jest utworzenie projektu, co można zrobić za pomocą terminala, używając komendy dotnet new webapp -o TaskManager. Następnie w kolejnym kroku należy dodać bibliotekę SignalR JavaScript SDK, która będzie obsługiwała komunikację na poziomie klienta. Używając narzędzia LibMan, dodajemy potrzebne skrypty JavaScript do aplikacji. Ważne jest również, by dodać odpowiednią konfigurację do aplikacji Razor Pages, aby połączyć się z SignalR w sposób wydajny i bezproblemowy.

Po utworzeniu projektu i dodaniu niezbędnych zależności, możemy przystąpić do implementacji metod w Hubie, które będą odpowiedzialne za rzeczywistą komunikację pomiędzy serwerem a klientem. Konfiguracja Hubu to kluczowy etap, ponieważ to właśnie za jego pomocą klienci będą mogli wysyłać i odbierać dane w czasie rzeczywistym.

Pomimo pozornie skomplikowanej natury aplikacji w czasie rzeczywistym, dzięki SignalR proces ten staje się znacznie prostszy, umożliwiając deweloperom skupienie się na logice aplikacji, a nie na szczegółach komunikacji sieciowej. Ważne jest, by zrozumieć, że każda aplikacja w czasie rzeczywistym opiera się na stałym połączeniu między klientem a serwerem, które pozwala na natychmiastową wymianę danych. Tylko takie podejście gwarantuje interaktywność i szybkość działania aplikacji, której użytkownicy oczekują.

Jak Docker, CI/CD i DevOps przyspieszają rozwój aplikacji

Zrozumienie podstawowych zasad działania kontenerów Docker, podejścia DevOps oraz procesów CI/CD jest kluczowe dla nowoczesnego modelu tworzenia oprogramowania. Te technologie zmieniają sposób, w jaki tworzymy, testujemy i wdrażamy aplikacje, oferując konsystencję, przenośność i efektywność. Dzięki nim rozwój aplikacji staje się szybszy, bardziej niezawodny i elastyczny.

Docker to narzędzie, które umożliwia pakowanie aplikacji w kontenery, co pozwala na ich uruchomienie w różnych środowiskach z zachowaniem spójności. Aby sprawdzić, czy kontener działa prawidłowo, wystarczy wydać polecenie:

nginx
docker ps

Na ekranie wyświetli się lista uruchomionych kontenerów, podobna do przykładu w Figurze 10.18. Jeśli po uruchomieniu aplikacji w kontenerze napotkamy błąd połączenia z bazą danych, warto sprawdzić, czy nasz adres IP został dodany do białej listy w ustawieniach bazy danych na platformie Azure. W razie potrzeby, zmieniając ciąg połączenia, możemy użyć zmiennych środowiskowych podczas uruchamiania kontenera, jak pokazano w poniższym przykładzie:

arduino
docker run -d -p 8899:8080 -e ConnectionStrings__DefaultConnection="Server=.;Database=UrlShortenerDB;user id=sa;password=P4sword123;Encrypt=False;" localhost/urlshortener:1.0

Dzięki temu możemy łatwo dostosować parametry połączenia do naszej bazy danych, jak również uruchomić wiele instancji aplikacji na różnych portach:

arduino
docker run -d -p 9900:8080 localhost/urlshortener:1.0
docker run -d -p 9910:8080 localhost/urlshortener:1.0

W wyniku tych poleceń, mamy trzy kontenery z tą samą aplikacją uruchomioną w różnych portach na naszym lokalnym środowisku. Aby zakończyć pracę z kontenerami, wystarczy wykonać polecenie:

arduino
docker stop <container_id>

Aby znaleźć identyfikator kontenera, wystarczy ponownie użyć polecenia docker ps.

Równocześnie warto zrozumieć, jak procesy CI (Continuous Integration) i CD (Continuous Delivery) wpływają na rozwój i wdrażanie aplikacji. CI, jako praktyka regularnego scalania zmian w kodzie do centralnego repozytorium, wspiera wykrywanie problemów z integracją na wczesnym etapie. Proces CI jest automatycznie wspierany przez testy, które weryfikują, czy wprowadzone zmiany nie psują istniejącej funkcjonalności aplikacji.

Korzyści płynące z CI to:

  • wczesne wykrywanie błędów,

  • poprawa jakości kodu dzięki testom automatycznym,

  • szybka pętla feedbacku, pozwalająca na natychmiastowe poprawki w kodzie,

  • lepsza współpraca między członkami zespołu.

Warto również dodać, że recenzje kodu są istotnym elementem procesu CI. Pozwalają one na bieżąco analizować kod pod kątem dobrych praktyk, a także zapewniają, że zmiany są zgodne z wymaganiami jakościowymi. Proces przeglądu kodu, mimo że często wykonywany ręcznie, stanowi istotny element rozwoju zespołu.

Po zakończeniu etapu CI następuje proces CD, którego celem jest automatyczne wdrażanie aplikacji do różnych środowisk – deweloperskich, testowych i produkcyjnych. Dzięki CD, aplikacje są wdrażane w sposób ciągły, co umożliwia szybsze dostarczanie nowych funkcji oraz poprawek. Kluczowe korzyści wynikające z CD to:

  • szybsze dostarczanie nowych funkcji i poprawek,

  • zmniejszenie ryzyka związanego z wdrażaniem dużych zmian,

  • zapewnienie spójności wdrożeń,

  • zwiększenie niezawodności systemu dzięki automatycznemu monitorowaniu i mechanizmom przywracania poprzednich wersji.

Te praktyki sprawiają, że proces tworzenia i wdrażania aplikacji staje się bardziej płynny, zautomatyzowany i mniej podatny na błędy. Z perspektywy zespołu programistycznego, podejście DevOps z wykorzystaniem CI/CD umożliwia nie tylko usprawnienie procesu dostarczania oprogramowania, ale również umożliwia stały rozwój i adaptację do zmieniających się potrzeb rynkowych.

Przy wprowadzaniu DevOps i CI/CD, warto również pamiętać, że te procesy wymagają solidnej infrastruktury i odpowiednich narzędzi, które pozwolą na płynne zarządzanie aplikacjami w chmurze i na lokalnych serwerach. Istotne jest również, aby zespół rozwijał odpowiednią kulturę współpracy i komunikacji, co jest niezbędne do efektywnego wdrożenia DevOps.