Pierwszy projekt w Blazorze, jaką strukturę projektów wybrać?

Zaczynasz pierwszy projekt w Blazorze. Rozpoczynanie projektów jest jednym z przyjemniejszych momentów, ja na początku sprawdzam jakie podejścia mogą usprawnić moje projekty oraz jakie są dobre praktyki, a skoro Ty czytasz ten artykuł, to zapewne Ciebie też interesuje ten temat.

W tym poście poruszymy tematy takie jak struktura aplikacji oraz dobre praktyki w budowaniu aplikacji. Na początek struktura solucji, w większości moich projektów wygląda następująco:

Ma wiele wspólnych części z Clean Architecture zaproponowanym przez Jason Taylora, zachęcam do zapoznania się z jego implementacja po dokładniejszy opis poszczególnych projektów, w skrócie ich przeznaczenie to:

Nazwa projektuOpis
MyFirstBlazorApp.ApiProjekt zawierający endopinty web api, w tym miejscu znajdować się kontrolery i konfiguracja hosta, auth czy rejestracja serwisów.
MyFirstBlazorApp.Api.DomainDomena całej aplikacji, w tym miejscu powinny znajdować się encje, agregaty czy enumy, powinna być całkowicie niezależna od innych warstw.
MyFirstBlazorApp.Api.ApplicationWarstwa realizująca logikę aplikacji, tutaj dodamy wszelkiego rodzaju interfejsy, jest to dobre miejsce na logikę związaną z CQRS. Ten wykorzystuje wykorzystuje warstwę domeny w aplikacji.
MyFirstBlazorApp.Api.InfrastructureW tym miejscu znajdą się implementacje interfejsów zadeklarowanych w aplikacji, repozytoria, kontekst bazodanowy czy metody rozszerzające.
MyFirstBlazorApp.ClientDocelowy projekt z komponentami Blazora, w tym miejscu dodamy layouty, komponenty czy konfiguracje części frontendowej.
MyFirstBlazorApp.Client.ApplicationWarstwa do logiki aplikacji po stronie frontendu, tak jak w przypadku web api dodajemy tu interfejsy i pozostałą logikę, której użyjemy w Blazorze.
MyFirstBlazorApp.Client.InfrastructureProjekt do implementowania interfejsów z warstwy aplikacji, w tym miejscu będą znajdować się serwisy do komunikacji z web api czy obsługi LocalStorage.
MyFirstBlazorApp.SharedWarstwa do współdzielenia modeli między web api, a frontendem z Blazorem.

Wszystkie przedstawione projekty mają swoje odpowiednimi w katalogu z testowymi projektami. Alternatywnie można rozpocząć projekt od utworzenia współdzielonych warstw Application, Domain oraz Infrastructure i zostawić wyłącznie Api i Client jako oddzielne projekty warstwy prezentacji. Ja zdecydowałem się na takie podejście ze względu na to, że nie chciałbym mieszać serwisów wykorzystywanych w Api poprzez część związaną z Blazorem i odwrotnie oraz z doświadczenia wiem, że o wiele łatwiej w przyszłości połączyć kilka projektów w jeden większy niż rozdzielać je na mniejsze.

Teraz pora na strukturę projektu Blazor, u mnie wygląda ona następująco:

Struktura katalogów w projekcie zorientowana jest na funkcjonalności, najważniejsze katalogi prezentują się następująco:

Nazwa kataloguOpis
PagesKatalog z komponentami reprezentującymi strony, oznaczone są dyrektywą @page, składają się z mniejszych komponentów.
SharedW tym miejscu przechowywane są layouty oraz współdzielone komponenty.
ComponentsKatalog ze strukturą z podziałem na funkcjonalności, jest to miejsce przechowywania wszystkich mniejszych komponentów z których budujemy strony.
Components/CommonKatalog z komponentami współdzielonymi między poszczególnymi funkcjonalnościami, wewnątrz katalogu jest podział na kontrolki, kontenery oraz elementy layoutów.
Components/ProductsTutaj będą znajdować się komponenty poszczególnych funkcjonalności, w tym wypadku produktów, możliwe jest dalsze zagnieżdżanie tego katalogu.
Components/SharedKatalog z komponentami współdzielonymi między funkcjonalnościami, podobnie jak Common. Różnica między tymi katalogami jest taka, że w Common przechowujemy komponenty, które mogą występować między różnymi projektami np. Button czy Card, natomiast w Shared powinny znajdować się komponenty, które są wykorzystywane w różnych funkcjonalnościach, lecz nie są generyczne np. UserAvatar w przypadku, gdy wyświetlamy użytkownika w kilku różnych miejscach.

Powyższa struktura jest wynika z moich doświadczeń z projektami frontendowymi, w tym wykorzystującymi Blazora. Trzymanie komponentów najwyższego poziomu oznaczonych dyrektywą @page w katalogu Pages pozwala szybko zorientować się w strukturze projektu, następnie orientacja na funkcjonalności w katalogu Components pozwala na odpowiednie dostosowywanie wielkości podkatalogów i rozbudowywania ich. Ogranicza to także sytuacje w której mamy spore różnice między katalogami, co jest częstym problemem, gdy zdecydujemy się na podział katalogów ze względu na typ.

Ostatnim elementem jest rejestrowanie serwisów. Możemy to zrobić w Program.cs poprzez dopisanie linijki

builder.Services.AddTransient<IService, Service>();

Może to się sprawdzić w przypadku, gdy serwisów jest niewiele, lecz ja zalecam utworzenie w każdym projekcie klasy Module w której będą metody do rejestrowania serwisów, przykładowa implementacja:

public static class InfrastructureModule
{
   public static IServiceCollection AddInfrastructure(this IServiceCollection serviceCollection)
   {
      serviceCollection.AddTransient<IService, Service>();
      return serviceCollection;
   }
}

Należy jeszcze dodać moduł w Program.cs

builder.Services.AddInfrastructure();

W ten sposób możliwe jest rejestrowanie serwisów w modułach bez potrzeby zmiany Program.cs przy każdej rejestracji, a dodatkowo mamy dokładniejszy podział podczas rejestracji serwisów, a każdy moduł możemy łatwiej przenieść i wykorzystać w innej aplikacji.

Przedstawiona struktura powinna wspomóc tworzenie i utrzymywanie kodu, a także być odporna na rozrastanie się projektu. Pamiętaj, aby pilnować separacji między projektami, wszystkie warstwy mają konkretne przeznaczenie, a trzymanie się ich pozwoli na łatwiejsze poruszanie się po projektach i uniknięcia kosztownych błędów wykorzystywania klas poza ich kontekstem.

Jeżeli uznasz ten post za przydatny to proszę udostępnij go innym, natomiast jak chcesz być na bieżąco i otrzymywać informacje o moich aktywnościach przed innymi to zapraszam Cię do newslettera na którym regularnie udostępniam przedpremierowo artykuły, materiały wideo i wiele więcej.

Share via
Copy link
Powered by Social Snap