W końcu nastąpił większy postęp w mojej aplikacji! Bardzo się z tego cieszę, szczególnie, że początki nie były łatwe i wywołały u mnie frustrację i tym samym niechęć do dalszej pracy nad projektem. W końcu również widać efekty w postaci wywołania API i zwrócenia wyników w JSON. Dziś opiszę co udało mi się zrealizować.
Wzorce w praktyce
Na wstępnie chciałbym zaznaczyć, że nie udałoby mi się tego wszystkiego zrealizować gdyby nie fantastyczny kurs Piotrka Gankiewicza - Becoming a software developer. Udało mi się zastosować w praktyce wzorzec Onion Architecture, a przynajmniej na tyle ile go zrozumiałem. Oczywiście wszystko to małe kroki, ale są one dla mnie bardzo ważne. Opiszę wszystko na przykładzie klasy User
, która jest najbardziej dopracowana.
Klasa domenowa User
wygląda następująco:
Jak widać walidacja danych następuje przed utworzeniem instancji klasy, zwracane są odpowiednie wyjątki. Kwestia uwierzytelniania i przechowywania hasła nie jest jeszcze rozwiązana, ale to na ten moment nie jest kluczowe.
Następnie utworzyłem repozytorium z interfejsem IUserRepository
, po to żeby było wiadomo jakie operacje będzie można wykonywać na obiektach domenowych, jednocześnie nie ma tutaj uzależnienia od implementacji sposobu realizowania tych zadań.
Kolejnym krokiem już w projekcie DataBoard.Infrastructure
utworzyłem klasę UserDTO
bez zbędnych metod, która będzie transferować do projektu DataBoard.Web
tylko część informacji. Zostanie ona oczywiście rozszerzona, tylko wstępnie tak wygląda.
W DataBoard.Infrastructure
znajduje się właściwa implementacja repozytorium UserRepository
. Wstępnie wygląda następująco. Jest ona powiązana z bazą danych oraz Entity Framework Core. Za pomocą wbudowanych mechanizmów w ASP.NET Core DependencyInjection wstrzykuje zależność “kontekstu” bazy danych.
Sam kontekst wygląda następująco
Również w DataBoard.Infrastracture
znajdują się usługi, które udostępniane są dla DataBoard.Web
, tak aby ten ostatni nie miał świadomości o tym skąd i w jaki sposób są pobierane dane. Jako zależności wstrzykuje tutaj interfejs IUserRepository
oraz IMapper
. Ten drugi pozwala na transofrmację obiektu domenowego w obiekt DTO.
Na samym końcu “układu pokarmowego” (a może jednak na początku) znajduje się DataBoard.Web
i kontroler UserController
. Tu również następuje wstrzyknięcie zależności, w tym wypadku wcześniej wspomnianej usługi IUserService
.
Po wywołaniu adresu http://localhost:5000/api/users otrzymuję listę użytkowników zapisanych w bazie danych w formacie JSON.
Problemy
Najwięcej problemów przyniosło mi zastosowanie Entity Framework Core. Co prawda opisywałem na swoim blogu jak można go zastosować w aplikacji, ale była ta prosta aplikacj bez podziałów na warstwy.
Po pierwsze w Databoard.Web
Startup.cs
musiałem wstrzyknąć kontekst bazy danych services.AddDbContext<DataboardContext>(options => options.UseSqlServer("Data Source=localhost;Database=Databoard;User ID=sa;Password=4BEsFpaq"));
a w nim ConnectionStringa.
Kolejny problem stanowiło to, że kontekst bazy danych znajdował się w DataBoard.Infrastructure
, wywołanie dla tego projektu dotnet ef migrations add InitialCreate
kończyło się błędem:
Niestety nie zrozumiałem co należy zrobić, aż natknąłem się na to rozwiązanie na GitHub.
Uruchomiłem polecenie dotnet ef --startup-project ../DataBoard.Web/ migrations add InitialCreate
a następnie dotnet ef --startup-project ../DataBoard.Web/ database update
, najpierw zostały utworzone pierwsze pliki migracyjne, a następnie została zmodyfikowana baza danych.
Dodatkowo, aby wypełnić bazę danych “dummy data” wywołuję statyczną metodę, która zostaje wywołana wraz ze startem aplikacji.
Co dalej
Backend zaczął działać, teraz muszę się skupić na frontendzie. Zbuduję podstawową główną stronę opierając się na Bootstrapie dołączę do tego komponenty napisane w Vue.js, które będą konsumować API. Nie wiem czy jest to rozwiązanie optymalne, czy w ogóle prawidłowe, ale na pewno muszę napierać do przodu :)