Architektura / warstwowanie projektu .NET MVC

11

Jak planujesz architekturę aplikacji internetowej MVC na dużą skalę, w jaki sposób wdrażasz warstwy, aby były możliwie jak najbardziej rozdzielone i łatwe do przetestowania? (w zasadzie postępuj zgodnie z najlepszymi praktykami) Powiedzmy, że najpierw używam kodu jako dostępu do danych.

Mam problem z tym, co zdefiniować jako „logikę biznesową” i jak ma ona oddziaływać z warstwą danych. Biorąc za przykład aplikację do sprzedaży pojazdów, czy logika biznesowa byłaby klasami wykonującymi zadania, takie jak obliczanie zakresu podatkowego dla danych pojazdów, porównywanie statystyk mil na galon itp.? Jeśli chodzi o podmioty gospodarcze (np. Samochody osobowe, dostawcze, motocykle), umieściłbym je w warstwie danych wraz z moją DataContextklasą.

Co też stanowiłoby logikę aplikacji w przeciwieństwie do biznesu - zgaduję takie rzeczy jak weryfikacja danych wejściowych sesji / użytkownika?

Na przykład kontroler samochodowy może zwrócić wynik działania / widoku, który zawiera listę dziesięciu najlepszych samochodów filtrowanych według typu i najlepszego mpg. Powiedzmy, że mam ICarRepository„carRepo” wstrzyknięty do mojego kontrolera (używając wzorca repozytorium / DI), filtruję moje samochody na podstawie parametru metody akcji, np.var cars = carRepo.getCarsByType("hatchback");

Więc trzymałem wiedzę o dostępie do danych poza moim kontrolerem za pomocą repozytorium, teraz, aby utrzymać logikę biznesową poza kontrolerem za pomocą modelu domeny - var result = new MpgCalculator (samochody); - Powiedzmy, że potrzebuję klasy kalkulatora, ponieważ musi ona wykonać dodatkową logikę, aby obliczyć najlepszą efektywność paliwową, więcej niż tylko ładowanie / filtrowanie jednostek z bazy danych. Mam teraz zestaw danych do renderowania, który używał repozytorium do pobierania z warstwy dostępu do danych, oraz obiekt specyficzny dla domeny do przetwarzania i wykonywania zadań związanych z biznesem na tych danych.

Czy popełniam tutaj błędy? czy nadal musimy używać wzorca repozytorium, czy mogę po prostu kodować interfejs, aby oddzielić ORM i przetestować? W tym temacie, ponieważ moje konkretne klasy danych dostępu do kontekstu dbcontext znajdują się w warstwie danych, czy definicje interfejsu powinny przejść do warstwy domeny / biznesu, co oznacza, że ​​jeśli technologia dostępu do danych zostanie kiedykolwiek zmieniona, moje pozostałe warstwy nie zostaną zmienione?

Z tego, co dotychczas studiowałem, moja struktura wygląda następująco:

Aplikacja internetowa MVC -> Standardowy projekt internetowy - modelami tutaj są ViewModels

Domena / warstwa biznesowa -> klasy / modele specyficzne dla biznesu, których kontrolery mogą używać do przetwarzania jednostek domeny z warstwy danych przed przejściem do odpowiednich widoków

Czy konieczna jest abstrakcja repozytorium? -> Słyszę wiele debat na ten temat, zwłaszcza gdy używam ORM

Warstwa danych -> Klasy jednostek (samochód, furgonetka, motocykl), DbContext - konkretna warstwa technologii dostępu do danych

Michael Harper
źródło

Odpowiedzi:

26

Masz wiele ruchomych części w swoim pytaniu, dotykających wielu pojęć, ale oto moja podstawowa rada, jeśli chodzi o myślenie o aplikacji MVC o średniej i dużej skali:

Prezentacja <---> Logika biznesowa <---> Dostęp do danych

Po pierwsze, najlepiej nie myśleć o aplikacji jako o „aplikacji MVC”. Jest to aplikacja, która wykorzystuje wzorzec MVC jako składnik prezentacji. Myślenie o tym w ten sposób pomoże ci oddzielić obawy związane z logiką biznesową od problemów związanych z prezentacją . Być może małe aplikacje mogą nakładać wszystko, aż do dostępu do bazy danych do struktury MVC, ale szybko stanie się niemożliwe do zastosowania w przypadku średnich i dużych aplikacji.

MVC (prezentacja)

W Twojej aplikacji komponent ASP.NET MVC powinien zajmować się przekształcaniem danych biznesowych do celów wyświetlania (modele), wyświetlaniem interfejsu użytkownika (widoki) oraz problemami z komunikacją, takimi jak routing, uwierzytelnianie, autoryzacja, sprawdzanie poprawności żądań, obsługa odpowiedzi i jak (Kontrolery). Jeśli masz kod, który robi coś innego, to nie należy on do komponentu MVC .

Repozytorium / ORM (dostęp do danych)

Również w Twojej aplikacji warstwa dostępu do danych powinna zajmować się odzyskiwaniem i przechowywaniem trwałych danych. Zwykle ma to postać relacyjnej bazy danych, ale istnieje wiele innych sposobów utrwalania danych. Jeśli masz kod, który nie odczytuje ani nie przechowuje trwałych danych, nie należy on do warstwy danych . Dzieliłem się przemyśleniami na temat dyskusji na temat ORM / repozytorium wcześniej na SO, ale podsumowując, nie uważam ORM za to samo co repozytorium, z kilku powodów.

Logika biznesowa

Masz teraz warstwę prezentacji (MVC) i warstwę danych (repozytorium lub ORM) ... Cała reszta to warstwa logiki biznesowej (BLL). Powinien tu znajdować się cały kod, który decyduje o tym, które dane należy pobrać, wykonuje skomplikowane obliczenia lub podejmuje decyzje biznesowe. Zwykle organizuję swoją logikę biznesową w formie „usług”, do których moja warstwa prezentacji może wezwać do wykonania żądanej pracy. Wszystkie moje modele domen istnieją tutaj.

Twoje podejście

To dla mnie twoje podejście trochę się psuje. Opisujesz swój kontroler MVC jako miejsce, w którym uzyskasz dane z repozytorium, i wzywasz MPGCalculator do wykonania jakiejś pracy itp. Nie chciałbym, aby mój kontroler zrobił to wszystko, ale zamiast tego oddelegowałby to wszystko do usługi w BLL.

Innymi słowy, nie wstrzykiwałbym repozytorium i MPGCalculator do kontrolera, co daje kontrolerowi zbyt dużą odpowiedzialność (już zajmuje się wszystkimi rzeczami kontrolera , o których wspomniałem powyżej). Zamiast tego chciałbym, aby usługa w BLL obsługiwała to wszystko i przekazała wyniki z powrotem do kontrolera. Kontroler może następnie przekształcić wyniki we właściwy model i przekazać go do poprawnego widoku. Kontroler nie ma w sobie żadnej logiki biznesowej, a jedyne rzeczy, które zostaną do niego wprowadzone, to odpowiednie usługi BLL.

Postępowanie w ten sposób oznacza, że ​​logika biznesowa (na przykład biorąc pod uwagę zestaw pojazdów, oblicz MPG i sortuj najlepiej od najgorszego ) jest niezależna od problemów związanych z prezentacją i trwałością. Zwykle będzie w bibliotece, która nie zna strategii utrwalania danych ani strategii prezentacji ani nie dba o to.

Eric King
źródło
Cześć Eric, doskonała odpowiedź - w odniesieniu do repozytoriów zakładam, że konkretne klasy żyłyby w warstwie dostępu do danych i „ICarRepository” itp. W warstwie biznesowej / usługowej? Następnie mógłbym wprowadzić usługi do mojego kontrolera, który może zawierać 1 lub więcej repozytoriów w zależności od wymagań?
Michael Harper,
@MichaelHarper Tak, to brzmi jak całkiem dobry sposób na zrobienie tego.
Eric King,
1
Podczas gdy uwierzytelnianie jest sprawą kontrolera (różne interfejsy uwierzytelniają się inaczej) powiedziałbym, że autoryzacja jest logiką biznesową i należy do warstwy biznesowej. Czy sie zgadzasz?
tom
1
@tom Tak, masz rację. Myślałem o prostej autoryzacji, ponieważ użytkownik ma dostęp do tej trasy , ale może być o wiele więcej. Część „dużo więcej” należy do warstwy biznesowej.
Eric King
1
@HunterNelson Jeśli mapujesz na model widoku, mapowanie powinno nastąpić tam, gdzie jest widok, w warstwie prezentacji. Nigdzie indziej nie miałoby to sensu.
Eric King,
0

Wygląda na to, że wszystko jest w porządku dla twojej struktury. Jedyne, czego nie jestem pewien, to to, że wspominasz, że modele w MVC to „ViewModels” i że kontrolery komunikują się z warstwą domeny. Myślę, że ma to sens, jeśli domyślnym wzorcem jest użycie kontrolera do uzyskania dostępu do warstwy domeny, a następnie użycie „ViewModels” jako bardziej specyficznych dla widoku kompilacji informacji z wielu jednostek domeny, co ma sens dla tego konkretnego widoku. Jeśli to właśnie robisz, prawdopodobnie nic ci nie jest.

Istnieje szkoła myślenia, że ​​powinieneś mieć pełną abstrakcję warstwy domeny w swojej aplikacji MVC, jeśli chcesz ją mieć. Osobiście myśl o zrobieniu tego w aplikacji korporacyjnej powoduje silne bóle psychiczne.

Wolę używać wzorca repozytorium do zarządzania dostępem do warstwy danych, ponieważ poprawia to testowalność i elastyczność. Dwie najbardziej drastyczne zmiany to interfejs użytkownika i baza danych. Wyobraź sobie, że niektóre informacje, które wyciągasz bezpośrednio z bazy danych, zostały zmienione, tak że trzeba je pobrać z wywołania usługi, a nie z połączenia z bazą danych, lub niektóre informacje zostały przeniesione do innej bazy danych wymagającej innego pliku .edmx plik. Wzorzec repozytorium zapewnia abstrakcję na poparcie tego.

wpenberthy
źródło
Dziękuję za odpowiedź William 😊 Uważam moje obiekty biznesowe / logikę i podmioty domeny za „modele”, których kontroler używa do przetwarzania działań użytkownika i modeli widoków, za widok konkretnych modeli, które mogą zawierać grupy modeli itp.
Michael Harper,