Erstellen einer Service-Schicht für meine MVC-Anwendung?

82

Soweit ich weiß, trennt MVC die Klassendefinitionen (Modell) von der Präsentation (Ansicht) über den "Kleber", der die Steuerung darstellt. Der Controller sollte eine einzige Verantwortung haben und daher testbar sein. ViewModels werden verwendet, um Daten von mehreren Entitäten zusammenzuführen und die Daten vom Controller für die Ansicht zu "massieren".

Es scheint, dass Geschäftslogik nicht wirklich einen Platz hat ... also denke ich, dass eine andere Ebene für Services geeignet wäre. Ich bin mir nur nicht sicher, wo diese Ebene platziert werden soll oder wie die Services erstellt werden sollen. Sollte es sich um eine Klasse namens "Services" handeln, die eine Reihe von Funktionen enthält? Ich bin ein bisschen neu in MVC, daher wäre jedes Lesematerial, Beispiele oder allgemeine Tipps für Neulinge fantastisch.

user2062383
quelle

Antworten:

126

Normalerweise verwende ich eine Service-Schicht, wenn ich eine ASP.NET MVC-Anwendung entwickle. Es ähnelt dem Service-Layer-Muster , das Martin Fowler in Patterns of Enterprise Application Architecture erläutert . Es kapselt Ihre Geschäftslogik und macht die Controller ziemlich dünn. Grundsätzlich verwenden die Controller die Serviceschicht, um die Domänenmodelle abzurufen, die dann in Ansichtsmodelle umgewandelt werden. Ich verwende auch das Unit of Work-Entwurfsmuster , um Transaktionen abzuwickeln, und das Repository-Entwurfsmuster , um die Datenzugriffsschicht zu kapseln, um das Testen von Einheiten zu vereinfachen und ORMs einfach auszutauschen. Diese Abbildung zeigt die typischen Ebenen, die ich in einer MVC-Anwendung verwende.

MVC-Architektur

Die Serviceschicht wird in diesem Diagramm als "Anwendungs- oder Domänenschicht" bezeichnet, da die Leute verwirrt sind, wenn Sie den Begriff "Serviceschicht" verwenden. Sie neigen dazu zu denken, dass dies ein Webdienst ist. Es handelt sich tatsächlich um eine Assembly, die von Ihrer bevorzugten Webdiensttechnologie wie ASP.NET Web API oder WCF sowie von einem Controller verwendet werden kann.

Für Namenskonventionen verwende ich normalerweise etwas, das die Domäne beschreibt, gefolgt vom Dienst. Wenn ich beispielsweise eine Service-Schicht habe, die die Benutzermitgliedschaft verwaltet, hätte ich eine Klasse namens MembershipService, die alle Methoden enthält, die von Controllern und Webdiensten zum Abfragen und Bearbeiten der Mitgliedschaftsdomäne benötigt werden. Beachten Sie, dass Sie möglicherweise mehrere Domänen in derselben Anwendung haben, sodass Sie mehrere Service-Layer haben können. Mein Punkt ist hier, dass Sie nicht einen einzigen monolithischen Dienst haben müssen, der sich um die gesamte Anwendung kümmert.

Kevin Junghans
quelle
7
Gibt es ein gutes Beispiel, das diese Methodik implementiert?
Animesh
@Animesh Sie müssen nur mit Beispielen im Netz, EF + Code First oder POCO-Vorlage für DAL, T4Scaffolding zum Generieren von Repository und UnitOfWork komponieren. Service ist nur eine Koordination zwischen DAL und POCO, die die Geschäftslogik kapseln. Dann ASP.NET MVC Controller ODER WebApi, die nur die Serviceschicht aufrufen und Ergebnisse anzeigen (ASP.NET MVC) oder sie einem anderen Client (ASP.NET WebApi) zur Verfügung stellen
riadh gomri
2
Das Repository und die UoW sind nicht erforderlich, nicht wahr? Zumindest in Ihrem Beispiel, wenn Sie nur eine Datenbanktechnologie verwenden müssen (und es ist nicht DDD). Aus diesem Grund hat EF bereits UoW- und Repository-Muster selbst implementiert.
Krypru
1
Ich weiß es hier nicht, da mir das Beispiel und die Grafik gefallen, aber viele Online-Tutorials verwenden das Repository-Muster unnötig. Sie abstrahieren, weil sie ohne Nutzen abstrahieren können, nur damit sie eine Schnittstelle verwenden können.
Johnny
Genial !!! Vielen Dank an @kevin Junghans. Ihre Antwort hat mir wirklich geholfen, komplexe Webanwendungen zu entwickeln. Eine kurze Frage: Müssen wir bei der Entwicklung von auf Mikrodiensten basierenden Webanwendungen Serviceklassen implementieren oder erledigen MVC-Klassen einfach die Aufgabe?
Codemilan
28

Mein Rat ist, separate Klassen namens "Dienste" zu erstellen. Fügen Sie sie in ein anderes Klassenbibliotheksprojekt (oder Namespace-Projekt) ein und machen Sie sie unabhängig von der MVC-Framework-Infrastruktur. Ich empfehle auch eine Art Abhängigkeitsinjektion (die beste ist die Konstruktorinjektion). Dann sehen Ihre Serviceklassen möglicherweise so aus:

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

     public MyService(IFirstDependency firstService, ISecondDependency secondService)
     {
     }

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

Dann nutzen Sie diesen Dienst von Ihren Controllern. Schauen Sie hier für ein vollständiges Beispiel.

Laut Repositories - mein Rat ist, sie nicht zu verwenden, wenn Sie ein modernes ORM (NHibernate, EntityFramework) verwenden, da Ihre Geschäftslogik in der Serviceschicht gekapselt ist und Ihre Datenbank bereits im ORM-Framework gekapselt ist.

Marian Ban
quelle
4
Ich denke, das Problem beim Überspringen des Repository-Abschnitts und beim direkten Aufrufen des ORM besteht darin, dass Ihre Serviceklassen direkt den ORM-Kontext erhalten, was bedeutet, dass alle Klassen in Ihrem Service Zugriff auf alle Tabellen haben, die Sie anstelle jedes Service in den Kontext gezogen haben Klasse, die nur mit den Tabellen arbeitet, die sie benötigt. Sie könnten dies vermeiden, indem Sie DbSets an den Ctor jeder Klasse übergeben und dies mit DI lösen, aber Sie könnten auf Probleme damit stoßen?
user441521
10

Lesen Sie den Artikel aus den Best Practices von MSDN.

Der Quellcode der Anwendung im Artikel finden Sie hier .

emre nevayeshirazi
quelle
10

Zitat aus "Geschäftslogik sollte in einem Service sein, nicht in einem Modell"? ::

In einer MVP / MVC / MVVM / MV * -Architektur sind überhaupt keine Dienste vorhanden. In diesem Fall bezieht sich der Begriff auf ein generisches Objekt, das in einen Controller oder ein Ansichtsmodell eingefügt werden kann. Die Geschäftslogik ist in Ihrem Modell. Wenn Sie "Serviceobjekte" erstellen möchten, um komplizierte Vorgänge zu orchestrieren, wird dies als Implementierungsdetail angesehen. Viele Leute implementieren MVC leider so, aber es wird als Anti-Pattern (Anemic Domain Model) angesehen, da das Modell selbst nichts tut, sondern nur eine Reihe von Eigenschaften für die Benutzeroberfläche.

Einige Leute denken fälschlicherweise, dass eine 100-Zeilen-Controller-Methode, die alles in einen Dienst umwandelt, irgendwie zu einer besseren Architektur führt. Das tut es wirklich nicht. Alles, was es tut, ist eine weitere, wahrscheinlich unnötige Indirektionsebene hinzuzufügen. In der Praxis erledigt der Controller die Arbeit immer noch, nur über ein schlecht benanntes "Helfer" -Objekt. Ich empfehle Jimmy Bogards Präsentation " Wicked Domain Models" als ein klares Beispiel dafür, wie aus einem anämischen Domain-Modell ein nützliches wird. Dabei wird sorgfältig geprüft, welche Modelle Sie verfügbar machen und welche Vorgänge in einem Geschäftskontext tatsächlich gültig sind.

Arvand
quelle
Dies ist die beste Antwort. Der ausgewählte sagt, dass Geschäftslogik auf Dienste angewendet werden soll, die in der Steuerung verwendet werden sollen, aber Geschäftslogik sollte auf dem Modell sein.
Mateus Felipe