Czym jest Blazor?
Jeżeli śledzisz moje treści, albo śledzisz tematy dla deweloperów, omawiane przez Microsoft, to na pewno ze słowem Blazor miałeś niejednokrotnie do czynienia.
Do tej pory, tworząc treści, jakoś po prostu zakładałem, że przede wszystkim będę pokazywał jak korzysta się z Blazora, jak buduje się w nim aplikacje, na co pozwala. Ale naszła mnie refleksja, że żeby iść w praktykę i omawianie kolejnych tematów, to warto mieć zbudowane podstawy.
Dlatego dzisiaj chcę Ci przybliżyć pokrótce czym właściwie Blazor jest i jak zaczynał.
Czym jest Blazor
Zacznijmy od oczywistego punktu, czyli czym właściwie jest Blazor.
Blazor jest frameworkiem webowym, pozwalającym programistom budować komponenty z użyciem języka C# i HTML. Nie ma tutaj rozróżnienia na komponenty statyczne i dynamiczne.
Blazor wykorzystuje składnię Razor do definiowania komponentów. Co powoduje, że możemy w kodzie HTML używać wstawek z języka C#. W porównaniu do MVC i Razor Pages, Blazor pozwala też na budowanie dynamicznych komponentów. W przypadku dwóch poprzednich, żeby dodać do strony interaktywność, programista musiał zawsze bezpośrednio posiłkować się językiem JavaScript i ewentualnie dodatkowymi bibliotekami. W tym kontekście Blazor jest rozwiązaniem kompletnym. Przynajmniej z punktu widzenia programisty budującego końcową aplikację.
Co warto od razu podkreślić – niezależnie czy mówimy o Blazorze Server, czy Blazorze WebAssembly – Blazor pod spodem korzysta też z silnika JavaScript. W przypadku Blazora WebAssembly jest on głównie używany do wystartowania kodu WASM, a potem do modyfikowania drzewa DOM, oraz komunikowania się z API przeglądarki. Ponieważ obecna implementacja WebAssembly nie ma bezpośredniego dostępu do drzewa elementów na stronie. Z kolei Blazor Server praktycznie w całości opiera sie o JavaScript, ponieważ do działania wykorzystuje bibliotekę SignalR. Za jej pomocą odbiera z przeglądarki zdarzenia i przesyła do przeglądarki fragmenty kodu HTML, które następnie umieszcza w odpowiednich miejscach.
Jednak co też bardzo istotne – Blazor w żadnym miejscu nie jest transpilowany do JavaScriptu. Nie jest to rozwiązanie w stylu TypeScriptu, który musi zostać zamieniony na JavaScript. Blazor wykorzystuje JavaScript jako API do przeglądarki i używa go jako swojej zależności.
Historia
Blazor został pierwszy raz zaprezentowany przez Steve’a Standersona w 2017r., podczas konferencji NDC Oslo (znajdziesz ją TUTAJ). Jednak do użytku wszedł w 2018 roku, jako część frameworka .NET Core 3.1.
Osobiście zacząłem się nim interesować w roku 2020 (przynajmniej tak wynika z pierwszych wpisów na moim blogu i pierwszych filmów na kanale Youtube). I właściwie od początku czułem, że jest to interesujące i w pewien sposób przełomowe rozwiązanie. Jednak początkowo miało ono dużo ograniczeń i faktycznie było raczej demem technologicznym, niż produkcyjnym rozwiązaniem.
Co ciekawe, pierwsza prezentacja dotyczyła Blazora WebAssembly, wtedy jeszcze opartego o runtime DotNetAnywhere, skompilowany dla WebAssembly.
Jednak pierwszą dostępną publicznie wersją była wersja Blazor Server, dopiero jakiś czas po tym deweloperzy dostali też w swoje ręce publiczne wydanie Blazor WASM. Tym razem jednak Blazor WebAssembly nie działał już w oparciu o runtime DotNetAnywhere, ale o Mono, które jest też używane przez mobilne aplikacje pisane z wykorzystaniem MAUI (wcześniej Xamarin).
Dopiero w .NET 5, Blazor przestał działać w przeglądarce Internet Explorer. I szczerze mówiąc, kiedy przeczytałem tą informację, to byłem w szoku, że Blazor kiedykolwiek działał w Internet Explorerze i komuś chciało się te dwie rzeczy ze sobą łączyć.
Główne założenia
Głównym założeniem stojącym za technologią Blazor jest możliwość budowania w pełni funkcjonalnego, i przede wszystkim, interaktywnego interfejsu użytkownika.
Zadaniem Blazora jest, w połączeniu z frameworkiem ASP.NET, umożliwienie deweloperom zbudowania pełnej aplikacji – od backendu, po frontend – w całości z wykorzystaniem języka C#. W dodatku, korzystając z Blazor WebAssembly, Blazor umożliwia budowanie aplikacji typu SPA, które w pełni działają po stronie przeglądarki użytkownika.
Tutaj mogę wtrącić swoje przemyślenie na temat założeń tego frameworka.
Przekaz od Microsoftu jest taki, że raczej każdy i w każdej sytuacji powinien chcieć przejść na technologię Blazor, bo jest to po prostu wygodne rozwiązanie.
Jednak moim zdaniem, głównym założeniem stojącym za tą technologią, mogła być chęć wykorzystania do pracy frontendowej także programistów backendowych, którzy nie chcą, albo nie potrafią pracować z językiem JavaScript. W ten sposób dużo prościej jest zrobić z backend developerów full-stack developerów i poniekąd obniżyć koszty w części projektów.
Możliwość pisania w języku C#, korzystanie z tej samej składni, która była „za czasów” ASP.NET MVC, czy możliwość współdzielenia bibliotek i klas, to silne sugestie, że tak naprawdę to z Blazorem frontend tak właściwie jest częścią backendu, tak jak kiedyś, kiedy się pisało Razor Pages i ASP.NET MVC. Pamiętacie? Pewnie, że pamiętacie. No to wracamy, tylko lepsi, bo bez jQuery do pokazywania modali i walidacji inputów.
Obecna wersja, udostępniona wraz z .NET 8, przeszła małą rewolucję. I obecnie ma ona niejako być uniwersalnym rozwiązaniem, niezależnie od tego, czy budujemy statyczne, czy interaktywne treści.
Co ważne – chęć skorzystania ze wszystkich dobrodziejstw Blazora wymaga, żeby był on zintegrowany z backendem pisanym w .NET, a konkretnie w ASP.NET.
Tak naprawdę, jeżeli chcemy, żeby Blazor faktycznie działał jak każda inna aplikacja frontendowa, typu SPA, to mamy do wyboru jedynie Blazor WebAssembly. Jednak decydując się na ten krok, mamy ograniczone pole manewru, np. jeżeli chodzi o łatwość żonglowania konfiguracjami środowiska. Ale też tracimy bardzo duży benefit związany z korzystaniem z Blazora, czyli możliwość współdzielenia modeli, albo bibliotek pomiędzy backendem i frontendem.
Tryby renderowania
Obecnie Blazor posiada trzy główne tryby renderowania:
- Server-Side Rendering
- Server
- WebAssembly
Wcześniej dwa ostatnie były dostępne, jednak każdy w osobnym szablonie projektu. Startując projekt musieliśmy zdecydować, w którym podejściu go będziemy budowali.
Trzeci tryb doszedł wraz z .NET 8 i jest właśnie takim powrotem do statycznie renderowanych treści. Jednocześnie wraz z tym trybem, dwa pozostałe zostały wciągnięte do współpracy. I obecnie tworząc projekt nie musimy od razu decydować, czy cały będzie w Blazor Server, czy w Blazor WebAssembly. Teraz po prostu możemy stworzyć aplikację Blazor i decydować o trybie renderowania na poziomie strony, albo komponentu.
Na temat każdego z trybów można by pisać osobne artykuły. Także tutaj tylko w paru słowach zrobię ich charakterystykę.
Server-Side Rendering
Najmłodszy z trybów, a jednocześnie najstarszy, jeżeli chodzi o koncepcję i założenia na jakich się opiera.
Obecnie jest to domyślny tryb renderowania treści w Blazorze. Jeżeli nie chcemy z niego korzystać, musimy jawnie oznaczyć strony lub komponenty, dla których oczekujemy innego trybu.
SSR odpowiada za całkowicie statyczne generowanie treści. Jeżeli pracowałeś wcześniej z ASP.NET MVC, albo ASP.NET Razor Pages, to to jest dokładnie ten typ pracy. Backend generuje gotowy kod HTML, który jest prezentowany użytkownikowi. Zero interaktywności. Nawet formularze, w domyślnej postaci, nie zadziałają, jeżeli ich akcje, wykonywane przy submitowaniu, są opisane kodem C#. Nie zadziała inny kod komponentu, niż ten uruchamiany prze inicjalizowaniu tego komponentu.
Jednak nie jest tak, że ten tryb jest bez sensu i po co go używać, skoro mamy stare dobre MVC.
SSR ma chociażby tą gigantyczną przewagę nad MVC, że pisanie w nim komponentów, a więc po prostu schludne dzielenie frontendu na mniejsze klocki, z których to wszystko składamy, jest dużo przyjemniejsze i prostsze.
Dodatkowo, SSR jest w pełni zintegrowany z pozostałymi dwoma trybami, a więc ten sam komponent może działać zarówno w trybie SSR, jak i Server, albo WebAssembly (oczywiście jeżeli jest w miarę dobrze napisany).
Oprócz tego, Blazor SSR ma zaimplementowany ciekawy mechanizm, który udaje dynamiczne ładowanie treści. Czego w MVC nie byliśmy w stanie uzyskać bez dodatkowej pracy.
Stream Rendering, bo o nim mowa, sprytnie wykorzystuje długi czas timeoutu odpowiedzi z serwera do tego, żeby najpierw szybko pokazać użytkownikowi widok bez danych (np. z napisałem „Trwa ładowanie”), a kiedy backend będzie miał dane, dosłać w tej samej odpowiedzi zaktualizowaną część, która wskoczy na miejsce poprzedniej. Bez żadnego naszego udziału.
Oczywiście, że pod spodem jest wykorzystywany kawałek JavaScriptu, a więc nie jest to całkowicie statyczna treść. Jednak nie wymaga od dewelopera żadnej dodatkowej pracy, a od serwera obsługi dwóch różnych zapytań.
Także Blazor Server-Side Rendering ma moim zdaniem sens jeżeli potrzebujemy wyrenderować w naszym backendzie statyczną stronę. Ma przewagę nad ASP.NET MVC w postaci tego, że bardzo upraszcza budowanie mniejszych komponentów, a dodatkowo zapewnia ciekawe mechanizmy do udawania dynamicznej strony. Dlatego dla treści statycznych obecnie, wybrałbym to rozwiązanie ponad MVC.
Blazor Server
Najstarsza, dostępna publicznie , implementacja Blazora.
Ten tryb renderowania teoretycznie wprowadza interaktywność do naszej aplikacji, ale taką lekko udawaną.
Zasada działania Blazora Server jest taka, że użytkownik pobiera na starcie właściwie tylko bibliotekę JavaScriptową i szkielet pliku HTML. Biblioteka nawiązuje połączenie z serwerem za pomocą rozwiązania o nazwie SignalR. Otwiera się wtedy WebSocket pomiędzy przeglądarką, a serwerem.
Od tego momentu każda akcja użytkownika, każde kliknięcie w przycisk, w link, interaktywny element, powoduje wysłanie tej informacji przez wspomniany WebSocket to serwera. Serwer przechwytuje takie zdarzenie i uruchamia silnik Blazora dla konkretnej strony. Renderuje zmiany względem poprzedniego widoku użytkownika i taką paczkę zmian odsyła przez WebSocket do przeglądarki. Tam, załadowana wcześniej biblioteka, nanosi te zmiany na obecny dokument HTML i w ten sposób użytkownik widzi nowe elementy, bez przeładowywania strony.
Oczywiście całość zachowuje się jak zwyczajna interaktywna strona. Jednak to udawanie wspomniałem dlatego, że mimo wszystko jest to mechanizm, który ciągle renderuje statyczne fragmenty widoku i je na bieżąco podmienia. Taki jakby film poklatkowy ;)
Zaletą tego trybu renderowania jest to, że tak naprawdę kod Blazora, a więc cały kod C#, wykonuje się po stronie serwera. Dzięki czemu nasze komponenty mają bezpośredni dostęp do całej zawartości serwera i nie musimy bawić się w jakieś budowanie API i przesyłanie każdej informacji w jedną i drugą stronę. Przede wszystkim też, dzięki bezpośredniemu wykonywaniu na serwerze, cała logika aplikacji jest ukryta przed użytkownikiem i jego chęciami sprawdzenia jak coś robimy.
Ma to jednak też wadę – utrudniony dostęp do API przeglądarki i problematyczne komunikowanie się ze skryptami JavaScript.
Jest to dobry tryb w przypadku, kiedy nasza aplikacja nie jest aż tak mocno interaktywna, żeby non stop musieć podmieniać fragmenty stron. Dodatkowo, korzystanie z WebSocketów ma jeszcze tę wadę, że jest ich na każdym serwerze skończona pula. Niezależnie od tego jak dobry serwer mamy i jak dobrze napisaliśmy aplikację. Więc Blazor Server sprawdzi się do systemów, które nie mają aż tak gigantycznej ilości użytkowników. Teoretycznie można to obejść korzystając z zewnętrznych usług, takich jak Azure SignalR Hub, jednak nadal skalowanie tutaj ma swoje limity.
Inna sprawa to to, że Blazor Server, co z resztą sugeruje sama nazwa, wymaga ciągłego połączenia z serwerem i przez to nasz frontend staje się bezużyteczny w przypadku jakiejkolwiek przerwy w działaniu backendu. Kiedy tylko połączenie zostanie zakłócone, frontend pokazuje informację, że próbuje nawiązać połączenie i użytkownik nic nie jest w stanie wtedy nic zrobić na stronie.
Także moim zdaniem, jest to dobry tryb do aplikacji biznesowych, bardziej wewnętrznych. Gdzie mamy skończoną ilość użytkowników, a w dodatku mocno korzystamy z zasobów serwera i np. chętnie się odwołujemy do innych usług wewnątrz sieci, albo korzystamy z wewnętrznych bibliotek i po prostu łatwiej i bezpieczniej jest to wszystko mieć zgrane w całości na serwerze, bez konieczności dzielenia kodu logiki między frontend i backend.
Blazor WebAssembly
Na koniec przyszła pora na najciekawszy, albo też najbardziej egzotyczny tryb dostępny w Blazorze.
Blazor WebAssembly, z całej tej trójki trybów renderowania, jako jedyny pozwala faktycznie implementować strony typu SPA. Więc też jako jedyny z całej trójki jest prawdziwą konkurencją dla Reacta czy Angulara.
Blazor WebAssembly (w skrócie Blazor WASM), jak sama nazwa wskazuje, korzysta z technologii WebAssembly. Nie będę tutaj rozpisywał się na temat tej technologii, zostawmy to sobie na inny dzień. Jednak wspomnę tylko, że WebAssembly pozwala uruchamiać skompilowane, specjalnie pod to rozwiązanie, pliki wykonywalne, m.in. wewnątrz przeglądarki. Także mówimy w tym przypadku o plikach binarnych, które działają bezpośrednio w przeglądarce użytkownika i są całkowicie autonomiczną aplikacją.
W przypadku Blazora WASM, wraz z naszym kodem, kompilowanym po prostu do plików DLL, dodajemy, rękami komendy budującej kod, środowisko uruchomieniowe .NET, skompilowane do WebAssembly. Aktualnie tym środowiskiem jest Mono, maksymalnie odchudzone, tak żeby nie wymagać od użytkownika pobierania setek megabajtów plików przy pierwszym wejściu na stronę.
Jednak nadal jest to około 10MB + waga naszej aplikacji do pobrania. Dlatego pierwsze wejście i uruchomienie aplikacji napisanej w Blazor WebAssembly zajmuje dużo czasu, nierzadko nawet 10 i więcej sekund. Bo poza tym, że muszą zostać pobrane pliki wykonywalny, to kiedy są już w pamięci przeglądarki, sama platforma .NET musi się uruchomić w tej przeglądarce, co też trwa te 2-3 sekundy.
Sama technologia WebAssembly, potrafi być bardzo szybka, szybsza od kodu JavaScriptowego. Jednak jest jeden problem – WebAssembly nie ma bezpośredniego dostępu do API przeglądarki i do drzewa DOM. Żeby cokolwiek z nimi zrobić, musi poprosić JavaScript o wykonanie konkretnych operacji. Dlatego o ile logika pisana w WASM może być bardzo szybka, tak manipulowanie elementami wizualnymi będzie zawsze wolniejsze niż w przypadku JavaScript, bo korzysta z tego JavaScriptu, a w dodatku dodaje swój narzut na callowanie zewnętrznych funkcji.
Z uwagi na to, że Blazor WebAssembly jest całkowicie niezależną aplikacją frontendową, to trzeba z nią pracować jak z tego typu aplikacją. Przede wszystkim oznacza to, że nie mamy bezpośredniego dostępu do zasobów serwera, albo do bazy danych. Musimy pracować z API, nawet jeżeli działamy w konfiguracji aplikacji Blazor WASM hostowanej w aplikacji ASP.NET.
Jednak pisząc aplikacje webowe, pewnie i tak pracowałeś i pracujesz z API HTTP, także raczej nie jest to jakaś poważna wada.
Dużą zaletą, względem Blazora Server, jest to, że aplikacja pisana w Blazor WebAssembly może działać całkowicie niezależnie od serwera. Przerwa w komunikacji klient-serwer nie powoduje, że użytkownik nic nie może zrobić. Dlatego jeżeli potrzebujemy aplikację, która ma działać również w trybie offline, to zdecydowanie potrzebny nam Blazor WebAssembly.
Dodatkowo, ten tryb renderowania, wykorzystuje do renderowania widoków i wykonywania logiki maszynę użytkownika, a nie serwer. Więc jest trybem, który nie wysyca dodatkowo zasobów naszego backendu.
Podsumowanie
Blazor jest ciekawym rozwiązaniem, które moim zdaniem jest bardzo dobrym rozwinięciem platformy .NET i ASP.NET. Oczywiście posiada swoje wady, o których nieraz również wspominam.
Obecne wydanie, które nareszcie pozwala elastycznie dobierać tryby renderowania i mieszać tryby, w których kod jest wykonywany na serwerze i w przeglądarce, daje to minimum elastyczności, którego brakowało wcześniej i co zdecydowanie mocniej przybliża Blazora do grupy technologii, które nadają się do pisania złożonych aplikacji, które będą działać na produkcji.
Ale dzisiaj miałem dla Ciebie tylko szybkie omówienie tego frameworka. Szczegóły nieraz już pokazywałem i będę pokazywał w przyszłości w osobnych materiałach.
Leave a Comment