Edit: Ich habe diese Antwort in meinem Blog aktualisiert:
http://www.samwheat.com/post/The-function-of-ViewModels-in-MVC-web-development
Meine Antwort ist etwas langatmig, aber ich denke, es ist wichtig, Ansichtsmodelle mit anderen Arten von häufig verwendeten Modellen zu vergleichen, um zu verstehen, warum sie anders sind und warum sie notwendig sind.
Zusammenfassend und um die gestellte Frage direkt zu beantworten:
Im Allgemeinen ist ein Ansichtsmodell ein Objekt, das alle Eigenschaften und Methoden enthält, die für die Darstellung einer Ansicht erforderlich sind. Die Eigenschaften des Ansichtsmodells beziehen sich häufig auf Datenobjekte wie Kunden und Aufträge und enthalten darüber hinaus auch Eigenschaften, die sich auf die Seite oder die Anwendung selbst beziehen, wie z. B. den Benutzernamen, den Anwendungsnamen usw. View-Modelle bieten ein praktisches Objekt, das an eine Rendering-Engine übergeben werden kann, um eine HTML-Seite zu erstellen. Einer der vielen Gründe für die Verwendung eines View-Modells ist, dass View-Modelle eine Möglichkeit bieten, bestimmte Präsentationsaufgaben wie die Verarbeitung von Benutzereingaben, die Validierung von Daten, das Abrufen von Daten für die Anzeige usw. zu testen.
Hier ein Vergleich von Entitätsmodellen (auch DTOs oder Modelle genannt), Präsentationsmodellen und Ansichtsmodellen.
Datenübertragungsobjekte, auch bekannt als "Modell"
Ein Datentransferobjekt (DTO) ist eine Klasse mit Eigenschaften, die einem Tabellenschema in einer Datenbank entsprechen. DTOs sind so benannt, weil sie häufig für die Übertragung von Daten zu und von einem Datenspeicher verwendet werden.
Merkmale von DTOs:
- sind Geschäftsobjekte - ihre Definition ist abhängig von den Anwendungsdaten.
- Sie enthalten in der Regel nur Eigenschaften - keinen Code.
- Wird in erster Linie für den Transport von Daten zu und von einer Datenbank verwendet.
- Eigenschaften stimmen genau oder sehr genau mit Feldern in einer bestimmten Tabelle in einem Datenspeicher überein.
Datenbanktabellen sind in der Regel normalisiert, daher sind auch DTOs in der Regel normalisiert. Dadurch sind sie für die Darstellung von Daten nur bedingt geeignet. Für bestimmte einfache Datenstrukturen eignen sie sich jedoch oft recht gut.
Hier sind zwei Beispiele, wie DTOs aussehen könnten:
public class Customer
{
public int ID { get; set; }
public string CustomerName { get; set; }
}
public class Order
{
public int ID { get; set; }
public int CustomerID { get; set; }
public DateTime OrderDate { get; set; }
public Decimal OrderAmount { get; set; }
}
Präsentation Modelle
Ein Präsentationsmodell ist ein Dienstprogramm Klasse, die zur Darstellung von Daten auf einem Bildschirm oder in einem Bericht verwendet wird. Präsentationsmodelle werden in der Regel verwendet, um komplexe Datenstrukturen zu modellieren, die aus Daten von mehreren DTOs bestehen. Präsentationsmodelle stellen oft eine denormalisierte Sicht der Daten dar.
Merkmale von Präsentationsmodellen:
- sind Geschäftsobjekte - ihre Definition ist abhängig von den Anwendungsdaten.
- Enthalten meist Eigenschaften. Der Code beschränkt sich in der Regel auf die Formatierung von Daten oder deren Konvertierung in oder aus einem DTO. Präsentationsmodelle sollten keine Geschäftslogik enthalten.
- Sie zeigen oft eine denormalisierte Ansicht der Daten. Das heißt, sie kombinieren oft Eigenschaften aus mehreren DTOs.
- Enthalten oft Eigenschaften eines anderen Basistyps als ein DTO. Beispielsweise können Dollarbeträge als Zeichenketten dargestellt werden, so dass sie Kommas und ein Währungssymbol enthalten können.
- Oftmals werden sie durch ihre Verwendung und die Eigenschaften ihrer Objekte definiert. Mit anderen Worten, ein einfaches DTO, das als Backing Model für die Darstellung eines Gitters verwendet wird, ist in Wirklichkeit auch ein Präsentationsmodell im Kontext dieses Gitters.
Präsentationsmodelle werden "nach Bedarf" und "bei Bedarf" verwendet (während DTOs normalerweise an das Datenbankschema gebunden sind). Ein Präsentationsmodell kann verwendet werden, um Daten für eine ganze Seite, ein Gitter auf einer Seite oder ein Dropdown in einem Gitter auf einer Seite zu modellieren. Präsentationsmodelle enthalten oft Eigenschaften, die andere Präsentationsmodelle darstellen. Präsentationsmodelle werden oft für einen einmaligen Zweck konstruiert, z. B. um ein bestimmtes Raster auf einer einzelnen Seite darzustellen.
Ein Beispiel für ein Präsentationsmodell:
public class PresentationOrder
{
public int OrderID { get; set; }
public DateTime OrderDate { get; set; }
public string PrettyDate { get { return OrderDate.ToShortDateString(); } }
public string CustomerName { get; set; }
public Decimal OrderAmount { get; set; }
public string PrettyAmount { get { return string.Format("{0:C}", OrderAmount); } }
}
Modelle ansehen
Ein Ansichtsmodell ähnelt einem Präsentationsmodell insofern, als es eine unterstützende Klasse für die Darstellung einer Ansicht ist. Es unterscheidet sich jedoch stark von einem Präsentationsmodell oder einem DTO in der Art, wie es aufgebaut ist. View-Modelle enthalten oft dieselben Eigenschaften wie Präsentationsmodelle und DTOs, weshalb sie oft verwechselt werden.
Merkmale von Ansichtsmodellen:
- sind die einzige Datenquelle, die zum Rendern einer Seite oder eines Bildschirms verwendet wird. In der Regel bedeutet dies, dass ein Ansichtsmodell alle Eigenschaften bereitstellt, die jedes Steuerelement auf der Seite benötigt, um sich selbst korrekt darzustellen. Dadurch, dass das View-Modell die einzige Datenquelle für die Ansicht ist, werden seine Fähigkeiten und sein Wert für Unit-Tests erheblich verbessert.
- Sind zusammengesetzte Objekte die sowohl Eigenschaften enthalten, die aus Anwendungsdaten bestehen, als auch Eigenschaften, die vom Anwendungscode verwendet werden. Dieses Merkmal ist entscheidend für die Wiederverwendbarkeit des View-Modells und wird in den folgenden Beispielen erläutert.
- Enthält Anwendungscode. View Models enthalten normalerweise Methoden, die während des Renderings und der Interaktion des Benutzers mit der Seite aufgerufen werden. Dieser Code bezieht sich in der Regel auf Ereignisbehandlung, Animation, Sichtbarkeit von Steuerelementen, Styling usw.
- Enthält Code, der Geschäftsdienste aufruft, um Daten abzurufen oder an einen Datenbankserver zu senden. Dieser Code wird oft fälschlicherweise in einem Controller platziert. Der Aufruf von Geschäftsdiensten von einem Controller aus schränkt in der Regel die Nützlichkeit des View-Modells für Unit-Tests ein. Um das klarzustellen: View-Modelle selbst sollten keine Geschäftslogik enthalten, aber sie sollten Dienste aufrufen, die Geschäftslogik enthalten.
- Sie enthalten oft Eigenschaften, die andere Ansichtsmodelle für andere Seiten oder Bildschirme darstellen.
- werden "pro Seite" oder "pro Bildschirm" geschrieben. In der Regel wird für jede Seite oder jeden Bildschirm in einer Anwendung ein eigenes Ansichtsmodell geschrieben.
- Sie leiten sich in der Regel von einer Basisklasse ab, da die meisten Seiten und Bildschirme gemeinsame Eigenschaften haben.
Ansicht Modellzusammensetzung
Wie bereits erwähnt, sind Ansichtsmodelle zusammengesetzte Objekte, da sie Anwendungseigenschaften und Geschäftsdateneigenschaften in einem einzigen Objekt kombinieren. Beispiele für häufig verwendete Anwendungseigenschaften, die in Ansichtsmodellen verwendet werden, sind:
- Eigenschaften, die zur Anzeige des Anwendungsstatus verwendet werden, wie Fehlermeldungen, Benutzername, Status usw.
- Eigenschaften, die zum Formatieren, Anzeigen, Stilisieren oder Animieren von Steuerelementen verwendet werden.
- Eigenschaften, die für die Datenbindung verwendet werden, z. B. Listenobjekte und Eigenschaften, die Zwischendaten enthalten, die vom Benutzer eingegeben werden.
Die folgenden Beispiele zeigen, warum die zusammengesetzte Natur von View-Modellen wichtig ist und wie wir am besten ein effizientes und wiederverwendbares View-Modell konstruieren können.
Nehmen wir an, wir schreiben eine Webanwendung. Eine der Anforderungen an das Anwendungsdesign ist, dass der Seitentitel, der Benutzername und der Anwendungsname auf jeder Seite angezeigt werden müssen. Wenn wir eine Seite erstellen wollen, die ein Präsentationsauftragsobjekt anzeigt, können wir das Präsentationsmodell wie folgt ändern:
public class PresentationOrder
{
public string PageTitle { get; set; }
public string UserName { get; set; }
public string ApplicationName { get; set; }
public int OrderID { get; set; }
public DateTime OrderDate { get; set; }
public string PrettyDate { get { return OrderDate.ToShortDateString(); } }
public string CustomerName { get; set; }
public Decimal OrderAmount { get; set; }
public string PrettyAmount { get { return string.Format("{0:C}", OrderAmount); } }
}
Dieses Design könnte funktionieren aber was, wenn wir eine Seite erstellen wollen, die eine Liste von Bestellungen anzeigt? Die Eigenschaften "PageTitle", "UserName" und "ApplicationName" werden sich wiederholen und die Arbeit damit wird unhandlich. Und was ist, wenn wir im Konstruktor der Klasse eine Logik auf Seitenebene definieren wollen? Das ist nicht mehr möglich, wenn wir für jede Bestellung, die angezeigt werden soll, eine Instanz erstellen.
Komposition über Vererbung
Hier ist ein Weg, wie wir das Präsentationsmodell der Bestellung so umgestalten können, dass es ein echtes Ansichtsmodell wird und für die Anzeige eines einzelnen PresentationOrder-Objekts oder einer Sammlung von PresentationOrder-Objekten nützlich ist:
public class PresentationOrderVM
{
// Application properties
public string PageTitle { get; set; }
public string UserName { get; set; }
public string ApplicationName { get; set; }
// Business properties
public PresentationOrder Order { get; set; }
}
public class PresentationOrderVM
{
// Application properties
public string PageTitle { get; set; }
public string UserName { get; set; }
public string ApplicationName { get; set; }
// Business properties
public List<PresentationOrder> Orders { get; set; }
}
Wenn wir uns die beiden oben genannten Klassen ansehen, können wir erkennen, dass es sich bei einem Ansichtsmodell um ein Präsentationsmodell handelt, das ein anderes Präsentationsmodell als Eigenschaft enthält. Das Präsentationsmodell der obersten Ebene (d. h. das Ansichtsmodell) enthält Eigenschaften, die für die Seite oder Anwendung relevant sind, während das Präsentationsmodell (Eigenschaft) Eigenschaften enthält, die für die Anwendungsdaten relevant sind.
Wir können einen Schritt weiter gehen und eine Basis-View-Modell-Klasse erstellen, die nicht nur für PresentationOrders, sondern auch für jede andere Klasse verwendet werden kann:
public class BaseViewModel
{
// Application properties
public string PageTitle { get; set; }
public string UserName { get; set; }
public string ApplicationName { get; set; }
}
Jetzt können wir unsere PresentationOrderVM wie folgt vereinfachen:
public class PresentationOrderVM : BaseViewModel
{
// Business properties
public PresentationOrder Order { get; set; }
}
public class PresentationOrderVM : BaseViewModel
{
// Business properties
public List<PresentationOrder> Orders { get; set; }
}
Wir können unser BaseViewModel noch besser wiederverwendbar machen, indem wir es generisch machen:
public class BaseViewModel<T>
{
// Application properties
public string PageTitle { get; set; }
public string UserName { get; set; }
public string ApplicationName { get; set; }
// Business property
public T BusinessObject { get; set; }
}
Jetzt sind unsere Implementierungen mühelos:
public class PresentationOrderVM : BaseViewModel<PresentationOrder>
{
// done!
}
public class PresentationOrderVM : BaseViewModel<List<PresentationOrder>>
{
// done!
}