MVC DDD: Ist es in Ordnung, Repositories zusammen mit Diensten im Controller zu verwenden?

8

Die meiste Zeit im Service-Code hätte ich so etwas:

%Vor%

also ist es irgendwie überflüssig

Ich habe angefangen, die Repositories direkt im Controller zu verwenden

ist das ok? Gibt es eine Architektur, die so funktioniert?

    
Omu 26.08.2010, 12:23
quelle

5 Antworten

5
  

Sie verlieren die Fähigkeit, Geschäftslogik dazwischen zu haben.

Ich stimme dem nicht zu.

Wenn Geschäftslogik ist, wo es sein sollte - im Domänenmodell, dann Aufruf Repo in Controller (oder besser - Modellbinder dafür verwenden), aggregierte Root-und Aufrufmethode zu erhalten scheint mir völlig in Ordnung.

Anwendungsdienste sollten verwendet werden, wenn zu viele technische Details involviert sind, was die Controller in Unordnung bringen würde.

  

Ich habe mehrere Leute erwähnt, die kürzlich Modellbinder benutzt haben, um sie in ein Repo einzuladen. Woher kommt diese verrückte Idee?

Ich glaube, wir sprechen hier über zwei verschiedene Dinge. Ich vermute, dass Ihr "Modellbinder" auch bedeutet, dass Sie das Modell gleichzeitig als Ansichtsmodell verwenden und die Werte von der Benutzeroberfläche direkt an sie binden (was an sich keine schlechte Sache ist und in einigen Fällen würde ich diesen Weg gehen).

Mein 'Modellbinder' ist eine Klasse, die ' IModelBinder ', die Repository in Konstruktor (die injiziert und daher - erweitert werden kann, wenn wir Caching mit einigen grundlegenden Zusammensetzung benötigen) und verwendet, bevor Aktion aufgerufen wird, aggregierte Stamm abrufen und ersetzen int id oder Guid id oder string slug oder whatever Aktionsargument mit realem Domänenobjekt. Kombiniert man dies mit dem Input-View-Model-Argument, können wir weniger Code schreiben. Etwas wie das:

%Vor%

In meinem tatsächlichen Code ist es ein wenig komplexer, weil es ModelState-Validierung und einige Ausnahmebehandlungen enthält, die aus dem Inneren des Domänenmodells geworfen werden können (extrahiert in die Controller-Erweiterungsmethode zur Wiederverwendung). Aber nicht viel mehr. Bisher - längste Controller-Aktion ist ~ 10 Zeilen lang.

Sie können die Arbeitsimplementierung sehen (ziemlich komplex und (für mich) unnötig komplex) hier .

  

Machen Sie gerade CRUD-Apps mit Linq To Sql oder versuchen Sie etwas mit echter Domänenlogik?

Wie Sie (hoffentlich) sehen können, zwingt uns diese Art des Ansatzes fast dazu, sich auf die aufgabenbasierte App zu konzentrieren CRUD basiert.

  

Indem Sie den gesamten Datenzugriff in Ihrer Service-Schicht vornehmen und IOC verwenden, können Sie viele Vorteile von AOP wie unsichtbares Caching, Transaktionsmanagement und einfache Zusammensetzung von Komponenten, die Sie sich mit Modellbindern nicht vorstellen können, erhalten.

>

... und mit einer neuen Abstraktionsschicht, die uns einlädt, Infrastruktur mit Domänenlogik zu vermischen und die Isolation des Domänenmodells zu verlieren.

  

Bitte erleuchte mich.

Ich bin mir nicht sicher, ob ich es getan habe. Ich glaube nicht, dass ich selbst erleuchtet bin. :)

Hier ist meine aktuelle Modellbinder-Basisklasse. Hier ist eine der Controller-Aktionen meines aktuellen Projekts. Und hier ist "Mangel" an Geschäftslogik.

    
Arnis Lapsa 27.08.2010, 11:55
quelle
2

Wenn Sie Repositories in Ihren Controllern verwenden, gehen Sie direkt von der Datenschicht zur Präsentationsschicht. Sie verlieren die Fähigkeit, Geschäftslogik dazwischen zu haben.

Wenn Sie jetzt sagen, dass Sie nur Dienste verwenden werden, wenn Sie Geschäftslogik benötigen, und überall Repositorys verwenden, wird Ihr Code zum Albtraum. Die Präsentationsschicht ruft jetzt sowohl die Business- als auch die Datenschicht auf, und Sie haben keine nette Trennung von Bedenken.

Ich würde immer diese Route gehen: Repositories -> Services -> UI . Sobald Sie nicht glauben, dass Sie eine Business-Schicht benötigen, ändern sich die Anforderungen und Sie müssen ALLES neu schreiben.

    
Martin 26.08.2010 12:29
quelle
1

Hier ist die Sache.

"Geschäftslogik" sollte sich in Ihren Entitäten und Wertobjekten befinden.

Repositories behandeln nur AggregateRoots. Wenn Sie also Ihre Repositories direkt in Ihren Controllern verwenden, fühlt sich das so an, als würden Sie diese Aktion als Ihren "Service" betrachten. Da Ihr AggregateRoot möglicherweise nur auf andere ARs über seine ID verweist, müssen Sie möglicherweise mehr als einen Repo aufrufen. Es wird sehr schnell sehr böse.

Wenn Sie Dienste benötigen, stellen Sie sicher, dass Sie POCOs und nicht das tatsächliche AggregateRoot und seine Mitglieder anzeigen.

Ihr Repo sollte keine anderen Vorgänge ausführen als das Erstellen, Abrufen, Aktualisieren und Löschen von Daten. Möglicherweise haben Sie einige benutzerdefinierte abrufen basierend auf bestimmten Bedingungen, aber das ist es. Also, eine Methode in Ihrem Repo, die eine in Ihrem Service ... Code Geruch genau dort passt.

Ihr Service ist API orientiert. Denken Sie darüber nach ... Wenn Sie diesen Dienst in einer .dll-Datei für mich verwenden würden, wie würden Sie Ihre Methoden so erstellen, dass ich leicht weiß, was Ihr Dienst leisten kann? Service.Update (Objekt) macht nicht viel Sinn.

Und ich habe noch nicht einmal über CQRS gesprochen ... wo die Dinge noch interessanter werden.

Ihre Web-API ist nur ein CLIENT Ihres Service. Ihr Service kann von einem anderen Dienst genutzt werden, richtig? Also, darüber nachdenken. Wahrscheinlich benötigen Sie einen Dienst, um Operationen in AggregateRoots zu kapseln, indem Sie sie normalerweise erstellen oder aus einem Repo abrufen, etwas dagegen tun und dann ein Ergebnis zurückgeben. Normalerweise.

Macht Sinn?

    
Pepito Fernandez 19.12.2016 16:58
quelle
0

Meine eigenen rohen Praktiken für DDD / MVC:

  • -Controller sind anwendungsspezifisch, daher sollten sie nur anwendungsspezifische Methoden enthalten und Service-Methoden aufrufen.
  • alle öffentlichen Service-Methoden sind normalerweise atomare Transaktionen oder Abfragen
  • nur Dienste instanziieren & amp; rufen Sie Repositories
  • auf
  • Meine Domain definiert eine IContextFactory und einen IContext (massive undichte Abstraktion als IContext-Member sind IDBSet)
  • Jede Anwendung hat eine Art Kompositionswurzel , die hauptsächlich eine Kontext-Factory instanziiert an die Services übergeben (Sie könnten den DI-Container verwenden, aber keine große Sache)

Dies zwingt mich, meinen Geschäftscode und den Datenzugriff von meinen Controllern fernzuhalten. Ich finde es eine gute Disziplin, gegeben, wie locker ich bin, wenn ich dem oben genannten nicht folge!

    
Chalky 18.12.2016 09:17
quelle
-2

Auch bei "Rich-Domain-Modell" benötigen Sie weiterhin einen Domain-Service für den Umgang mit Geschäftslogik, der mehrere Entitäten umfasst. Ich habe CRUD auch nie ohne Geschäftslogik gesehen, aber in einfachem Beispielcode. Ich würde immer gerne Martins Weg gehen, um meinen Code einfach zu halten.

    
Tien Do 09.09.2010 04:31
quelle