Ich habe einen mehrstufigen Registrierungsprozess , der von einem einzelnen Objekt in der Domänenschicht unterstützt wird und dessen Validierungsregeln für Eigenschaften definiert sind.
Wie soll ich das Domänenobjekt überprüfen, wenn die Domäne auf mehrere Ansichten aufgeteilt ist und ich das Objekt beim Posten teilweise in der ersten Ansicht speichern muss?
Ich habe über die Verwendung von Sitzungen nachgedacht, aber das ist nicht möglich, da der Prozess langwierig und die Datenmenge hoch ist. Daher möchte ich keine Sitzung verwenden.
Ich habe darüber nachgedacht, alle Daten in einer relationalen In-Memory-Datenbank (mit demselben Schema wie die Hauptdatenbank) zu speichern und diese Daten dann in die Hauptdatenbank zu leeren, aber es sind Probleme aufgetreten, weil ich zwischen Diensten (in den Ansichten angefordert) routen sollte, die mit der arbeiten Hauptdatenbank und In-Memory-Datenbank.
Ich suche eine elegante und saubere Lösung (genauer gesagt eine bewährte Methode).
UPDATE UND Klarstellung:
@Darin Vielen Dank für Ihre nachdenkliche Antwort. Genau das habe ich bis jetzt getan. Übrigens habe ich eine Anfrage, die viele Anhänge enthält. Ich entwerfe Step2View
beispielsweise, welcher Benutzer Dokumente asynchron hochladen kann. Diese Anhänge sollten jedoch in einer Tabelle mit referenzieller Beziehung zu einer anderen Tabelle gespeichert werden, die zuvor in gespeichert worden sein sollte Step1View
.
Daher sollte ich das Domänenobjekt in Step1
(teilweise) speichern , aber ich kann nicht, da das gesicherte Core-Domänenobjekt, das teilweise dem ViewModel eines Step1 zugeordnet ist, nicht ohne Requisiten gespeichert werden kann, die von konvertiert stammen Step2ViewModel
.
quelle
Antworten:
Zunächst sollten Sie in Ihren Ansichten keine Domänenobjekte verwenden. Sie sollten Ansichtsmodelle verwenden. Jedes Ansichtsmodell enthält nur die Eigenschaften, die für die angegebene Ansicht erforderlich sind, sowie die für diese bestimmte Ansicht spezifischen Validierungsattribute. Wenn Sie also einen Assistenten für drei Schritte haben, bedeutet dies, dass Sie drei Ansichtsmodelle haben, eines für jeden Schritt:
und so weiter. Alle diese Ansichtsmodelle können von einem Hauptansichtsmodell des Assistenten unterstützt werden:
Dann könnten Sie Controller-Aktionen ausführen, die jeden Schritt des Assistentenprozesses rendern und den Hauptschritt
WizardViewModel
an die Ansicht übergeben. Wenn Sie sich im ersten Schritt der Controller-Aktion befinden, können Sie dieStep1
Eigenschaft initialisieren . Anschließend generieren Sie in der Ansicht das Formular, mit dem der Benutzer die Eigenschaften von Schritt 1 ausfüllen kann. Wenn das Formular gesendet wird, wendet die Controller-Aktion nur die Validierungsregeln für Schritt 1 an:In der Ansicht von Schritt 2 können Sie jetzt den Html.Serialize-Helfer aus MVC-Futures verwenden, um Schritt 1 in ein verstecktes Feld innerhalb des Formulars zu serialisieren (eine Art ViewState, wenn Sie dies wünschen):
und innerhalb der POST-Aktion von Schritt 2:
Und so weiter, bis Sie zum letzten Schritt gelangen, in dem Sie
WizardViewModel
alle Daten ausgefüllt haben . Anschließend ordnen Sie das Ansichtsmodell Ihrem Domänenmodell zu und übergeben es zur Verarbeitung an die Serviceschicht. Die Serviceschicht führt möglicherweise alle Validierungsregeln selbst aus und so weiter ...Es gibt auch eine andere Alternative: Verwenden Sie Javascript und setzen Sie alle auf dieselbe Seite. Es gibt viele JQuery-Plugins , die Assistentenfunktionen bieten ( Stepy ist eine nette). Im Grunde geht es darum, Divs auf dem Client anzuzeigen und auszublenden. In diesem Fall müssen Sie sich keine Sorgen mehr über den anhaltenden Zustand zwischen den Schritten machen.
Unabhängig davon, für welche Lösung Sie sich entscheiden, verwenden Sie immer Ansichtsmodelle und führen Sie die Validierung für diese Ansichtsmodelle durch. Solange Sie die Validierungsattribute für Datenanmerkungen in Ihre Domänenmodelle einfügen, werden Sie große Probleme haben, da Domänenmodelle nicht an Ansichten angepasst sind.
AKTUALISIEREN:
OK, aufgrund der zahlreichen Kommentare komme ich zu dem Schluss, dass meine Antwort nicht klar war. Und ich muss zustimmen. Lassen Sie mich versuchen, mein Beispiel weiter auszuarbeiten.
Wir könnten eine Schnittstelle definieren, die alle Schrittansichtsmodelle implementieren sollten (es ist nur eine Markierungsschnittstelle):
Dann würden wir 3 Schritte für den Assistenten definieren, wobei jeder Schritt natürlich nur die Eigenschaften enthält, die er benötigt, sowie die relevanten Validierungsattribute:
Als nächstes definieren wir das Hauptansichtsmodell des Assistenten, das aus einer Liste von Schritten und einem aktuellen Schrittindex besteht:
Dann gehen wir weiter zum Controller:
Einige Anmerkungen zu diesem Controller:
[Deserialize]
Attribute aus der Microsoft Futures-Bibliothek. Stellen Sie daher sicher, dass SieMvcContrib
NuGet installiert haben . Aus diesem Grund sollten Ansichtsmodelle mit dem[Serializable]
Attribut versehen werdenIStepViewModel
Schnittstelle. Damit dies sinnvoll ist, benötigen wir einen benutzerdefinierten Modellordner.Hier ist der zugehörige Modellordner:
Dieser Ordner verwendet ein spezielles verstecktes Feld namens StepType, das den konkreten Typ jedes Schritts enthält und das wir bei jeder Anfrage senden.
Dieser Modellordner wird registriert in
Application_Start
:Das letzte fehlende Teil des Puzzles sind die Ansichten. Hier ist die Hauptansicht
~/Views/Wizard/Index.cshtml
:Und das ist alles, was Sie brauchen, damit dies funktioniert. Wenn Sie möchten, können Sie natürlich das Erscheinungsbild einiger oder aller Schritte des Assistenten personalisieren, indem Sie eine benutzerdefinierte Editorvorlage definieren. Machen wir es zum Beispiel für Schritt 2. Also definieren wir einen
~/Views/Wizard/EditorTemplates/Step2ViewModel.cshtml
Teil:So sieht die Struktur aus:
Natürlich gibt es Raum für Verbesserungen. Die Aktion Index POST sieht aus wie s..t. Es ist zu viel Code darin. Eine weitere Vereinfachung würde darin bestehen, alle Infrastrukturelemente wie Index, aktuelle Indexverwaltung, Kopieren des aktuellen Schritts in den Assistenten usw. in einen anderen Modellordner zu verschieben. Damit wir endlich am Ende haben:
So sollten POST-Aktionen aussehen. Ich verlasse diese Verbesserung für das nächste Mal :-)
quelle
Als Ergänzung zu Amit Baggas Antwort finden Sie unten, was ich getan habe. Auch wenn ich weniger elegant bin, finde ich diesen Weg einfacher als Darins Antwort.
Controller:
Modelle:
quelle
Ich würde Ihnen empfehlen, den Status des vollständigen Prozesses auf dem Client mithilfe von Jquery beizubehalten.
Auf diese Weise können Sie Ihr Domänenobjekt einfach direkt aus den Formularpostdaten erstellen. Falls die Daten fehlerhaft sind, geben Sie einen gültigen JSON zurück, der alle Fehlermeldungen enthält, und zeigen Sie sie in einem div an.
Bitte teilen Sie die Schritte
quelle
Assistenten sind nur einfache Schritte zur Verarbeitung eines einfachen Modells. Es gibt keinen Grund, mehrere Modelle für einen Assistenten zu erstellen. Sie müssen lediglich ein einzelnes Modell erstellen und es zwischen Aktionen in einem einzelnen Controller übergeben.
Die obige Studentin ist einfach dumm, also ersetzen Sie Ihre Felder dort. Als nächstes beginnen wir mit einer einfachen Aktion, die unseren Assistenten initiiert.
Dies ruft die Ansicht "WizardStep1.cshtml" auf (wenn Sie also Rasiermesser verwenden). Sie können den Assistenten zum Erstellen von Vorlagen verwenden, wenn Sie möchten. Wir leiten den Beitrag lediglich zu einer anderen Aktion um.
Die Sache ist, dass wir dies in einer anderen Aktion veröffentlichen werden; die WizardStep2-Aktion
In dieser Aktion prüfen wir, ob unser Modell gültig ist, und senden es in diesem Fall an unsere Ansicht WizardStep2.cshtml. Andernfalls senden wir es mit den Validierungsfehlern an Schritt 1 zurück. In jedem Schritt senden wir es an den nächsten Schritt, validieren diesen Schritt und fahren fort. Einige versierte Entwickler könnten nun sagen, dass wir nicht zwischen solchen Schritten wechseln können, wenn wir [Erforderliche] Attribute oder andere Datenanmerkungen zwischen den Schritten verwenden. Und Sie hätten Recht, also entfernen Sie die Fehler bei Elementen, die noch überprüft werden müssen. Wie unten.
Schließlich würden wir das Modell einmal im Datenspeicher speichern. Dies verhindert auch, dass ein Benutzer, der einen Assistenten startet, ihn jedoch nicht beendet, unvollständige Daten nicht in der Datenbank speichert.
Ich hoffe, Sie finden diese Methode zum Implementieren eines Assistenten viel einfacher zu verwenden und zu warten als jede der zuvor genannten Methoden.
Danke fürs Lesen.
quelle
Ich wollte meine eigene Art des Umgangs mit diesen Anforderungen teilen. Ich wollte SessionState überhaupt nicht verwenden, noch wollte ich, dass es clientseitig behandelt wird, und die Serialisierungsmethode erfordert MVC-Futures, die ich nicht in mein Projekt aufnehmen wollte.
Stattdessen habe ich einen HTML-Helper erstellt, der alle Eigenschaften des Modells durchläuft und für jedes ein benutzerdefiniertes verstecktes Element generiert. Wenn es sich um eine komplexe Eigenschaft handelt, wird sie rekursiv ausgeführt.
In Ihrem Formular werden sie zusammen mit den neuen Modelldaten bei jedem "Assistenten" -Schritt an die Steuerung gesendet.
Ich habe das für MVC 5 geschrieben.
Jetzt können Sie für alle Schritte Ihres "Assistenten" dasselbe Basismodell verwenden und die Modelleigenschaften "Schritt 1,2,3" mithilfe eines Lambda-Ausdrucks an den @ Html.HiddenClassFor-Helfer übergeben.
Sie können sogar bei jedem Schritt einen Zurück-Button haben, wenn Sie möchten. Haben Sie einfach eine Zurück-Schaltfläche in Ihrem Formular, die es mithilfe des formaction-Attributs an eine StepNBack-Aktion auf dem Controller sendet. Nicht im folgenden Beispiel enthalten, sondern nur eine Idee für Sie.
Sowieso ist hier ein grundlegendes Beispiel:
Hier ist dein MODELL
Hier ist dein CONTROLLER
Hier sind deine ANSICHTEN
Schritt 1
Schritt 2
Schritt 3
quelle
Hinzufügen weiterer Informationen aus @ Darins Antwort.
Was ist, wenn Sie für jeden Schritt einen eigenen Entwurfsstil haben und jeden in einer separaten Teilansicht beibehalten möchten, oder wenn Sie für jeden Schritt mehrere Eigenschaften haben?
Während der Verwendung haben
Html.EditorFor
wir die Einschränkung, die Teilansicht zu verwenden.Erstellen Sie 3 Teilansichten unter dem
Shared
Ordner:Step1ViewModel.cshtml , Step3ViewModel.cshtml , Step3ViewModel.cshtml
Der Kürze halber poste ich gerade die erste Patialansicht. Andere Schritte sind die gleichen wie Darins Antwort.
Step1ViewModel.cs
Step1ViewModel.cshtml
Index.cshtml
Wenn es eine bessere Lösung gibt, kommentieren Sie diese bitte, um andere zu informieren.
quelle
Eine Möglichkeit besteht darin, einen Satz identischer Tabellen zu erstellen, in denen die in jedem Schritt gesammelten Daten gespeichert werden. Wenn alles gut geht, können Sie im letzten Schritt die reale Entität erstellen, indem Sie die temporären Daten kopieren und speichern.
Eine andere ist,
Value Objects
für jeden Schritt zu erstellen und dann inCache
oder zu speichernSession
. Wenn alles gut geht, können Sie Ihr Domain-Objekt daraus erstellen und speichernquelle