Muster zum Teilen von Objekten zwischen API und Anwendung

9

Ich habe ernsthafte Zweifel am Design meiner Webanwendung.

Ich wollte die Geschäftslogik von der Schnittstelle trennen, also habe ich eine Web-API erstellt, die alle Anforderungen an die Datenbank verarbeitet.

Es ist eine ASP.NET-Web-API mit Entity-Framework und einer Arbeitseinheit sowie einem generischen Repository-Muster. Bisher ist alles gut.

PROBLEM

Wenn ich Hilfe benötige, kann ich keine effiziente Methode zum Freigeben von Objekten zwischen der API und der Anwendung finden.

Ich möchte das Entitätsobjekt nicht direkt serialisieren. Ich dachte, es wäre eine schlechte Praxis, denn wenn sich das Entitätsmodell ändert, könnte ich ohne Grund große Objekte serialisieren.

Wie es jetzt implementiert ist

Da meine Schnittstelle eine ASP.NET-Webanwendung in C # und meine API in C # ist, habe ich eine gemeinsame Bibliothek mit der Definition aller meiner Klassen erstellt, die ich zwischen ihnen teilen möchte.

Ich weiß, dass die Lösung nicht funktioniert, wenn ich eine Android-App entwickle. Ich muss meine Klassen erneut in Java erstellen, aber das ist nicht mein größtes Problem.

Das Problem ist, dass ich das Gefühl habe, meine Objekte immer zu konvertieren.

BEISPIEL

Hier ist ein Beispiel für meinen Arbeitsablauf:

Ich beginne mit einem Modell mit allen Objekten und den Datenanmerkungen für mein Formular, dann würde der Benutzer dieses Modell an einen Controller senden.

Im Controller muss ich dieses Modell in eine Klasse in meiner gemeinsamen Bibliothek konvertieren und dieses Objekt dann an meine API senden.

Dann fängt ein Controller in meiner API den Aufruf ab und konvertiert dieses Objekt in ein Entitätsobjekt, um die Datenbank zu aktualisieren.

Ich habe also 3 Klassen

  1. Das Modell für die Ansicht mit allen Datenanmerkungen für die Validierung (Client)
  2. Die allgemeinen Bibliotheksklassen zum Freigeben der Objekte (DLL)
  3. Die Entitätsklassen (API)

Ich habe das Gefühl, dass ich etwas wirklich falsch mache. Gibt es etwas eleganteres? Ich möchte sicherstellen, dass ich eine gute Lösung für dieses Problem habe, bevor das Projekt zu groß wird.

Marc
quelle
Wenn meine Frage nicht klar ist, zögern Sie nicht, Fragen zu stellen.
Marc
Für mich ist nicht klar, welche Architektur Sie implementiert haben (vielleicht ist es der .net-Wortlaut, der mich verwirrt) - ist es eine dreistufige Architektur: Client, Server, Datenbank?
Andy
Ja, ich habe eine Webanwendung, die eine Web-API verwendet. Die API ist die mit der Geschäftslogik mit der Datenbank.
Marc

Antworten:

12

Ich weiß, es scheint, als würden Sie ständig Objekte zwischen Ihren Datenbankobjekten, Ihren Datenübertragungsobjekten, Ihren Clientobjekten mit Validierungslogik usw. hin und her konvertieren, aber ich würde sagen, nein, Sie machen nichts falsch .

Jedes dieser Objekte kann dieselbe Informationseinheit darstellen, hat jedoch sehr unterschiedliche Verantwortlichkeiten. Das Datenbankobjekt ist Ihre Kommunikationsschnittstelle mit der Datenbank und sollte in der Datenbankebene aufbewahrt werden, da es möglicherweise unterschiedliche Anmerkungen zu Datenbankmetadaten und / oder unnötige Details zur Datenbankimplementierung enthält.

Ihr Datenübertragungsobjekt ist die Kommunikationsschnittstelle mit Ihren API-Verbrauchern. Diese sollten so sauber wie möglich sein, um einen einfachen Verbrauch aus verschiedenen Sprachen / Plattformen zu ermöglichen. Dies kann bestimmte Einschränkungen für das Aussehen und Verhalten dieser APIs mit sich bringen, je nachdem, welche API-Konsumenten Sie unterstützen möchten.

Ihre Client-Objekte mit Validierungslogik sind nicht Teil Ihres API-Projekts, sondern Teil Ihres Consumer-Projekts. Diese können in diesem Fall nicht mit den Datenübertragungsobjekten identisch sein, da Sie ihnen zusätzliche clientspezifische Logik (in diesem Fall Validierungsattribute) hinzufügen, von der der Server nichts weiß (und von der er nichts wissen sollte!). Sie sollten dies nicht tun Zählen Sie diese Objekte als Teil Ihrer API, da dies wirklich nicht der Fall ist. Sie sind sehr konsumentenspezifisch und einige Anwendungen, die Ihre API verwenden, müssen diese Objekte möglicherweise nicht einmal erstellen und können genauso gut nur mit Ihren Datenübertragungsobjekten überleben. Wenn Sie beispielsweise keine Validierung benötigen, benötigen Sie keine zusätzliche Objektebene, die vollständig mit Ihren Datenübertragungsobjekten identisch ist.

Mir scheint, dass jeder der drei Objekttypen sehr gut einer einzigen Verantwortung zugeordnet ist, die aus sauberer Codierung und bewährten Verfahren besteht. Leider bedeutet sauberer Code und bewährte Methoden manchmal, dass Sie viel zusätzlichen Code schreiben und "nur weil" durch zusätzliche Rahmen springen. Und während des Codierens kann es schwierig sein, den Wert zu schätzen, den dies für Sie bietet. Sobald Sie jedoch Ihre Anwendung freigeben und sie unterstützen oder neue Funktionen für die nächste Version hinzufügen, werden Sie wahrscheinlich zu schätzen wissen, dass Sie sich die Zeit dafür genommen haben Trennen Sie diese Bedenken in erster Linie richtig. (Ganz zu schweigen davon, dass Sie '

Ich hasse es auch, Konvertierungscode zwischen verschiedenen Objekttypen wie diesem zu schreiben, aber meine Lösung ist normalerweise eine der folgenden:

  • Verwenden Sie eine Bibliothek, die den größten Teil der Objektkonvertierung für Sie erledigt. Wenn Sie beispielsweise C # verwenden, können Sie die fantastische AutoMapper-Bibliothek ( http://automapper.org/ ) verwenden. Ich glaube, dass es ein paar andere Bibliotheken wie diese gibt, aber AutoMapper ist die leistungsstärkste, die ich bisher gesehen habe.
  • Wenn Sie keine Bibliothek finden, die Ihnen bei Ihren Objektkonvertierungen hilft, schreiben Sie eine Reihe von Dienstprogrammmethoden für die Konvertierung zwischen ihnen. Das mag scheiße sein, aber es lohnt sich auf lange Sicht. Schreiben Sie die Konvertierungsmethode, wenn Sie zum ersten Mal etwas konvertieren müssen - warten Sie nicht.
wasatz
quelle
Vielen Dank für Ihre Erklärungen, aber ich finde immer noch schwer etwas zu verstehen. Ich verstehe nicht, warum die Ebene für die Datenübertragung keine Validierung hat. Was ist, wenn ich einige Validierungen für meine nächste mobile App vergesse? Zumindest würde es nicht validieren, wenn ich die API aufrufe, anstatt eine Ausnahme in meinem Datenbankmodell zu machen. Ich bin mir nicht sicher, ob ich das verstehe.
Marc
1
Ich sage nicht, dass Sie nicht auf API-Ebene validieren sollten. Um ehrlich zu sein, ist dies der wichtigste Ort, an dem validiert werden muss. Die Validierung in Ihrer App ist nur eine "nette Funktion", mit der Ihre Benutzer keine Fehler machen können. Die Validierung Ihrer Datenübertragungsobjekte dient dazu, böswillige und fehlerhafte Daten fernzuhalten. Da diese verschiedenen Fällen jedoch verwendet werden, müssen Sie möglicherweise verschiedene Validierungsrahmen verwenden (Sie werden verschiedene Validierungs Frameworks verwenden , wenn Ihre Anwendung und Ihre api nicht in der gleichen Sprache geschrieben ist) , und Sie können auf jeder Ebene (Forts etwas andere Dinge validieren . im nächsten Kommentar)
Wasatz
1
Sie sollten also Ihre Datenübertragungsobjekte validieren. Sie sollten jedoch auch sicherstellen, dass die Art und Weise, wie Sie sie validieren, nicht versehentlich Abhängigkeiten von einem anderen Framework verursacht . Und natürlich können Sie, wie ich bereits sagte, nicht sicher sein, ob Ihre Datenübertragungsobjekte überhaupt validiert wurden oder ob sie von demselben Framework validiert wurden - Sie müssen also "zweimal validieren".
Wasatz
2
Hauptsächlich sollten Sie versuchen, Ihre Anwendung und Ihre API als zwei völlig unterschiedliche und separate Anwendungen anzuzeigen. Möglicherweise entwickeln Sie sie gleichzeitig und sie befinden sich möglicherweise in derselben Visual Studio-Lösung / demselben Eclipse-Projekt. Aber es sind wirklich zwei völlig getrennte Programme. Wenn Sie in Ihrer Anwendung arbeiten, versuchen Sie zu "vergessen", dass Sie derjenige sind, der die API erstellt hat, und verwenden Sie sie wie bei einer normalen API eines Drittanbieters. Auf diese Weise haben Sie eine bessere Chance zu sehen, wie sich andere fühlen, wenn Sie Ihre API verwenden, und die schlimmsten Teile frühzeitig zu korrigieren.
Wasatz
1
Das Gleiche gilt natürlich auch für die Arbeit an Ihrem API-Projekt. Stellen Sie sich vor, Sie schreiben einen Dienst, den viele Entwickler von Drittanbietern verwenden werden. Versuchen Sie, nicht zu viel über Ihre aktuelle Anwendung nachzudenken, sondern sich mehr mit "Welche Dienste biete ich an" zu beschäftigen und davon auszugehen, dass alle, die Ihre API verwenden (einschließlich Sie selbst), böse Menschen sind, die versuchen, Ihren Server und zu töten Lassen Sie Ihre gesamte Datenbank löschen.
Wasatz