Piszę o programowaniu w ASPNET CORE. Jaką architekturę wybrać dla swojego projektu

Clean Architecture

Clean Architecture 101. Tworzenie solucji w .NET CORE.

Założymy dzisiaj projekt od zera, stosując model Clean Architecture. Zaczniemy od dodania odpowiednich projektów reprezentujących warstwy. Następnie dodamy referencje pomiędzy nimi, ustalając przez to kierunek komunikacji. Zakończymy dodaniem folderów na kod, który pojawi się w kolejnym wpisie oraz pozbyciem się zbytecznych plików. Przy każdym kroku postaram się Ci rozjaśnić „co i dlaczego”.

Solucja w Clean Architecture

Wykorzystamy tutaj terminal (tj. PowerShell) oraz .NET Core CLI. Oczywiście wszystkie operacje można wykonać z poziomu GUI, jednak terminal jest po prostu szybszy i bardziej efektowny (#hacker). Dodam tylko jeszcze że korzystam z Windowsa.

Stwórzmy folder w którym będzie znajdować się nasza aplikacja.

mkdir MyCleanArchitecture #make directory 
cd MyCleanArchitecture    #change directory 

Teraz przy użyciu .NET Core CLI dodamy solucję, czyli kontener na projekty.

dotnet new sln -n MyCleanArchitecture

Następnie tworzymy dwa foldery i od razu przechodzimy do pierwszego z nich – znajdować będzie się w nim nasza aplikacja, drugi jest na testy.

mkdir src
mkdir tests
cd src

Projekty w Clean Architecture

Tworzymy kolejno trzy projekty (odwzorowujące warstwy). Dwa z nich będą typu classLib, jeden zaś webApi. Ten ostatni będzie punktem wejścia dla aplikacji – czyli StartUp Project.

dotnet new classlib -n ApplicationCore -f netcoreapp3.1 --no-restore
dotnet new classlib -n Infrastructure -f netcoreapp3.1 --no-restore
dotnet new webapi -n WebApi -f netcoreapp3.1 --no-restore

-n „nazwa” – opcja oznaczająca jak ma zostać nazwany tworzony projekt
-f „framework” – narzucamy wersję platformy np. netcoreapp3.1 to .NET CORE 3.1
–no-restore – po stworzeniu projektu nie będą pobierane jego zależności (nie wykona się dotnet restore)

Kolejny krok to dodanie projektów do pliku solucji. Po wykonaniu tego kroku, za każdym razem gdy otworzymy MyCleanArchitecture.sln w Visual Studio, załadowane zostaną nasze projekty.

dotnet sln ..\MyCleanArchitecture.sln add .\WebApi\
dotnet sln ..\MyCleanArchitecture.sln add .\ApplicationCore\
dotnet sln ..\MyCleanArchitecture.sln add .\Infrastructure\

Wskazujemy referencje pomiędzy projektami. W taki sposób nadajemy kierunek komunikacji.

dotnet add .\Infrastructure\ reference .\ApplicationCore\
dotnet add .\WebApi reference .\ApplicationCore\
dotnet add .\WebApi reference .\Infrastructure\

Foldery na kod

A teraz kilka folderów na nasze klasy oraz opis do czego służą.

mkdir .\ApplicationCore\Interfaces    # Interfejsy
  • Interfejsy – są abstrakcyjnymi kontraktami które będziemy implementować w konkretnych serwisach. Najważniejsze jest to, że nie wszystkie zostaną zaimplementowane własnie w tej warstwie, ponieważ zależeć mogą od środowiska czy wersji aplikacji. Przykłady:
    • IDriversLicenseService.cs – gdzie zdefiniujemy metody HandleDriversLicenseApplication, RevokeDriversLicense
    • INotificationService – zaimplementujemy go dopiero na warstwie Infrastructure gdzie w zależności od środowiska (produkcyjne/deweloperskie) wyślemy maila lub smsa. Pozwala to ująć „powiadomienie osoby wnioskującej o wydaniu prawo jazdy” w logice domenowej bez potrzeby wiązania się z konkretną usługą
mkdir .\ApplicationCore\Entities          # Model danych
mkdir .\ApplicationCore\Exceptions        # Wyjątki
mkdir .\ApplicationCore\Services          # Serwisy domenowe
mkdir .\ApplicationCore\Specifications    # Specyfikacje
  • Model danych – wszystkie klasy które występują w naszej domenie, odwzorowania realnych bytów. Przykład: DriversLicense.cs, DriversLicenseApplication.cs (wniosek o prawo jazdy), Driver.cs
  • Wyjątki – zrozumiałe samo przez się. Przykład: UnderAgeDriverException.cs
  • Serwisy- konkretne implementacje wyżej wymienionych interfejsów. Przykład: DriversLicenseService.cs (:IDriversLicenseService.cs)
  • Specyfikację – klasy zawierające opis jakie elementy modelu dane mają zostać pobrane, jak po filtrowane itp. Ogólnie implementacja Specification Patern. Przykład: DriverWithLicenseSpecification.cs
mkdir .\Infrastructure\Data\Configs      # Konfiguracje
mkdir .\Infrastructure\Data\Migrations   # Migracje modelu bazy danych
mkdir .\Infrastructure\Services          # Serwisy zewnętrzne
  • Konfiguracje – znajdą tu miejsce wszystkie konfiguracje relacji pomiędzy encjami. Zamiast używać na modelu danych (ApplicationCore) adnotacji z EntityFramework-a, użyjemy fluent API. Przykład: DriverConfiguration.cs w której znajdą się wpisy o relacjach encji Drivers
  • Migracje – kod wygenerowany przez EntityFramework, w którym znajdują się opisy zmian w modelu bazy danych
  • Serwisy – implementacje interfejsów (m.in z ApplicationCore), znajdziemy głównie tutaj dostęp do bazy danych, usług notyfikacyjnych. Przykład: NotificationService (implementujący INotificationService z warstwy domenowej) czyli nasz zarządca powiadomień (e-mail, sms, telefon a może nawet człowiek…)
Clean Architecture
Stworzona przez nas solucja

A teraz pora sfinalizować nasze wysiłki. Pobieramy wymagane biblioteki, budujemy i działa (nie ma jeszcze co, ale(!!!) przynajmniej się buduje).

cd ..           #uciekamy do poziomu solucji
dotnet restore  #pobranie brakujących bibliotek - Nugetów
dotnet build    #budowanie projektu

⭐ BONUSOWY KONTENT ⭐

Stworzone przez nas foldery nie będą widoczne w solucji do czasu aż nie do damy do nich jakiegoś pliku lub nie załączymy ich do odpowiednich projektów. Najprościej zrobimy to poprzez edytowanie pliku *.csproj (np. ApplicationCore.csproj) i dodać tagi <Folder Include=”Entities\” /> go jak poniżej, :

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <TargetFramework>netcoreapp3.1</TargetFramework>
  </PropertyGroup>

  <ItemGroup>
    <Folder Include="Entities\" />
    <Folder Include="Exceptions\" />
    <Folder Include="Services\" />
    <Folder Include="Specifications\" />
  </ItemGroup>

</Project>

Dodatkowo w WebApi\Properties\launchSettings.json zmieniamy linie

"launchUrl": "weatherforecast",

na (zarówno w profilu „IIS Express” jak i „WebApi”)

"launchUrl": "",

Następnie możemy pozbyć się przykładowych klas z projektów. Aby to uczynić z poziomu folderu src uruchamiamy:

rm .\ApplicationCore\Class1.cs
rm .\Infrastructure\Class1.cs
rm .\WebApi\WeatherForecast.cs
rm .\WebApi\Controllers\WeatherForecastController.cs

Z racji że git nie obsługuje dodawania pustych folderów, dodałem do każdego z tych folderów emptyFile.txt. Zrobiłem to tylko żeby było Ci łatwiej zobaczyć co mam na myśli. Na repo znajduję się też cały skrypt a więc serdecznie ZAPRASZAM!

A tu mamy link do repo!

Podsumowanie

Udało nam się zrobić pierwszy krok ku lepszemu jutrze naszego kodu! Stworzyliśmy projekty, dodaliśmy zależności pomiędzy nimi oraz dodaliśmy foldery na nasze klasy. Najważniejsze że wiemy gdzie będą się znajdować kolejne elementy!

W kolejnym wpisie zajmiemy się implementacją modelu danych, procesów biznesowych oraz tego, co mi wpadnie do głowy.

Previous

Jaką architekturę wybrać dla swojego projektu? 3 Propozycje

Next

Programowanie 101. Enkapsulacja, hermetyzacja czy kapsułkowanie?

3 Comments

  1. Janek

    swietny post !!! 🙂

  2. luke

    Czekam na kolejny artykuł z rozwijania projektu zachowując Clean Architecture i wykorzystując Entity Framework.

    Pamiętaj, że warstwa aplikacji i domeny nie może mieć zależności do paczek EF!

1 Pingback

  1. dotnetomaniak.pl

Dodaj komentarz

Twój adres email nie zostanie opublikowany. Pola, których wypełnienie jest wymagane, są oznaczone symbolem *

Powered by WordPress & Theme by Anders Norén