MVC: Wo soll die Geschäftslogik platziert werden? [geschlossen]

81

Zuallererst habe ich viele Fragen dazu gesehen, aber nicht genug Gründe dafür. Wenn meine Frage nicht gut genug ist und entfernt werden sollte, werde ich verstehen.

Ich habe mir zum Beispiel diese und eine Antwort von mehr als 45 Stimmen angesehen, die besagt, dass er Ihnen rät, die Geschäftslogik in das Modell aufzunehmen, was ziemlich logisch klingt.

Mein erstes großes Projekt habe ich jedoch mit all meinem BL vollständig in den Controllern durchgeführt, da ich diese Dinge nicht in Frage gestellt habe und nachgesehen habe, wie es in AccountControllerdem automatisch hinzugefügten Projekt gemacht wird, wenn Sie MVC mit Formularauthentifizierung auswählen. Alle Methoden sehen ziemlich voll mit BL aus. Oder ist es vielleicht die geringste Menge an Code, die hinzugefügt werden konnte, und ich übersehen Dinge?

Eine Person auf Youtube fragte mich, ob er Recht habe, indem er die gesamte Logik in seine Modelle einbaute, und zuerst war ich nein! Dann fing ich an zu denken, dass er vielleicht Recht hatte!?

Wo lege ich meine Geschäftslogik hin? Wenn es sich um Modellklassen handelt, wie viel Code sollte dann in einer Methode, die sich im Controller befindet, als fehlerfreie Menge betrachtet werden? Eine Zeile, um höchstens eine Methode aus dem Modell in einem Controller aufzurufen und dann zur Ansicht zurückzukehren?

Andrius Naruševičius
quelle
1
Geschäftslogik geht in die Controller. Modelllogik geht in das Modell. Modelllogik ist Dinge, die sich spezifisch / nur mit dem Modell befassen. Setter / Getter / Eigenschaften / Addierer / Entferner usw.
Crush
1
@crush: Ich stimme nicht zu. Wie ich gelesen habe - "Ein
Modellobjekt enthält
@BobbyDigital - können Sie einen Link zur Quelle bereitstellen? :)
Andrius Naruševičius
Sicher, es ist in der Erklärung der richtigen MVC-Verwendung im Big Nerd Ranch Guide enthalten, aber leider müssen Sie das Buch kaufen, um dies zu bestätigen.
ChiefTwoPencils
Ich werde jedoch sagen, nachdem ich gerade versucht habe, dies in einem C # -Buch zu bestätigen, geht die Geschäftslogik in asp.net in die mittlere Ebene, wobei die oberste Ebene die Benutzeroberfläche, die mittlere Ebene der Controller und die unterste Ebene die Datenbank ist. Aber sie sprechen nicht spezifisch / explizit über MVC. Dies kommt von C # für Programmierer :)
ChiefTwoPencils

Antworten:

54

Ich bevorzuge es aus mehreren Gründen, Domänenlogik in das Modell aufzunehmen.

  1. Das Modell sollte keinen UI-Code enthalten und daher einfacher zu testen sein. Wann immer möglich, möchte ich ein voll funktionsfähiges Modell (dh vollständige Testabdeckung) haben, bevor ich einen UI-Code schreibe. Der Controller kann darauf vertrauen, dass das Modell das Richtige tut, und sich nur mit Bedenken hinsichtlich der Benutzeroberfläche befassen.

  2. Wenn Sie Domänenlogik in einen Controller einfügen, ist die gemeinsame Nutzung zwischen verschiedenen Apps oder sogar zwischen verschiedenen Controllern nicht so einfach.

Ferruccio
quelle
2
Ja, das hat mir sehr gut gefallen, #2weil ich es schwierig fand, es selbst zwischen den Controllern zu teilen (ich musste Methoden wie statische verwenden)!
Andrius Naruševičius
Ja @ AndriusNaruševičius, tu das nicht. Sie sollten versuchen, Ihre Abhängigkeiten in Controller einzufügen und sich nicht auf andere Controller verlassen.
Mark Walsh
Beachten Sie, dass ich denke, dass diese Antwort über "Domänenmodelle" (M Teil des klassischen MVC-Pattens) spricht, was etwas ist, das nichts mit dem ASP.Net MVC "Modell" (Teil des MVVM-Musters) zu tun hat.
Alexei Levenkov
1
Also ... wo setzen Sie Logik ein, die auf mehreren Modellen beruht?
Kolob Canyon
1
@Ferrucio Das ist eine schlechte Lösung. Sie landen in einer "Abhängigkeitshölle", in der Sie Objekte erstellen, die auf anderen zu erstellenden Objekten beruhen. Es ist eine schlechte Lösung, da unnötige / nicht verwendete Daten ohne Grund weitergegeben werden. Sie möchten, dass Funktionen nur das übernehmen, was sie für die Erledigung der Aufgabe benötigen. Andernfalls wird der Code sehr schnell unklar. Die bessere Lösung besteht darin, Geschäftslogikklassen zu erstellen, deren Erstellung das Nötigste erfordert (oder noch besser, verwenden Sie die Abhängigkeitsinjektion, um erstellt zu werden). Auf diese Weise müssen Sie nie mehrere nicht verwandte Objekte abrufen, um die Geschäftslogik auszuführen.
Kolob Canyon
43

Ich mag es, meine Modelle sauber zu halten, dh nur mit Eigenschaften und ohne Geschäftslogik. Ich denke immer, dass es gut ist, Abhängigkeiten in den Controller einzufügen, und diese Abhängigkeiten enthalten die Logik, die ich für meine Modelle ausführe. Ich halte mich nach Möglichkeit gerne an das Prinzip der Einzelverantwortung und finde, dass Modelle mit unzähligen Methoden sehr schnell aufgebläht werden. Für beide gibt es Vor- und Nachteile. Das Einfügen vieler Abhängigkeiten hat einen Overhead, ermöglicht jedoch das isolierte Testen und hält die Klassen einfach, sodass Sie schlankere Controller haben. Obwohl meine Logik in meinem Modell als Mitglieder der Klasse nicht wirklich existiert, ist sie immer noch eine Geschäftslogik. Ich neige dazu, keine Geschäftslogik im Controller zu definieren, da spöttische Dinge wie der Http-Kontext ein Albtraum sind und unnötig.

Mark Walsh
quelle
5
+1 stimme voll und ganz zu. Ich dachte, ich wäre der einzige, der die Verantwortung der Models auf ein Minimum beschränken möchte!
Lee
1
Sicher, er ist ein Kern meines Login-Controllers gist.github.com/markwalsh-liverpool/8fb361a9df0dcf034caf
Mark Walsh
1
Wenn Sie Ihre Logik also nicht in Ihre Modelle oder Controller einbauen - wo setzen Sie sie ein?
Niico
1
Wie übergeben Sie Argumente an den Konstruktor des Controllers? Wird die Initialisierung des Controllers nicht normalerweise hinter den Kulissen durchgeführt?
Jeff
1
Ich benutze Abhängigkeitsinjektion.
Mark Walsh
23

Die Geschäftslogik gehört zur Problemdomäne und alles, was zur Problemdomäne gehört, geht in MVC zum Modell .

Der Controller sollte dafür verantwortlich sein, die Daten vom Modell an die Ansicht und von der Ansicht zurück an das Modell zu übergeben. Die Steuerung ist daher die Brücke zwischen der Interaktion des Benutzers und der Modellierung und Speicherung des Problemstatus durch das Programm. Die Klempnerarbeiten sozusagen.

Der Schlüssel hier ist die Unterscheidung zwischen der Geschäftslogik und der Sanitärlogik. Meiner Meinung nach macht der automatisch generierte Account Controller hauptsächlich Klempnerarbeiten, nicht wirklich Geschäftslogik. Beachten Sie, dass die Installationslogik nicht unbedingt kurz ist, sodass Sie keine künstlichen Grenzwerte festlegen müssen (z. B. "X Anzahl der Anrufe höchstens in der Steuerung").

Theodoros Chatzigiannakis
quelle
Ich stimme dem zu. Ich denke jedoch, dass die Strukturierung der Klassen im Modell sehr verwirrend ist, insbesondere bei EF. IE: Verwenden Sie Teilklassen und bauen Sie die Logik in verschiedenen C # -Dateien auf? eine Datei für EF und eine Datei für die Logik?
S1r-Lanzelot
13

Als mein Team von Webforms (asp.net) zu mvc wechselte, hat es viel recherchiert und die folgende Struktur entwickelt. Meiner Meinung nach geht es nicht darum, wie groß oder klein die Anwendung ist. Es geht darum, den Code sauber und klar zu halten.

DALProject

AccountsDAL.cs --- > Calls SP or any ORM if ur using any

BLLProject

AccountsBLL.cs ---> Calls DAL

WebProject

Model
    AccountsModel --- > Contains properties And call BLL
Controllers
    IndexController ---> Calls Models and returns View
Views
    Index

Controller sollten für die Datenübertragung zwischen Modell und Ansicht verantwortlich sein. Ansonsten sollte es keinen unnötigen Code geben. Wenn Sie beispielsweise protokollieren, sollte dies auf Modellebene und nicht auf Controller-Ebene erfolgen.

Muneeb Zulfiqar
quelle
13

Es scheint einige Verwirrung um dieses Thema zu geben. Meistens scheinen die Leute dazu zu neigen, das MVC-Muster mit der N-Tier-Architektur als Entweder-Oder-Situation zu verwechseln. Die Realität ist, dass die beiden Ansätze zusammen verwendet werden können, aber einer nicht vom anderen abhängig ist und auch nicht erforderlich ist.

Die N-Tier-Architektur befasst sich mit der Aufteilung einer Anwendung in mehrere Ebenen. Ein einfaches Beispiel ist die Aufteilung der Anwendung in eine Präsentationsschicht, eine Geschäftslogikschicht und eine Datenzugriffsschicht.

MVC ist ein Entwurfsmuster, das sich mit der Präsentationsschicht einer Anwendung befasst. Es ist durchaus möglich, eine Anwendung nach einem MVC-Ansatz zu entwerfen, ohne Geschäftslogik und Datenzugriffslogik von der Präsentationsschicht zu trennen, und so ein einstufiges Design zu erhalten.

Wenn Sie einen MVC-Ansatz verfolgen, ohne die Anwendung auch in Ebenen zu unterteilen, erhalten Sie Modelle, Ansichten und Controller, deren Geschäftsregeln und Datenzugriffslogik mit dem Rest der Logik gemischt sind.

Per Definition sollte in einer N-Tier-Architektur die Präsentationsschicht nur mit der Geschäftslogikschicht kommunizieren können, sodass festgelegt werden sollte, dass jede der MVC-Komponenten nur mit der Geschäftslogikschicht kommunizieren kann.

Wenn Sie eine Anwendung erstellen, die keine Präsentation und damit keine Präsentationsebene umfasst, sollten Sie sich nicht mit dem MVC-Muster befassen müssen. Möglicherweise teilen Sie Ihre Anwendung jedoch weiterhin in mehrere Ebenen auf und folgen somit einem N-Tier-Design, obwohl keine Präsentationsebene erforderlich ist.

Baumfiddy
quelle
8

Im Allgemeinen sollte sich die Geschäftslogik in keinem der MVC-Player befinden. es sollte nur werden verbraucht , indem Sie Ihre Controller - Aktionen.

Wie viele bereits erwähnt haben, ist es am besten, eine Bibliothek zum Hosten von Geschäftslogik als eine Reihe von clientunabhängigen, wiederverwendbaren Komponenten zu erstellen.

Auf diese Weise erhöhen wir die Wiederverwendbarkeit, Kompatibilität, Skalierbarkeit und Testbarkeit mit unserer Software erheblich. Wir reduzieren auch unsere Abhängigkeit von bestimmten Framework-Funktionen, was die Migration auf neuere / andere Technologien erleichtert.

Die Zusammenfassung unserer Geschäftslogik in eine eigenständige Baugruppe (oder Baugruppen) hat uns im Laufe der Jahre gute Dienste geleistet. Unsere Geschäftslogik kann dann von praktisch jeder .NET-Technologie (ASP.NET MVC / API / Core, WPF, Win Forms, WCF, UWP, WF, Konsole usw.) verwendet werden.

Darüber hinaus möchten wir, dass unsere mittlere Ebene Geschäftsregeln und Validierungslogik verarbeitet, um unsere Abhängigkeiten von den .NET MVC Frameworks zu verringern. Beispielsweise vermeiden wir die Verwendung der Validierungshilfen für .NET MVCs und verlassen uns stattdessen auf unsere eigenen. Dies ist ein weiterer Faktor, mit dem wir unsere Geschäftslogik problemlos aus jeder .NET-Technologie nutzen können.

Durch die logische Gestaltung unserer mittleren Ebene auf diese Weise konnten wir diese physische Architektur problemlos erreichen:

Geben Sie hier die Bildbeschreibung ein

Es wurde mit Peasy.NET geschrieben und hat uns über die Jahre gute Dienste geleistet . So gut, dass wir uns für Open Source entschieden haben.

Wenn jemand neugierig ist, wie unsere mittlere Ebene aussieht, finden Sie hier ein Beispiel einer kundenunabhängigen Geschäftsschicht. Außerdem wird der Verbrauch durch mehrere .NET-Clients (ASP.NET MVC, Web Api und WPF) dargestellt.

Hoffe das hilft jemandem!

Ahanusa
quelle
Meistens muss die Logik nicht wiederverwendet werden. Wenn ich mich für die Verwendung von ASP.NET Core MVC für die Web-API entscheide, möchte ich diese Geschäftslogik niemals in WPF oder WinForms verwenden. Weil der Client sowieso mit dem Server kommuniziert. Es ist einfach schlecht, Geschäftslogik und insbesondere Datenbankzugriffslogik auf die Clientseite zu stellen.
Konrad
Je mehr Ebenen Sie hinzufügen, desto geringer ist die Wartbarkeit und Testbarkeit. Am Ende sind Integrationstests wichtiger.
Konrad
8

Die Geschäftslogik sollte nicht in Ihre Modellansichten oder Controller integriert werden. Es sollte eine separate Business Logic-Schicht vorhanden sein . Der einzige Zweck dieser Ebene besteht darin, Ihre Geschäftslogik zu handhaben. Dies entspricht eher SOLID .

Wenn Sie Ihre Geschäftslogik in MV oder C einfügen, erhalten Sie Code, der schwer zu testen / wiederzuverwenden ist.

Was ist mit der Logik in den Modellen?

Das ist eine schlechte Lösung.

Sie werden in einer Abhängigkeitshölle enden, in der Objekte auf Objekten beruhen. Geben Sie hier die Bildbeschreibung ein

Selbst wenn Sie eine absolut einfache Funktion haben, müssen Sie dennoch alle Abhängigkeiten erfüllen, um sie aufzurufen.

Außerdem werden unnötige und nicht verwendete Daten ohne Grund weitergegeben. Dies kann sich auch auf die Leistung auswirken, je nachdem, wie schlecht es wird.

Ich sollte auch erwähnen, dass Unit-Tests zu einem Problem werden, da Sie mehrere Objekte verspotten müssen, um eine einfache Funktion zu testen.

Anwendbare Grundsätze des sauberen Codes

  1. Klassen / Funktionen benötigen nur das, was sie benötigen, um die Arbeit zu erledigen.
  2. Funktionen sollten nach Möglichkeit 3 ​​Parameter oder weniger annehmen
  3. Benennen Sie Klassen / Funktionen / Variablen intelligent (folgen Sie den Standards von Microsoft)
  4. Koppeln Sie die Geschäftslogik nicht mit der Modellansicht oder dem Controller

Controller

In Ihrem Controller sollten Sie in der Lage sein, die Abhängigkeitsinjektion zum Injizieren der Geschäftslogikschicht zu verwenden . Stellen Sie sicher, dass Ihr Controller nur zum Weiterleiten von Informationen an die Geschäftslogikschicht verwendet wird. Der Controller sollte KEINE Geschäftslogik direkt enthalten. Jede Validierung muss IValidatableim Modell durchgeführt werden. Jede Geschäftslogik muss auf eine separate Ebene geleitet werden.

Kolob Canyon
quelle
Hier, wo ich arbeite, haben wir eine Geschäftsschicht und ich wollte nur, dass wir sie nicht hatten. Geschäftsschichten sind reine Unordnung, Logik soll im Modell sein.
Mateus Felipe
@MateusFelipe Wo setzen Sie also Logik ein, die mehrere Modelle erfordert (zum Beispiel: Zahlung und Produkt)? Erstellen Sie ein neues Modell mit Paymentund Productals Instanzvariable? Wie nennt man das Objekt? Wenn ein Modell nicht in einer Ansicht verwendet wird, ist es kein Modell mehr. Es ist Teil einer separaten Schicht. Im Idealfall sollte diese Klasse, die Sie machen, nur das nehmen, was sie von Zahlung und Produkt benötigt, um ihre Arbeit zu erledigen. Wenn es nur das productNameund das benötigt price, sollte es nur diese beiden Parameter verwenden, nicht das gesamte Objekt.
Kolob Canyon
4

Die allgemeine Antwort, die ich habe, ist, dass Geschäftslogik normalerweise in zwei Kategorien passt:

Objektorientierte Geschäftslogik: Wird als Objekte (im Modell) modelliert und normalerweise als Repositorys eingefügt.

Prozedurale Geschäftslogik: Geht in einen Dienst mit einer Schnittstelle, die in eine Steuerung eingefügt werden kann.

Controller-Logik: Logik, die steuert, wie Befehle empfangen und an die Modelle / Dienste übergeben werden und wie diese Ergebnisse an die Ansicht übergeben werden.

Controller sollten keine Geschäftslogik haben. Dies ist ein sehr spezifischer Teil eines Entwurfsmusters zur Steuerung, wie eine Benutzeroberfläche Eingaben an die Modelle weiterleitet, die mit Geschäftslogik umgehen (oder Services, wenn Ihre Probleme eher prozeduraler Natur sind).

WhiteleyJ
quelle
2

Ich mag es auch, meine Modelle sauber zu halten (Ref: @Mark Walsh). Das Problem, dass in Controllern eingebettete Logik nicht wiederverwendet werden kann, kann leicht durch Abhängigkeitsinjektion überwunden werden. Wenn Sie der Meinung sind, dass zu viel davon vorhanden ist, können Sie Ihre Geschäfts- / Domänenlogik über Schnittstellen verfügbar machen und das Fassadenmuster in den Controllern verwenden. Auf diese Weise erhalten Sie die Funktionalität, die Sie benötigen, aber halten Sie sowohl die Controller als auch das Modell schön sauber.

Bob H.
quelle
1

Ich würde es auch vorziehen, Modelle sauber zu halten. Die MVC-Controller sollten nur zum Telefonieren verwendet und sauber gehalten werden. Je nach Wiederverwendbarkeit, Sensibilität und Relevanz kann die Geschäftslogik geschrieben werden

1.WebApi-Controller: Der Vorteil der Verwendung eines Webapi-Controllers besteht darin, dass Sie diese später als Dienste für andere Geräte verfügbar machen können, sodass Ihr Code wiederverwendbar ist.

2. BAL / Common Commonent: Es gibt einige Logiken, die eine bestimmte Verwendung haben und nicht als API verfügbar gemacht werden können. Sie können in dieser Klasse gepusht werden.

3. Repository: Alle datenbankbezogenen Abfragen werden in einem Repository hinzugefügt. Es kann ein generisches Repository geben, das alle Funktionen (CRUD-Operationen) oder bestimmte Repositorys für jede Tabelle implementiert. Abhängig von den auszuführenden Operationen.

Nikitesh
quelle
1

Wie ahanusa schrieb, sollten Sie Ihre Geschäftslogik in eine separate DLL oder ein separates Verzeichnis stellen.
Ich verwende häufig ein Verzeichnis mit dem Namen "Logik" auf derselben Ebene von Modellen und Controllern, in das ich Klassen einfüge, die Geschäftslogiken ausführen.
Auf diese Weise lasse ich sowohl Modelle als auch Steuerungen reinigen.

Ryozzo
quelle
0

Ich weiß, dass es sich um eine Frage zu MVC handelt, aber ich denke, dass das Beispiel, das ich gebe (Web-API), nützlich sein wird.

Ich entwickle meine erste Web-API und verwende die Geschäftslogik aus anderen Anwendungen wieder. Um genau zu sein, es kommt von einer externen DLL, daher wird meine API nur verwendet, um mit einer SAP-Lösung zu "sprechen", Anforderungen von der Bestellung zu empfangen und Antworten zurückzusenden.

Wie kann ich meine (bereits implementierte) Logik in meinen Controller einfügen? Ich brauche es nicht Mein Controller empfängt, validiert nur Anfragen und verfasst Antworten, um Daten zurückzusenden.

Ich arbeite mit ViewModel-Klassen und alles, was sie haben müssen, ist eine Zuordnungsfunktion, um Informationen aus TransferObjects (die von der externen DLL stammen) zu lesen und in ein ViewModel zu übersetzen.

Ich bin mit meiner Anwendung (in diesem Fall der Web-API), die die Geschäftslogik enthält, nicht zufrieden. Ich denke, dass die Wiederverwendbarkeit auf diese Weise verloren geht.

Ich behandle meine Geschäftslogik als eine Abhängigkeit, die ich in den Controller einspeise.

Ich habe das Legacy viel überarbeitet, um eine Unit Testable-Lösung bereitzustellen. Ich musste viele Schnittstellen erstellen und einige Entwurfsmuster in das Legacy implementieren, um diese Lösung bereitzustellen.

Aus meiner Sicht muss die Geschäftsschicht von der Anwendung getrennt sein, vorzugsweise in einer anderen Klassenbibliothek. So haben Sie ein echtes Trennungskonzept in Ihrer Anwendung implementiert.

Wenn Ihr CORE (Geschäft) Ihre Anwendung (API / WebSite) ist , werden die Geschäftsregeln natürlich in Ihre MVC-Klassen implementiert. Wenn Sie jedoch in Zukunft eine neue App entwickeln möchten und einige Geschäftsregeln gleich sind, werden Sie wahrscheinlich viele Probleme haben, nur um die gleiche Logik beizubehalten, die in beiden Anwendungen implementiert ist.

Otta Augusto
quelle