it-swarm.com.de

So ordnen Sie ein View Model in a zu POST Aktion?

Jeder Artikel, der im Internet zur Verwendung von ViewModels und zur Verwendung von Automapper gefunden wird, enthält die Richtlinien der Richtungszuordnung "Controller -> View". Sie nehmen ein Domänenmodell zusammen mit allen Auswahllisten in ein spezialisiertes ViewModel und übergeben es an die Ansicht. Das ist klar und gut.
. Die Ansicht hat ein Formular, und schließlich befinden wir uns in der Aktion POST. Hier kommen alle Modellbinder zusammen mit [offensichtlich] einem anderen View Model zur Szene, wobei [offensichtlich] verwandt zum ursprünglichen ViewModel mindestens in dem Teil der Namenskonventionen ist der Bindung und Validierung.

Wie ordnen Sie es Ihrem Domain Model zu?

Wenn es sich um eine Einfügeaktion handelt, könnten wir denselben Automapper verwenden. Aber was wäre, wenn es eine Update-Aktion wäre? Wir müssen unsere Domain-Entität aus dem Repository abrufen, ihre Eigenschaften entsprechend den Werten im ViewModel aktualisieren und im Repository speichern.

ADDENDUM 1 (9. Februar 2010): Manchmal reicht es nicht aus, die Eigenschaften des Modells zuzuweisen. Entsprechend den Werten von View Model sollte etwas gegen Domain Model unternommen werden. Das heißt, einige Methoden sollten für Domain Model aufgerufen werden. Wahrscheinlich sollte es eine Art Application Service-Schicht geben, die sich zwischen Controller und Domäne befindet, um View Models zu verarbeiten.


Wie organisiere ich diesen Code und wo soll er platziert werden, um die folgenden Ziele zu erreichen?

  • controller dünn halten
  • ehren Sie die SoC-Praxis
  • folgen Sie den Grundsätzen der domänengesteuerten Gestaltung
  • tROCKEN sein
  • fortsetzung folgt ...
84

Ich verwende eine IBuilder - Schnittstelle und implementiere sie mit ValueInjecter

public interface IBuilder<TEntity, TViewModel>
{
      TEntity BuildEntity(TViewModel viewModel);
      TViewModel BuildViewModel(TEntity entity);
      TViewModel RebuildViewModel(TViewModel viewModel); 
}

... (Implementierung) RebuildViewModel ruft einfach BuildViewModel(BuilEntity(viewModel)) auf

[HttpPost]
public ActionResult Update(ViewModel model)
{
   if(!ModelState.IsValid)
    {
       return View(builder.RebuildViewModel(model);
    }

   service.SaveOrUpdate(builder.BuildEntity(model));
   return RedirectToAction("Index");
}

ich schreibe nicht ViewModel. Ich schreibe Input, weil es viel kürzer ist, aber das ist nicht wirklich wichtig
ich hoffe es hilft

Update: Ich verwende diesen Ansatz jetzt in der ProDinner ASP.net-MVC-Demo-App , Es heißt jetzt IMapper. Es wird auch ein PDF bereitgestellt, in dem dieser Ansatz erläutert wird im Detail 

36
Omu

Tools wie AutoMapper können verwendet werden, um vorhandene Objekte mit Daten aus dem Quellobjekt zu aktualisieren. Die Controller-Aktion für die Aktualisierung könnte folgendermaßen aussehen:

[HttpPost]
public ActionResult Update(MyViewModel viewModel)
{
    MyDataModel dataModel = this.DataRepository.GetMyData(viewModel.Id);
    Mapper<MyViewModel, MyDataModel>(viewModel, dataModel);
    this.Repostitory.SaveMyData(dataModel);
    return View(viewModel);
}

Abgesehen von dem, was im obigen Ausschnitt sichtbar ist:

  • POST-Daten zum Anzeigen der Model + -Validierung werden in ModelBinder durchgeführt (kann mit benutzerdefinierten Bindungen erweitert werden)
  • Die Fehlerbehandlung (d. H. Das Auslösen von Ausnahmen für Datenzugriffsausnahmen durch das Repository abfangen) kann durch den [HandleError] -Filter ausgeführt werden

Die Controller-Aktion ist ziemlich dünn und die Anliegen sind voneinander getrennt: Zuordnungsprobleme werden in der AutoMapper-Konfiguration behandelt, die Validierung erfolgt durch ModelBinder und der Datenzugriff durch das Repository.

7
PanJanek

Ich möchte sagen, dass Sie den Begriff ViewModel für beide Richtungen der Client-Interaktion wiederverwenden. Wenn Sie genug ASP.NET-MVC-Code in der Wildnis gelesen haben, haben Sie wahrscheinlich den Unterschied zwischen einem ViewModel und einem EditModel gesehen. Das finde ich wichtig.

Ein ViewModel stellt alle Informationen dar, die zum Rendern einer Ansicht erforderlich sind. Dies kann Daten umfassen, die an statischen, nicht interaktiven Orten gerendert werden, und auch Daten, die lediglich eine Überprüfung durchführen, um zu entscheiden, was genau gerendert wird. Eine Controller-GET-Aktion ist im Allgemeinen dafür verantwortlich, das ViewModel für seine View zusammenzufassen.

Ein EditModel (oder möglicherweise ein ActionModel) stellt die Daten dar, die erforderlich sind, um die Aktion auszuführen, die der Benutzer für diesen POST ausführen wollte. Ein EditModel versucht also wirklich, eine Aktion zu beschreiben. Dies wird wahrscheinlich einige Daten aus dem ViewModel ausschließen, und obwohl es verwandt ist, denke ich, ist es wichtig zu wissen, dass sie tatsächlich unterschiedlich sind.

Eine Idee

Das heißt, Sie könnten sehr leicht eine AutoMapper-Konfiguration haben, um von Model -> ViewModel zu gehen, und eine andere, um von EditModel -> Model zu gehen. Dann müssen die verschiedenen Controller-Aktionen nur AutoMapper verwenden. Das EditModel könnte eine Funktion haben, um seine Eigenschaften gegen das Modell zu überprüfen und diese Werte auf das Modell selbst anzuwenden. Es tut nichts anderes und Sie haben ModelBinders in MVC, um die Anfrage trotzdem dem EditModel zuzuordnen. 

Eine andere Idee

Darüber hinaus habe ich in letzter Zeit darüber nachgedacht, dass die Idee eines ActionModels so aussieht, als würde der Client Ihnen zurückschicken. Dies ist eigentlich die Beschreibung mehrerer Aktionen, die der Benutzer ausgeführt hat, und nicht nur eine große Datenkugel. Dies würde sicherlich ein wenig Javascript auf der Clientseite erfordern, aber die Idee ist faszinierend, denke ich.

Wenn der Benutzer Aktionen auf dem Bildschirm ausführt, den Sie ihm präsentiert haben, erstellt Javascript eine Liste von Aktionsobjekten. Ein Beispiel ist möglicherweise der Benutzer auf einem Mitarbeiterinformationsbildschirm. Sie aktualisieren den Nachnamen und fügen eine neue Adresse hinzu, da der Mitarbeiter kürzlich verheiratet war. Unter den Covers erzeugt dies eine ChangeEmployeeName- und eine AddEmployeeMailingAddress-Objekte zu einer Liste. Der Benutzer klickt auf "Speichern", um die Änderungen zu übernehmen, und Sie übermitteln die Liste der zwei Objekte, von denen jedes nur die Informationen enthält, die zur Ausführung der jeweiligen Aktion erforderlich sind.

Sie benötigen einen intelligenteren ModelBinder als den standardmäßigen, aber ein guter JSON-Serialisierer sollte in der Lage sein, die Zuordnung der clientseitigen Aktionsobjekte zu den serverseitigen Objekten zu übernehmen. Die serverseitigen (wenn Sie sich in einer 2-Tier-Umgebung befinden) können leicht über Methoden verfügen, mit denen die Aktion für das Modell abgeschlossen wurde, mit dem sie arbeiten. Daher erhält die Controller-Aktion nur eine ID für die Model-Instanz, die sie abrufen kann, und eine Liste von Aktionen, die für sie ausgeführt werden sollen. Oder die Aktionen haben die ID in sich, um sie sehr voneinander zu trennen.

Vielleicht wird so etwas auf der Serverseite realisiert:

public interface IUserAction<TModel>
{
     long ModelId { get; set; }
     IEnumerable<string> Validate(TModel model);
     void Complete(TModel model);
}

[Transaction] //just assuming some sort of 2-tier with transactions handled by filter
public ActionResult Save(IEnumerable<IUserAction<Employee>> actions)
{
     var errors = new List<string>();
     foreach( var action in actions ) 
     {
         // relying on ORM's identity map to prevent multiple database hits
         var employee = _employeeRepository.Get(action.ModelId);
         errors.AddRange(action.Validate(employee));
     }

     // handle error cases possibly rendering view with them

     foreach( var action in editModel.UserActions )
     {
         var employee = _employeeRepository.Get(action.ModelId);
         action.Complete(employee);
         // against relying on ORMs ability to properly generate SQL and batch changes
         _employeeRepository.Update(employee);
     }

     // render the success view
}

Das macht die Aktion "Zurücksenden" wirklich ziemlich generisch, da Sie sich darauf verlassen müssen, dass Ihre ModelBinder-Instanz die richtige IUserAction-Instanz und Ihre IUserAction-Instanz dazu bringt, entweder die richtige Logik selbst auszuführen oder (wahrscheinlicher) das Model mit den Informationen aufzurufen.

Wenn Sie sich in einer dreistufigen Umgebung befanden, könnte die IUserAction einfach aus einfachen DTOs bestehen, die über die Grenze geschossen und auf ähnliche Weise auf der App-Ebene ausgeführt werden. Abhängig davon, wie Sie diese Schicht ausführen, kann sie sehr leicht aufgeteilt werden und trotzdem in einer Transaktion verbleiben (was Agatha in Frage kommt, und die Identitätskarte von DI und NHibernate ausnutzt).

Ich bin mir jedoch sicher, dass dies keine perfekte Idee ist, es würde einige JS auf Client-Seite benötigen, um es zu managen, und ich war noch nicht in der Lage, ein Projekt zu erstellen, um zu sehen, wie es sich entwickelt, aber der Beitrag versuchte, darüber nachzudenken, wie es geht Dorthin und zurück, so dachte ich, ich würde meine Gedanken geben. Ich hoffe, es hilft, und ich würde gerne andere Möglichkeiten erfahren, um die Interaktionen zu verwalten.

5
Sean Copenhaver

Sie müssen kein Viewmodel einer Domäne zuordnen, da Ihr Viewmodel möglicherweise mehr als ein Domänenmodell erstellt wird. Für Bildschirm (ui) optimierte Ansichtsmodelle, die sich vom Domänenmodell unterscheiden.

http://lostechies.com/jimmybogard/2009/06/30/how-we-do-mvc-view-models/

0
oguzh4n