Tworzysz warstwę usług dla mojej aplikacji MVC?

82

Z tego co rozumiem, MVC oddziela definicje klas (model) od prezentacji (widoku) za pomocą „kleju” czyli kontrolera. Kontroler powinien mieć jedną odpowiedzialność i dlatego powinien być testowalny. ViewModels są używane do łączenia danych z wielu jednostek i „masowania” danych ze sterownika dla widoku.

Wygląda na to, że logika biznesowa tak naprawdę nie ma miejsca ... więc myślę, że odpowiednia byłaby inna warstwa usług. Nie jestem tylko pewien, gdzie umieścić tę warstwę ani jak zbudować usługi - czy powinna to być klasa o nazwie „usługi”, która zawiera kilka funkcji? Jestem trochę nowy w MVC, więc wszelkie materiały do ​​czytania, próbki lub ogólne wskazówki dla nowicjuszy byłyby niesamowite.

user2062383
źródło

Odpowiedzi:

126

Zwykle używam warstwy usług podczas tworzenia aplikacji ASP.NET MVC. Jest podobny do wzorca warstwy usług, który Martin Fowler omawia w książce Patterns of Enterprise Application Architecture . Hermetyzuje logikę biznesową i sprawia, że ​​kontrolery są dość cienkie. Zasadniczo kontrolery używają warstwy usług do pobierania modeli domeny, które są następnie przekształcane w modele widoków. Używam również wzorca projektowego jednostki pracy do obsługi transakcji i wzorca projektowego repozytorium do hermetyzacji warstwy dostępu do danych w celu łatwiejszego testowania jednostkowego i możliwości łatwej wymiany ORMów. Ten rysunek przedstawia typowe warstwy, których używam w aplikacji MVC.

Architektura MVC

Warstwa usług jest oznaczona na tym diagramie jako „Warstwa aplikacji lub domeny”, ponieważ uważam, że ludzie są zdezorientowani, gdy używa się terminu „Warstwa usług”. Często myślą, że jest to usługa internetowa. W rzeczywistości jest to zestaw, który może być używany przez Twoją ulubioną technologię usług internetowych, na przykład ASP.NET Web API lub WCF, a także kontroler.

Jeśli chodzi o konwencje nazewnictwa, zwykle używam czegoś, co opisuje domenę, po której następuje usługa. Na przykład, jeśli mam warstwę usług, która obsługuje członkostwo użytkowników, miałbym klasę o nazwie MembershipService, która zawiera wszystkie metody potrzebne kontrolerom i usługom sieci Web do wykonywania zapytań i manipulowania domeną członkostwa. Pamiętaj, że możesz mieć kilka domen w tej samej aplikacji, więc możesz mieć wiele warstw usług. Chodzi mi o to, że nie musisz mieć jednej monolitycznej usługi, która zajmuje się całą aplikacją.

Kevin Junghans
źródło
7
Czy istnieje dobry przykład, który wdraża tę metodologię?
Animesh
@Animesh musisz po prostu komponować z przykładami w sieci, EF + Code First lub szablon POCO dla DAL, T4Scaffolding do generowania repozytorium i UnitOfWork, usługa to po prostu koordynacja między DAL i POCO hermetyzująca logikę biznesową. Następnie kontroler ASP.NET MVC LUB WebApi, które wywołują tylko warstwę usług i wyświetlają wyniki (ASP.NET MVC) lub
udostępniają
2
Repozytorium i UoW są niepotrzebne, prawda? Przynajmniej w twoim przykładzie, gdy musisz użyć tylko jednej technologii bazodanowej (i nie jest to DDD). Dlatego EF już zaimplementował sam UoW i wzorce repozytorium.
krypru
1
Nie wiem o tym tutaj, ponieważ podoba mi się przykład i grafika, ale wiele samouczków online niepotrzebnie używa wzorca repozytorium. Abstrahują, ponieważ mogą abstrahować bez żadnych korzyści, tylko po to, aby mogli używać interfejsu.
johnny
Niesamowite !!! Dziękuję @kevin Junghans, Twoja odpowiedź naprawdę pomogła mi w zaprojektowaniu złożonej aplikacji internetowej. Jedno krótkie pytanie, czy podczas tworzenia aplikacji internetowych opartych na mikrousługach musimy wdrażać klasy Service, czy po prostu klasy MVC wykonują robotę.
codemilan
28

Radzę stworzyć oddzielne klasy zwane „usługami”. Umieść je w innym projekcie biblioteki klas (lub przestrzeni nazw) i uniezależnij od infrastruktury platformy MVC. Polecam też użyć jakiegoś rodzaju zastrzyku zależności (najlepiej jest to wstrzyknięcie konstruktora). Twoje klasy usług mogą wtedy wyglądać tak:

 public class MyService : IMyService
 {
     IFirstDependency _firstService;
     ISecondDependency _secondService;

     public MyService(IFirstDependency firstService, ISecondDependency secondService)
     {
     }

     public Result DoStuf(InputDTO)
     {
         // some important logic         
     }
 }

Następnie korzystasz z tych usług ze swoich kontrolerów. Spójrz tu dla kompletnego przykładu.

Według Repozytoriów - radzę nie używać ich, jeśli zamierzasz korzystać z jakiegoś nowoczesnego ORM (NHibernate, EntityFramework), ponieważ Twoja logika biznesowa zostanie hermetyzowana w Warstwie Usług, a Twoja baza danych będzie już hermetyzowana w ramach ORM.

Marian Ban
źródło
4
Myślę, że problem z pominięciem sekcji repozytorium i przejściem od razu do ORM polega na tym, że twoje klasy usług otrzymają bezpośrednio kontekst ORM, co oznacza, że ​​wszystkie te klasy w twojej usłudze będą miały dostęp do wszystkich tabel, które pobrałeś do kontekstu zamiast do każdej usługi klasa pracuje tylko z potrzebnymi tabelami. Możesz tego uniknąć, przekazując DbSet do ctora każdej klasy i rozwiązując to za pomocą DI, ale możesz napotkać problemy z tym?
user441521
10

Zapoznaj się z artykułem z najlepszych praktyk MSDN.

Kod źródłowy aplikacji w artykule można znaleźć tutaj .

emre nevayeshirazi
źródło
10

Cytując z „Logika biznesowa powinna być w usłudze, a nie w modelu”? :

W architekturze MVP / MVC / MVVM / MV * usługi w ogóle nie istnieją. A jeśli tak, termin jest używany w odniesieniu do dowolnego ogólnego obiektu, który można wstrzyknąć do kontrolera lub modelu widoku. Logika biznesowa jest w Twoim modelu. Jeśli chcesz utworzyć „obiekty usługowe” do organizowania skomplikowanych operacji, jest to postrzegane jako szczegół implementacji. Niestety, wiele osób implementuje MVC w ten sposób, ale jest on uważany za anty-wzorzec (model domeny anemicznej), ponieważ sam model nic nie robi, to tylko zbiór właściwości interfejsu użytkownika.

Niektórzy ludzie błędnie myślą, że przyjęcie metody kontrolera 100-liniowego i wrzucenie tego wszystkiego do usługi w jakiś sposób tworzy lepszą architekturę. Naprawdę tak nie jest; wszystko, co robi, to dodanie kolejnej, prawdopodobnie niepotrzebnej warstwy pośredniej. Praktycznie rzecz biorąc, kontroler nadal wykonuje swoją pracę, po prostu robi to za pomocą źle nazwanego obiektu „pomocnika”. Gorąco polecam prezentację Jimmy'ego Bogarda Wicked Domain Models, aby uzyskać jasny przykład tego, jak zmienić anemiczny model domeny w użyteczny. Obejmuje dokładne zbadanie modeli, które prezentujesz, i które operacje są rzeczywiście ważne w kontekście biznesowym.

Arvand
źródło
To najlepsza odpowiedź. Wybrany mówi, aby umieścić logikę biznesową na usługach, które mają być używane w kontrolerze, ale logika biznesowa powinna być oparta na modelu.
Mateus Felipe