Bearbeiten: 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 langwierig, aber ich denke, es ist wichtig, Ansichtsmodelle mit anderen Arten häufig verwendeter Modelle zu vergleichen, um zu verstehen, warum sie unterschiedlich sind und warum sie notwendig sind.
Um die gestellte Frage zusammenzufassen und direkt zu beantworten:
Im Allgemeinen ist ein Ansichtsmodell ein Objekt, das alle Eigenschaften und Methoden enthält, die zum Rendern einer Ansicht erforderlich sind. Ansichtsmodelleigenschaften beziehen sich häufig auf Datenobjekte wie Kunden und Bestellungen und enthalten darüber hinaus Eigenschaften, die sich auf die Seite oder Anwendung selbst beziehen, wie z. B. Benutzername, Anwendungsname usw. Ansichtsmodelle bieten ein praktisches Objekt, an das sie an eine Rendering-Engine übergeben werden können Erstellen Sie eine HTML-Seite. Einer der vielen Gründe für die Verwendung eines Ansichtsmodells besteht darin, dass Ansichtsmodelle eine Möglichkeit bieten, bestimmte Präsentationsaufgaben wie das Verarbeiten von Benutzereingaben, das Überprüfen von Daten, das Abrufen von Daten zur Anzeige usw. zu testen.
Hier finden Sie einen Vergleich von Entitätsmodellen (a.ka. DTOs a.ka.-Modellen), Präsentationsmodellen und Ansichtsmodellen.
Datenübertragungsobjekte, auch bekannt als "Modell"
Ein Datenübertragungsobjekt (DTO) ist eine Klasse mit Eigenschaften, die mit einem Tabellenschema in einer Datenbank übereinstimmen. DTOs werden nach ihrer allgemeinen Verwendung für den Transport von Daten zu und von einem Datenspeicher benannt.
Eigenschaften von DTOs:
• Sind Geschäftsobjekte - ihre Definition hängt von den Anwendungsdaten ab.
• Enthält normalerweise nur Eigenschaften - kein Code.
• Wird hauptsächlich zum Transportieren von Daten zu und von einer Datenbank verwendet.
• Eigenschaften stimmen genau oder genau mit Feldern in einer bestimmten Tabelle in einem Datenspeicher überein.
Datenbanktabellen werden normalerweise normalisiert, daher werden DTOs normalerweise auch normalisiert. Dies macht sie für die Darstellung von Daten von begrenztem Nutzen. Für bestimmte einfache Datenstrukturen sind sie jedoch oft recht gut geeignet.
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äsentationsmodelle
Ein Präsentationsmodell ist eine Dienstprogrammklasse , mit der Daten auf einem Bildschirm oder Bericht gerendert werden. Präsentationsmodelle werden normalerweise verwendet, um komplexe Datenstrukturen zu modellieren, die aus Daten mehrerer DTOs bestehen. Präsentationsmodelle repräsentieren häufig eine denormalisierte Ansicht von Daten.
Eigenschaften von Präsentationsmodellen:
• Sind Geschäftsobjekte - ihre Definition hängt von den Anwendungsdaten ab.
• Enthalten hauptsächlich Eigenschaften. Code beschränkt sich normalerweise auf das Formatieren von Daten oder das Konvertieren in oder von einem DTO. Präsentationsmodelle sollten keine Geschäftslogik enthalten.
• Präsentieren Sie häufig eine denormalisierte Ansicht von Daten. Das heißt, sie kombinieren häufig Eigenschaften aus mehreren DTOs.
• Enthält häufig Eigenschaften eines anderen Basistyps als ein DTO. Beispielsweise können Dollarbeträge als Zeichenfolgen dargestellt werden, sodass sie Kommas und ein Währungssymbol enthalten können.
• Oft definiert durch ihre Verwendung sowie ihre Objektmerkmale. Mit anderen Worten, ein einfaches DTO, das als Hintergrundmodell für das Rendern eines Rasters verwendet wird, ist tatsächlich auch ein Präsentationsmodell im Kontext dieses Rasters.
Präsentationsmodelle werden "nach Bedarf" und "wo erforderlich" verwendet (während DTOs normalerweise an das Datenbankschema gebunden sind). Ein Präsentationsmodell kann verwendet werden, um Daten für eine ganze Seite, ein Raster auf einer Seite oder ein Dropdown-Menü für ein Raster auf einer Seite zu modellieren. Präsentationsmodelle enthalten häufig Eigenschaften, die andere Präsentationsmodelle sind. Präsentationsmodelle werden häufig für einen einmaligen Zweck erstellt, z. B. um ein bestimmtes Raster auf einer einzelnen Seite zu rendern.
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 anzeigen
Ein Ansichtsmodell ähnelt einem Präsentationsmodell, das eine Hintergrundklasse zum Rendern einer Ansicht darstellt. Es unterscheidet sich jedoch stark von einem Präsentationsmodell oder einem DTO in seiner Konstruktion. Ansichtsmodelle enthalten häufig dieselben Eigenschaften wie Präsentationsmodelle und DTOs. Aus diesem Grund werden sie häufig miteinander verwechselt.
Eigenschaften von Ansichtsmodellen:
• Sind die einzige Datenquelle, die zum Rendern einer Seite oder eines Bildschirms verwendet wird. Normalerweise bedeutet dies, dass ein Ansichtsmodell jede Eigenschaft verfügbar macht, die ein Steuerelement auf der Seite benötigt, um sich selbst korrekt zu rendern. Wenn Sie das Ansichtsmodell zur einzigen Datenquelle für die Ansicht machen, werden die Funktionen und der Wert für das Testen von Einheiten erheblich verbessert.
• Sind zusammengesetzte Objekte , die Eigenschaften enthalten, die aus Anwendungsdaten bestehen, sowie Eigenschaften, die vom Anwendungscode verwendet werden. Diese Eigenschaft ist beim Entwerfen des Ansichtsmodells für die Wiederverwendbarkeit von entscheidender Bedeutung und wird in den folgenden Beispielen erläutert.
• Anwendungscode enthalten. Ansichtsmodelle enthalten normalerweise Methoden, die beim Rendern und bei der Interaktion des Benutzers mit der Seite aufgerufen werden. Dieser Code bezieht sich normalerweise auf Ereignisbehandlung, Animation, Sichtbarkeit von Steuerelementen, Stil usw.
• Enthalten Code, der Geschäftsdienste aufruft, um Daten abzurufen oder an einen Datenbankserver zu senden. Dieser Code wird häufig fälschlicherweise in eine Steuerung eingefügt. Das Aufrufen von Geschäftsdiensten von einem Controller schränkt normalerweise die Nützlichkeit des Ansichtsmodells für Komponententests ein. Um es klar auszudrücken, sollten Ansichtsmodelle selbst keine Geschäftslogik enthalten, sondern Dienste aufrufen, die Geschäftslogik enthalten.
• Enthalten häufig Eigenschaften, die andere Ansichtsmodelle für andere Seiten oder Bildschirme sind.
• Sind "pro Seite" oder "pro Bildschirm" geschrieben. Ein eindeutiges Ansichtsmodell wird normalerweise für jede Seite oder jeden Bildschirm in einer Anwendung geschrieben.
• Normalerweise von einer Basisklasse abgeleitet, da die meisten Seiten und Bildschirme gemeinsame Eigenschaften haben.
Modellzusammensetzung anzeigen
Wie bereits erwähnt, sind Ansichtsmodelle zusammengesetzte Objekte, da sie Anwendungseigenschaften und Geschäftsdateneigenschaften für ein einzelnes Objekt kombinieren. Beispiele für häufig verwendete Anwendungseigenschaften, die in Ansichtsmodellen verwendet werden, sind:
• Eigenschaften, mit denen der Anwendungsstatus angezeigt wird, z. B. Fehlermeldungen, Benutzername, Status usw.
• Eigenschaften zum Formatieren, Anzeigen, Stilisieren oder Animieren von Steuerelementen.
• Eigenschaften, die für die Datenbindung verwendet werden, z. B. Listenobjekte und Eigenschaften, die vom Benutzer eingegebene Zwischendaten enthalten.
Die folgenden Beispiele zeigen, warum die zusammengesetzte Natur von Ansichtsmodellen wichtig ist und wie wir am besten ein Ansichtsmodell erstellen können, das effizient und wiederverwendbar ist.
Angenommen, wir schreiben eine Webanwendung. Eine der Anforderungen des Anwendungsdesigns besteht darin, dass der Seitentitel, der Benutzername und der Anwendungsname auf jeder Seite angezeigt werden müssen. Wenn Sie eine Seite zum Anzeigen eines Präsentationsreihenfolgeobjekts erstellen möchten, können Sie 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 ist, wenn wir eine Seite erstellen möchten, auf der eine Liste der Bestellungen angezeigt wird? Die Eigenschaften PageTitle, UserName und ApplicationName werden wiederholt und sind unhandlich. Was ist auch, wenn wir im Konstruktor der Klasse eine Logik auf Seitenebene definieren möchten? Dies ist nicht mehr möglich, wenn wir für jede angezeigte Bestellung eine Instanz erstellen.
Zusammensetzung über Vererbung
Hier ist eine Möglichkeit, das Bestellpräsentationsmodell neu zu faktorisieren, sodass es zu einem echten 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 sehen, dass eine Möglichkeit, über ein Ansichtsmodell nachzudenken, darin besteht, dass es ein Präsentationsmodell ist, das ein anderes Präsentationsmodell als Eigenschaft enthält. Das Präsentationsmodell der obersten Ebene (dh 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 Anwendungsdaten relevant sind.
Wir können unser Design noch einen Schritt weiter gehen und eine Modellklasse für die Basisansicht 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 folgendermaßen 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 wiederverwendbarer 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!
}