5. Die Ansicht und ihr Modell
5.1. Introduction
Kehren wir zur Architektur einer Anwendung ASP.NET MVC zurück:
![]() |
Im vorigen Kapitel haben wir untersucht, wie ASP.NET MVC die Informationen der Anfrage [1] einer Aktion [2a] in Form eines Modells darstellte, das Validierungsbeschränkungen enthalten konnte. Dieses Modell wurde der Aktion als Eingabe übergeben und wir haben es als Aktionsmodell bezeichnet. Wir befassen uns nun mit dem häufigsten Ergebnis einer Aktion, dem Typ [ViewResult], der einer Ansicht V [3] zusammen mit ihrem Modell M [2c] entspricht. Dieses Modell wird als Modell der Ansicht V bezeichnet und ist nicht mit dem soeben untersuchten Modell der Aktion zu verwechseln. Das eine ist die Eingabe der Aktion, das andere die Ausgabe.
Beginnen wir damit, ein neues Projekt [Exemple-03] [1] zu erstellen, das sich ebenfalls innerhalb derselben Lösung befindet und vom Basistyp ASP.NET MVC ist:
![]() |
Erstellen wir einen Controller mit dem Namen [First] [2]. Der für diesen Controller generierte Code lautet wie folgt:
using System.Web.Mvc;
namespace Exemple_03.Controllers
{
public class FirstController : Controller
{
public ActionResult Index()
{
return View();
}
}
}
- Zeilen 7–10: Eine Aktion [Index] wurde erstellt. Der Typ des Ergebnisses der Methode [Index] ist der der Klasse [ActionResult], von der die meisten möglichen Ergebnisse einer Aktion abgeleitet sind;
- Zeile 9: Die Methode [View] der Klasse [Controller] (Zeile 5) gibt einen Typ [ViewResult] zurück, der von [ActionResult] abgeleitet ist. Diese Methode lässt zahlreiche Überladungen zu. Wir werden uns einige davon ansehen. Die wichtigste ist die folgende:
![]() |
- Der erste Parameter ist der Name der Ansicht. Fehlt dieser, wird die Ansicht verwendet, die denselben Namen trägt wie die Aktion, die das [ViewResult] erzeugt, und die im Ordner [/Views/{controller}] gesucht wird, wobei {controller} der Name des Controllers ist;
- Der zweite Parameter ist die Vorlage der Ansicht. Fehlt dieser, hat die Ansicht keine Vorlage.
Die folgende Methode [Index]:
public ActionResult Index()
{
return View();
}
fordert die Ansicht [/Views/First/Index.cshtml] „ “ auf, sich anzuzeigen. Dabei wird ihr kein Modell übergeben. Erstellen wir [1] im Ordner [/Views/First]:
![]() |
und erstellen wir darin die Ansicht [Index] [2]:
![]() |
![]() |
Wir geben den Namen der Ansicht als [3] an. Diese wird unter [4] angelegt. Der generierte Code lautet wie folgt:
@{
Layout = null;
}
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width" />
<title>Index</title>
</head>
<body>
<div>
</div>
</body>
</html>
Hier handelt es sich um klassischen HTML-Code, mit Ausnahme der Zeilen 1–3, die C#-Code sind. Das Programm, das die Ansichten verwaltet, wird als Ansichts-Engine bezeichnet. Sie ist dafür zuständig, alles, was kein HTML ist, in HTML umzuwandeln. Letztendlich ist es nämlich genau das, was an den Client gesendet wird. Die View-Engine heißt hier [Razor]. Sie ermöglicht es, C#-Code in eine Ansicht einzubinden. [Razor] interpretiert diesen C#-Code und erzeugt daraus HTML-Code. Hier sind einige Grundregeln für die Einbindung von C#-Code in eine Ansicht:
- Der Wechsel von HTML zu C# erfolgt beim Auftreten des Zeichens @ (Zeile 1). Wenn dieses Zeichen einen Codeblock einleitet, werden geschweifte Klammern gesetzt (Zeilen 1 und 3). Wenn es eine Variable einleitet, deren Wert abgerufen werden soll, schreibt man einfach @variable;
- Die Umstellung von C# auf HTML erfolgt beim Auftreten des Zeichens < (Zeile 5). Manchmal muss man diese Umstellung erzwingen, insbesondere wenn man reinen Text ohne HTML-Tags in die Seite einfügt. In diesem Fall verwendet man das <text>-Tag, um den Text einzufügen: <text>hier reiner Text</text>.
Zeile 2 oben zeigt an, dass die Ansicht [Index] keine Masterseite hat.
Ändern wir die Ansicht wie folgt:
@{
Layout = null;
string vue = "Index";
}
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width" />
<title>Index</title>
</head>
<body>
<div>
<h3>Vue @vue</h3>
</div>
</body>
</html>
- Zeile 3: definiert eine C#-Variable;
- Zeile 15: gibt den Wert dieser Variablen aus.
Rufen wir nun die Ansichten URL und [/First/Index] auf:
![]() |
Der empfangene Code HTML lautet wie folgt:
Es handelt sich um ein reines HTML-Dokument. Der gesamte C#-Code ist verschwunden.
5.2. Verwenden Sie den Code [ViewBag], um Informationen an die Ansicht zu übergeben
Wir erstellen eine neue Aktion namens [Action01], die der Ansicht [Action01.cshtml] zugeordnet ist:
![]() |
Die Aktion [Action01] lautet wie folgt:
// Aktion01
public ViewResult Action01()
{
ViewBag.info = string.Format("Contrôleur={0}, Action={1}", RouteData.Values["controller"], RouteData.Values["action"]);
return View();
}
- Zeile 4: Hier wird die Eigenschaft [ViewBag] des Controllers verwendet. Es handelt sich um ein dynamisches Objekt, dem Eigenschaften hinzugefügt werden können, wie es in Zeile 4 geschieht. Dieses Objekt hat die Besonderheit, dass es auch für die Ansicht zugänglich ist. Es ist also eine Möglichkeit, Informationen an die Ansicht zu übermitteln;
- Zeile 5: Die Standardansicht der Aktion wird angefordert. Es handelt sich um die Ansicht [/First/Action01.cshtml]. Es wird ihr kein Template übergeben.
Die Ansicht [Action01.cshtml] sieht wie folgt aus:
@{
Layout = null;
}
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width" />
<title>Action01</title>
</head>
<body>
<div>
<h4>@ViewBag.info</h4>
</div>
</body>
</html>
- Zeile 14: Die Eigenschaft [ViewBag.info] wird angezeigt.
Testen wir es. Wir fragen nach URL und [/First/Action01]:
![]() |
5.3. Verwendung eines stark typisierten Modells zur Übergabe von Informationen an die Ansicht
Die vorherige Methode hat den Nachteil, dass Fehler nicht vor der Ausführung erkannt werden können. Wenn also die Ansicht [Action01.cshtml] den Code
<h4>@ViewBag.Info</h4>
verwendet, kommt es zu einem Fehler, da die Eigenschaft [Info] nicht existiert. Die durch die Aktion [Action01] erstellte Eigenschaft heißt [info]. Um dieses Problem zu vermeiden, kann man ein stark typisiertes Modell verwenden.
In einem der zuvor untersuchten Beispiele lautete die Aktion wie folgt:
// Aktion10
public ContentResult Action10(ActionModel03 modèle)
{
string erreurs = getErrorMessagesFor(ModelState);
string texte = string.Format("email={0}, jour={1}, info1={2}, info2={3}, info3={4}, erreurs={5}",
modèle.Email, modèle.Jour, modèle.Info1, modèle.Info2, modèle.Info3, erreurs);
return Content(texte, "text/plain", Encoding.UTF8);
}
Die Aktion [Action10] übermittelte an ihren Client sechs Informationen (E-Mail, Tag, Info1, Info2, Info3, Fehler) in Form einer Zeichenkette. Wir werden diese Informationen in einem Ansichtsmodell [ViewModel01] übermitteln. Da dieses Modell Informationen aus [ActionModel03] übernimmt, werden wir es von dieser Klasse ableiten.
Zunächst kopieren wir [ActionModel03] aus dem Projekt [Exemple-02] in das aktuelle Projekt [Exemple-03]:
![]() |
und ändern dessen Namensraum so, dass er dem des Projekts [Exemple-03] entspricht:
using System.ComponentModel.DataAnnotations;
namespace Exemple_03.Models
{
public class ActionModel03
{
[Required(ErrorMessage = "Le paramètre email est requis")]
[EmailAddress(ErrorMessage = "Le paramètre email n'a pas un format valide")]
public string Email { get; set; }
[Required(ErrorMessage = "Le paramètre jour est requis")]
[RegularExpression(@"^\d{1,2}$", ErrorMessage = "Le paramètre jour doit avoir 1 ou 2 chiffres")]
public string Jour { get; set; }
[Required(ErrorMessage = "Le paramètre info1 est requis")]
[MaxLength(4, ErrorMessage = "Le paramètre info1 ne peut avoir plus de 4 caractères")]
public string Info1 { get; set; }
[Required(ErrorMessage = "Le paramètre info2 est requis")]
[MinLength(2, ErrorMessage = "Le paramètre info2 ne peut avoir moins de 2 caractères")]
public string Info2 { get; set; }
[Required(ErrorMessage = "Le paramètre info3 est requis")]
[MinLength(4, ErrorMessage = "Le paramètre info3 doit avoir 4 caractères exactement")]
[MaxLength(4, ErrorMessage = "Le paramètre info3 doit avoir 4 caractères exactement")]
public string Info3 { get; set; }
}
}
- Zeile 2: der neue Namensraum;
Anschließend erstellen wir die Klasse [ViewModel01]:
![]() |
Der Code von [ViewModel01] lautet wie folgt:
namespace Exemple_03.Models
{
public class ViewModel01 : ActionModel03
{
public string Erreurs { get; set; }
}
}
- Zeile 3: Die Klasse erbt von [ActionModel03] und somit auch die Eigenschaften von [Email, Jour, Info1, Info2, Info3];
- Zeile 5: Die Eigenschaft [Erreurs] wird hinzugefügt.
Nun schreiben wir die Aktion [Action02], die:
- als Eingabe das Aktionsmodell [ActionModel03] akzeptiert;
- und als Ausgabe die Ansichtsvorlage [ViewModel01] liefert.
Der Code lautet wie folgt:
// Aktion02
public ViewResult Action02(ActionModel03 modèle)
{
string erreurs = getErrorMessagesFor(ModelState);
return View(new ViewModel01(){Email=modèle.Email, Jour=modèle.Jour, Info1=modèle.Info1, Info2=modèle.Info2, Info3=modèle.Info3, Erreurs=erreurs});
}
- Zeile 1: [Action02] erhält die Aktionsvorlage [ActionModel03]. Sie gibt ein Ergebnis vom Typ [ViewResult] zurück;
- Zeile 4: Die Fehler im Zusammenhang mit der Aktionsvorlage [ActionModel03] werden in der Zeichenkette [erreurs] zusammengefasst. Die Methode [getErrorMessagesFor] wurde auf Seite 65 beschrieben und in den Controller [First] des neuen Projekts aufgenommen;
- Zeile 5: Die Methode [View] wird mit einem Parameter aufgerufen. Dieser ist das View-Modell. Das View-Modell ist nicht angegeben. Daher wird das Standard-View [/Views/First/Action02] verwendet. Das View-Modell [ViewModel01] wird instanziiert und mit den fünf Informationen aus dem Aktionsmodell [ActionModel03] sowie der in Zeile 4 erstellten Information [erreurs] initialisiert.
Nun erstellen wir die Ansicht [/First/Action02.cshtml]:
![]() |
Der Code lautet wie folgt:
@model Exemple_03.Models.ViewModel01
@{
Layout = null;
}
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width" />
<title>Action02</title>
</head>
<body>
<h3>Informations du modèle de vue</h3>
<ul>
<li>Email : @Model.Email</li>
<li>Jour : @Model.Jour</li>
<li>Info1 : @Model.Info1</li>
<li>Info2 : @Model.Info2</li>
<li>Info3 : @Model.Info3</li>
<li>Erreurs : @Model.Erreurs</li>
</ul>
</body>
</html>
- Die Neuerung befindet sich in Zeile 1. Die Notation [@model] legt den Typ der Vorlagenansicht fest. Auf diese Vorlage wird anschließend durch die Notation [@Model] (Zeilen 16–21) verwiesen;
- Zeilen 15–22: Die Informationen der Vorlage werden in einer Liste angezeigt.
Sehen wir uns einige Beispiele für die Ausführung der Aktion [Action02] an.
Zunächst ohne Parameter:
![]() |
dann mit falschen Parametern:
![]() |
dann mit korrekten Parametern:
![]() |
In diesem Beispiel übernimmt die Ansichtsvorlage [ViewModel01] die Informationen aus der Aktionsvorlage [ActionModel03]. Dies ist häufig der Fall. Man kann dann eine einzige Vorlage verwenden, die sowohl als Aktionsvorlage als auch als Ansichtsvorlage dient. Wir erstellen eine neue Vorlage [ActionModel04]:
![]() |
die wie folgt aussehen wird:
using System.ComponentModel.DataAnnotations;
using System.Web.Mvc;
namespace Exemple_03.Models
{
[Bind(Exclude="Erreurs")]
public class ActionModel04
{
// ---------------------- Aktion --------------------------------
[Required(ErrorMessage = "Le paramètre email est requis")]
[EmailAddress(ErrorMessage = "Le paramètre email n'a pas un format valide")]
public string Email { get; set; }
[Required(ErrorMessage = "Le paramètre jour est requis")]
[RegularExpression(@"^\d{1,2}$", ErrorMessage = "Le paramètre jour doit avoir 1 ou 2 chiffres")]
public string Jour { get; set; }
[Required(ErrorMessage = "Le paramètre info1 est requis")]
[MaxLength(4, ErrorMessage = "Le paramètre info1 ne peut avoir plus de 4 caractères")]
public string Info1 { get; set; }
[Required(ErrorMessage = "Le paramètre info2 est requis")]
[MinLength(2, ErrorMessage = "Le paramètre info2 ne peut avoir moins de 2 caractères")]
public string Info2 { get; set; }
[Required(ErrorMessage = "Le paramètre info3 est requis")]
[MinLength(4, ErrorMessage = "Le paramètre info3 doit avoir 4 caractères exactement")]
[MaxLength(4, ErrorMessage = "Le paramètre info3 doit avoir 4 caractères exactement")]
public string Info3 { get; set; }
// ---------------------- Ansicht --------------------------------
public string Erreurs { get; set; }
}
}
- Zeilen 8–28: das Aktionsmodell mit seinen Integritätsbeschränkungen. Diese Felder werden auch Teil der Ansicht sein;
- Zeile 31: eine Eigenschaft, die spezifisch für das Modell der Ansicht ist. Sie wurde durch die Anmerkung in Zeile 5 aus dem Modell der Aktion ausgeschlossen.
Wir erstellen die folgende neue Aktion [Action03]:
// Aktion03
public ViewResult Action03(ActionModel04 modèle)
{
modèle.Erreurs = getErrorMessagesFor(ModelState);
return View(modèle);
}
- Zeile 2: [Action03] erhält das Aktionsmodell vom Typ [ActionModel04];
- Zeile 5: und gibt dieselbe Vorlage als Ansichtsvorlage zurück;
- Zeile 4: ergänzt durch die Information [Erreurs];
Nun müssen wir nur noch die Ansicht [/First/Action03.cshtml] erstellen:
![]() |
- in [1]: Rechtsklick im Code von [Action03], dann [Ajouter une vue];
- in [2]: der standardmäßig vorgeschlagene Name der Ansicht;
- in [3]: Geben Sie an, dass eine stark typisierte Ansicht erstellt wird;
- in [4]: Wählen Sie aus der Dropdown-Liste die richtige Klasse aus, in diesem Fall die Klasse [ActionModel04];
- in [5]: die erstellte Ansicht.
Wir geben der Ansicht [Action03] denselben Code wie der Ansicht [Action02]. Nur die Ansichtsvorlage (Zeile 1) und der Seitentitel (Zeile 11) ändern sich:
@model Exemple_03.Models.ActionModel04
@{
Layout = null;
}
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width" />
<title>Action03</title>
</head>
<body>
<h3>Informations du modèle de vue</h3>
<ul>
<li>Email : @Model.Email</li>
<li>Jour : @Model.Jour</li>
<li>Info1 : @Model.Info1</li>
<li>Info2 : @Model.Info2</li>
<li>Info3 : @Model.Info3</li>
<li>Erreurs : @Model.Erreurs</li>
</ul>
</body>
</html>
Rufen wir nun die Aktion [Action03] ohne Parameter auf:
![]() |
Die Ergebnisse sind dieselben wie zuvor. Häufig wird für die Aktion und die Ansicht dasselbe Modell verwendet, da das Ansichtsmodell oft Informationen aus dem Aktionsmodell übernimmt. Man verwendet dann ein umfassenderes Modell, das sowohl von der Aktion als auch von der dadurch generierten Ansicht genutzt werden kann. Man sollte darauf achten, Informationen, die nicht zum Aktionsmodell gehören, aus der Datenbindung auszuschließen. Andernfalls könnte ein gut informierter Benutzer Teile des Ansichtsmodells ohne unser Wissen initialisieren.
5.4. [Razor] – Erste Schritte
Wir werden nun einige Elemente der Ansichten [Razor] vorstellen, vor allem die Anweisungen foreach und if.
Nehmen wir an, wir möchten eine Liste von Personen in einer Tabelle HTML darstellen. Das View-Modell könnte wie folgt aussehen: [ViewModel02]:
![]() |
namespace Exemple_03.Models
{
public class ViewModel02
{
public Personne[] Personnes { get; set; }
public ViewModel02()
{
Personnes = new Personne[] { new Personne { Nom = "Pierre", Age = 44 }, new Personne { Nom = "Pauline", Age = 12 } };
}
}
public class Personne
{
public string Nom { get; set; }
public int Age { get; set; }
}
}
- Die Ansicht des Modells ist die Klasse [ViewModel02], Zeilen 3–10;
- Zeile 5: Das Modell verfügt über ein Array von Personen vom Typ [Personne], definiert in den Zeilen 12–16;
- Zeilen 6–10: Der Modellkonstruktor initialisiert die Eigenschaft [Personnes] aus Zeile 5 mit einem Array aus zwei Personen.
Die Aktion, die dieses Modell ausgibt, lautet wie folgt: [Action04]:
// Aktion04
public ViewResult Action04()
{
return View(new ViewModel02());
}
- Zeile 2: Die Aktion hat kein Eingabemodell;
- Zeile 4: Sie wechselt zu ihrer Standardansicht, einer Instanz der soeben definierten Vorlage [ViewModel02].
Die Ansicht [Action04.cshtml] zeigt das Modell [ViewModel02] an:
![]() |
Der Code der Ansicht [Action04.cshtml] lautet wie folgt:
@model Exemple_03.Models.ViewModel02
@using Exemple_03.Models
@{
Layout = null;
}
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width" />
<title>Action04</title>
</head>
<body>
<table border="1">
<thead>
<tr>
<th>Nom</th>
<th>Age</th>
</tr>
</thead>
<tbody>
@foreach (Personne p in Model.Personnes)
{
<tr>
<td>@p.Nom</td>
<td>@p.Age</td>
</tr>
}
</tbody>
</table>
</body>
</html>
- Zeile 1: die Vorlage der Ansicht;
- Zeile 2: Import des Namensraums der Klasse [Personne], die in Zeile 24 verwendet wird;
- Zeilen 16–32: das Array HTML, das die Personen des Modells anzeigt;
- Zeile 24: Der Beginn des C#-Codes wird durch das Zeichen @ markiert. Die Anweisung [foreach] durchläuft alle Personen des Modells in einer Schleife;
- Zeilen 26–27: Das Zeichen < beendet den C#-Code und leitet den Code HTML ein. Anschließend folgt erneut das Zeichen @, um wieder in den C#-Modus zu wechseln und den Namen der Person auszugeben. Dann folgt erneut das Zeichen <, das den Wechsel in den Modus HTML bewirkt;
- Zeile 28: Das Alter der Person wird geschrieben.
Die Ausführung der Aktion [Action04] liefert folgendes Ergebnis:
![]() |
Andere Elemente einer Ansicht können aus einer Sammlung gespeist werden: Listen (mit oder ohne Dropdown), Optionsfelder und Kontrollkästchen. Betrachten wir das folgende neue Beispiel, das eine Dropdown-Liste anzeigt.
Das Template [ViewModel05] sieht wie folgt aus:
![]() |
namespace Exemple_03.Models
{
public class ViewModel05
{
public Personne2[] Personnes { get; set; }
public int SelectedId { get; set; }
public ViewModel05()
{
Personnes = new Personne2[] {
new Personne2 { Id = 1, Prénom = "Pierre", Nom = "Martino" },
new Personne2 { Id = 2, Prénom = "Pauline", Nom = "Pereiro" },
new Personne2 { Id = 3, Prénom = "Jacques", Nom = "Alfonso" } };
SelectedId = 2;
}
}
public class Personne2
{
public int Id { get; set; }
public string Nom { get; set; }
public string Prénom { get; set; }
}
}
- Zeile 18: eine Klasse [Personne2] mit drei Eigenschaften;
- Zeile 3: das Modell [ViewModel05] der Ansicht;
- Zeile 5: die Liste der Personen, die in der Dropdown-Liste angezeigt werden sollen, in der Form [Prénom Nom];
- Zeile 6: das [Id] der Person, die in der Dropdown-Liste ausgewählt werden soll;
- Zeilen 8–16: Der Konstruktor, der ein Array mit drei Personen erstellt (Zeilen 10–13) und das [Id] der Person festlegt, die als ausgewählt angezeigt werden soll.
Die Ansicht [Action05.cshtml] zeigt dieses Modell an:
![]() |
Der Code lautet wie folgt:
@model Exemple_03.Models.ViewModel05
@using Exemple_03.Models
@{
Layout = null;
}
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width" />
<title>Action05</title>
</head>
<body>
<select>
@foreach (Personne2 p in Model.Personnes)
{
string selected = "";
if (p.Id == Model.SelectedId)
{
selected = "selected=\"selected\"";
}
<option value="@p.Id" @selected>@p.Prénom @p.Nom</option>
}
</select>
</body>
</html>
Die Merkmale der Dropdown-Liste HTML wurden in Abschnitt 2.5.2.6 vorgestellt. Hier noch einmal zur Erinnerung:
Combo | <select size="1" name="cmbValeurs"> <option value="1">Auswahl 1</option> <option selected="selected" value="2">Auswahl 2</option> <option value="3">Auswahl 3</option> </select> |
Tag HTML | <select size=".." name=".."> <option [selected="selected"] value=”v”>...</option> ... </select> zeigt die Texte zwischen den Tags <option>...</option> |
Attribute | name="cmbValeurs": Name des Steuerelements. size="1": Anzahl der sichtbaren Listenelemente. size="1" macht die Liste zu einer Combobox. selected="selected": Wenn dieses Schlüsselwort für ein Listenelement vorhanden ist, wird dieses in der Liste als ausgewählt angezeigt. In unserem obigen Beispiel erscheint das Listenelement choix2 als ausgewähltes Element der Combobox, wenn diese zum ersten Mal angezeigt wird. value=”v“: Wenn das Element vom Benutzer ausgewählt wird, wird dieser Wert [v] an den Server gesendet. Fehlt dieses Attribut, wird der angezeigte und ausgewählte Text an den Server gesendet. |
Der Code in den Zeilen 17–25 generiert die Tags <option>, die in das Tag <select> in Zeile 16 eingefügt werden.
- Zeile 17: Die Liste der Personen im Modell wird durchlaufen;
- Zeile 20: Es wird geprüft, ob die aktuelle Person diejenige ist, die ausgewählt werden soll. Wenn ja, wird der Text „selected="selected"“ vorbereitet, der in das Tag <option> eingefügt werden soll;
- Zeile 24: Das Tag <option> wird geschrieben.
Rufen wir die Aktion [Action05] auf:
![]() |
- In [1,2] werden die Personen in der Form [Prénom Nom] angezeigt;
- In [1,2] ist die ausgewählte Person diejenige, bei der der Wert von [Id] gleich 2 ist.
Betrachten wir nun den Quellcode HTML der obigen Seite:
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width" />
<title>Action05</title>
</head>
<body>
<select>
<option value="1" >Pierre Martino</option>
<option value="2" selected="selected">Pauline Pereiro</option>
<option value="3" >Jacques Alfonso</option>
</select>
</body>
</html>
- Zeilen 10–12: die drei durch den Code [Razor] generierten -Tags;option;
- Zeile 11: Es wurde tatsächlich die Person aus [Id]=2 ausgewählt.
Die beiden obigen Beispiele reichen uns aus. Beim Schreiben einer Ansicht [Razor] muss man der Versuchung widerstehen, Logik darin unterzubringen. Der C#-Code würde dies zwar zulassen. Im MVC-Modell muss die Logik jedoch in der Aktion oder in den unteren Schichten ([Metier, DAO]) liegen, nicht in der Ansicht. Selbst wenn man sich an das Modell MVC hält, kann es vorkommen, dass sich in der Ansicht viel Logik zur Berechnung von Zwischenwerten befindet. Dies kann bedeuten, dass das verwendete Modell nicht detailliert genug ist. Es muss die Endwerte enthalten, die die Ansicht benötigt, damit diese sie nicht selbst berechnen muss. Eine gute Ansicht ist eine Ansicht, in der nur ein Minimum an Logik vorhanden ist und in der die Struktur HTML der Ansicht klar bleibt. Wenn zu viel C#-Code eingefügt wird, kann die Struktur HTML unlesbar werden.
Im obigen Beispiel könnte die Dropdown-Liste von einem Internetnutzer verwendet werden, und man möchte dann wissen, welche Person er ausgewählt hat. Dazu benötigen wir ein Formular.
5.5. Formular – erste Schritte
Das Formular, das dem Nutzer angezeigt wird, sieht wie folgt aus:
![]() |
Als View-Template dient das bereits zuvor verwendete Template [ViewModel05]. Die Aktion, die diese Ansicht anzeigt, lautet wie folgt:
// Aktion06-GET
[HttpGet]
public ViewResult Action06()
{
return View("Action06Get",new ViewModel05());
}
- Zeile 2: Die Aktion kann nur über den Befehl HTTP GET aufgerufen werden;
- Zeile 5: Die Ansicht [/First/Action06Get.cshtml] wird anhand einer Instanz vom Typ [ViewModel05] angezeigt.
Die Ansicht [/First/Action06Get.cshtml] sieht wie folgt aus:
![]() |
@model Exemple_03.Models.ViewModel05
@using Exemple_03.Models
@{
Layout = null;
}
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width" />
<title>Action06-GET</title>
</head>
<body>
<h3>Action06 - GET</h3>
<p>Choisissez une personne</p>
<form method="post" action="/First/Action06">
<select name="personneId">
@foreach (Personne2 p in Model.Personnes)
{
string selected = "";
if (p.Id == Model.SelectedId)
{
selected = "selected=\"selected\"";
}
<option value="@p.Id" @selected>@p.Prénom @p.Nom</option>
}
</select>
<input name="valider" type="submit" value="Valider" />
</form>
</body>
</html>
Die wichtigsten Neuerungen sind folgende:
- Zeile 18: Damit der Browser die vom Benutzer eingegebenen Informationen übermitteln kann, benötigen wir ein Formular. Dieses wird durch das Tag <form> in den Zeilen 18 und 31 abgegrenzt.
Das <form>-Tag HTML wurde in Abschnitt 2.5.2.1 vorgestellt. Hier noch einmal seine Eigenschaften:
Formular | |
Tag HTML | <form name="..." method="..." action="...">...</form> |
Attribute | name="frmexemple": Name des Formulars – optional method="...": Methode, die vom Browser verwendet wird, um die im Formular erfassten Werte an den Webserver zu senden action="...": URL, an die die im Formular erfassten Werte gesendet werden. Ein Webformular wird von den Tags <form>...</form> umschlossen. Das Formular kann einen Namen haben (name="xx"). Dies gilt für alle Steuerelemente, die in einem Formular vorkommen können. Der Zweck eines Formulars besteht darin, vom Benutzer über Tastatur oder Maus eingegebene Informationen zu sammeln und diese an eine URL des Webservers zu senden. An welche? An diejenige, die im Attribut action="URL" angegeben ist. Fehlt dieses Attribut, werden die Informationen an den Webserver des Dokuments gesendet, in dem sich das Formular befindet. Ein Webclient kann zwei verschiedene Methoden namens POST und GET verwenden, um Daten an einen Webserver zu senden. Das Attribut method="méthode", wobei method gleich GET oder POST ist, des Tags <form> gibt dem Browser vor, welche Methode zum Senden der im Formular erfassten Informationen an die durch das Attribut action="URL" angegebene Adresse URL verwendet werden soll. Wenn das Attribut method nicht angegeben ist, wird standardmäßig die Methode GET verwendet. |
- Zeile 18: Hier ist zu sehen, dass die Werte des Formulars über einen Befehl an die Methoden URL und [/First/Action06] gesendet werden;
- Zeile 30: Ein Formular muss eine Schaltfläche vom Typ [submit] enthalten. Diese löst das Senden der eingegebenen Werte an die durch das Attribut [action] des Tags <form> angegebene URL aus.
Was genau übermittelt der Browser, wenn der Nutzer auf die Schaltfläche [Valider] klickt? Dies wurde in Abschnitt 2.5.3.1 erläutert. Fassen wir zusammen, was dort gesagt wurde:
Steuerelement HTML | visuell | zurückgegebene(r) Wert(e) |
<input type="radio" value="Ja" name="R1"/>Ja <input type="radio" name="R1" value="Nein" checked="checked"/>Nein | R1=Ja – der Wert des Attributs value des vom Benutzer markierten Optionsfelds. | |
<input type="checkbox" name="C1" value="eins"/>1 <input type="checkbox" name="C2" value="zwei" checked="checked"/>2 <input type="checkbox" name="C3" value="drei"/>3 | C1=eins C2=zwei – Werte der Attribute value der vom Benutzer angekreuzten Kontrollkästchen | |
<input type="text" name="txtSaisie" size="20" value="ein paar Wörter"/> | txtEingabe=Web-Programmierung - vom Benutzer in das Eingabefeld eingegebener Text. Leerzeichen wurden durch das Zeichen + ersetzt | |
<input type="password" name="txtMdp" size="20" value="unMotDePasse"/> | txtMdp=diesistgeheim – vom Benutzer in das Eingabefeld eingegebener Text | |
<textarea rows="2" name="areaSaisie" cols="20"> Zeile 1 Zeile 2 Zeile 3 </textarea> | Eingabefeld=Grundlagen+der%0D%0A Webprogrammierung+ – vom Benutzer in das Eingabefeld eingegebener Text. %OD%OA ist das Zeichen für das Zeilenende. Leerzeichen wurden durch das Pluszeichen ersetzt | |
<select size="1" name="cmbValeurs"> <option value='1'>Auswahl1</option> <option selected="selected" value='2'>Auswahl 2</option> <option value='3'>Auswahl 3</option> </select> | cmbWerte=3 - Attribut [value] des vom Benutzer ausgewählten Elements | |
<select size="3" name="lst1"> <option selected="selected" value='1'>Liste1</option> <option value='2'>Liste 2</option> <option value='3'>Liste 3</option> <option value='4'>Liste 4</option> <option value='5'>Liste 5</option> </select> | ![]() | lst1=3 - Attribut [value] des vom Benutzer ausgewählten Elements |
<select size="3" name="lst2" multiple="multiple"> <option selected="selected" value='1'>Liste1</option> <option value='2'>Liste 2</option> <option selected="selected" value='3'>Liste 3</option> <option value='4'>Liste 4</option> <option value='5'>Liste 5</option> </select> | lst2=1 lst2=3 - Attribute [value] der vom Benutzer ausgewählten Elemente | |
<input type="submit" value="Senden" name="cmdRenvoyer"/> | cmdRenvoyer=Senden - Name und Attribut value der Schaltfläche, über die die Formulardaten an den Server gesendet wurden | |
<input type="hidden" name="secret" value="uneValeur"/> | secret=einWert - Attribut value des versteckten Feldes |
In unserem Formular gibt es zwei Tags, die einen Wert senden können:
<select name="personneId">
...
</select>
und
<input name="valider" type="submit" value="Valider" />
Wenn der Nutzer Person Nr. 2 auswählt, werden die Werte in folgender Form übermittelt:
Die Namen der Parameter entsprechen den Attributen [name] der Tags, auf die sich POST bezieht. Ohne dieses Attribut geben die Tags keinen Wert aus. So könnte man im obigen Beispiel das Attribut name="valider" der Schaltfläche [submit] weglassen. Der gesendete Wert ist das Attribut [value] der Schaltfläche. Diese Information ist für uns hier nicht von Interesse. Manchmal verfügen Formulare über mehrere Schaltflächen vom Typ [submit]. In diesem Fall ist es wichtig zu wissen, welche Schaltfläche angeklickt wurde. Daher wird den verschiedenen Schaltflächen das Attribut [name] zugewiesen.
Das Tag <select> besteht aus einer Folge von <option>-Tags:
<select name="personneId">
<option value="1" >Pierre Martino</option>
<option value="2" selected="selected">Pauline Pereiro</option>
<option value="3" >Jacques Alfonso</option>
</select>
Es wird der Wert des Attributs [value] der ausgewählten Option übermittelt. Fehlt dieses Attribut, wird der von der Option angezeigte Text, zum Beispiel [Pierre Martino], übermittelt.
Die Zeichenfolge
wird in die folgende Option URL [/First/Action06] geschrieben:
// Aktion06-POST
[HttpPost]
public ViewResult Action06(ActionModel06 modèle)
{
return View("Action06Post",modèle);
}
Vielleicht erinnern Sie sich, dass wir bereits eine Aktion [Action06] hatten:
// Aktion06-GET
[HttpGet]
public ViewResult Action06()
{
return View("Action06Get",new ViewModel05());
}
Es ist möglich, zwei Aktionen mit demselben Namen zu haben, sofern sie nicht dieselben Befehle verarbeiten: HTTP:
- [Action06] in Zeile 3 verarbeitet eine POST (Zeile 2);
- [Action06] in Zeile c verarbeitet eine Aktion GET (Zeile b).
Die Aktion [Action06], die das POST verwaltet, erhält die folgende Parameterkette:
Wir benötigen ein Aktionsmodell, um diese Werte zu kapseln. Dies wird das folgende Modell [ActionModel06] sein:
![]() |
using System.ComponentModel.DataAnnotations;
namespace Exemple_03.Models
{
public class ActionModel06
{
[Required(ErrorMessage = "Le paramètre [personneId] est requis")]
public int PersonneId { get; set; }
[Required(ErrorMessage = "Le paramètre [valider] est requis")]
public string Valider { get; set; }
}
}
Die Aktion [Action06] empfängt diese Vorlage und leitet sie unverändert an die folgende Ansicht [Action06Post] weiter (Zeile 5 der Aktion):
![]() |
@model Exemple_03.Models.ActionModel06
@{
Layout = null;
}
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width" />
<title>Action06Post</title>
</head>
<body>
<h3>Action06 - POST</h3>
Valeurs postées :
<ul>
<li>ID de la personne sélectionnée : @Model.PersonneId</li>
<li>Commande utilisée : @Model.Valider</li>
</ul>
</body>
</html>
Die Vorlage wird in den Zeilen 18 und 19 angezeigt.
Sehen wir uns ein Beispiel an:
![]() |
In [1] wird die dritte Person aus [Id] ausgewählt, die dem Wert 3 entspricht. In [2] wird das Formular gesendet. In [3] werden die empfangenen Werte angezeigt. In [4,5] sieht man, dass dasselbe URL aufgerufen wurde, einmal durch ein GET und [4], der andere von einem POST und einem [5]. Dies ist im URL nicht zu erkennen.
In der Ansicht, die im Anschluss an den POST angezeigt wird, möchte man möglicherweise die nom und prénom der ausgewählten Person anstelle ihrer Nummer sehen. Daher müssen die Ansicht des POST und dessen Vorlage angepasst werden.
Wir erstellen eine Aktion [Action07], um diesen Fall zu behandeln. Diese Aktion muss die Sitzung des Benutzers nutzen, um dort die Liste der Personen zu speichern. Wir orientieren uns dabei an dem in Abschnitt 4.10 behandelten Modell, das es ermöglicht, die Daten aus den Bereichen [Application] und [Session] in das Modell der Aktion einzubinden.
Das Sitzungsmodell wird die folgende Klasse [SessionModel] sein:
![]() |
namespace Exemple_03.Models
{
public class SessionModel
{
public Personne2[] Personnes { get; set; }
}
}
- Zeile 2: Die Sitzung speichert die Liste der Personen, die in der Dropdown-Liste angezeigt werden;
Wir müssen den vorherigen Typ [SessionModel] mit einem Binder verknüpfen, den wir [SessionModelBinder] nennen werden. Dieser entspricht dem auf Seite 82 beschriebenen:
![]() |
using System.Web.Mvc;
namespace Exemple_03.Infrastructure
{
public class SessionModelBinder : IModelBinder
{
public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
// Die Daten des Bereichs [Session] werden zurückgegeben
return controllerContext.HttpContext.Session["data"];
}
}
}
Die Verknüpfung zwischen dem Modell [SessionModel] und seinen Modellen binder sowie [SessionModelBinder] erfolgt in [Global.asax]:
public class MvcApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
...
// Modellbinder
ModelBinders.Binders.Add(typeof(SessionModel), new SessionModelBinder());
}
// Sitzung
public void Session_Start()
{
Session["data"] = new SessionModel();
}
}
- Zeile 8: Die Verknüpfung des Modells mit seinem Binder erfolgt in [Application_Start];
- Zeile 13: Eine Instanz vom Typ [SessionModel] wird in Verbindung mit dem Schlüssel [data] in die Sitzung aufgenommen.
Anschließend sieht die Aktion [Action07] wie folgt aus:
// Action07-GET
[HttpGet]
public ViewResult Action07(SessionModel session)
{
ViewModel05 modèleVue = new ViewModel05();
session.Personnes= modèleVue.Personnes;
return View("Action07Get", modèleVue);
}
- Zeile 3: Die Aktion ruft einen Typ [SessionModel] ab, also die Daten des Bereichs [Session], die dem Schlüssel [data] zugeordnet sind;
- Zeile 5: Die Vorlage für die Ansicht wird erstellt;
- Zeile 6: Das Personenarray wird in die Sitzung geschrieben. Es wird in der folgenden Abfrage benötigt, nämlich der mit dem Schlüssel POST. Das Protokoll HTTP ist ein zustandsloses Protokoll. Es muss eine Sitzung verwendet werden, um zwischen den Abfragen Speicherplatz zur Verfügung zu haben. Eine Sitzung ist benutzerspezifisch und wird vom Webserver verwaltet;
- Zeile 7: Die Ansicht [Action07Get.cshtml] wird angezeigt. Sie sieht wie folgt aus:
@model Exemple_03.Models.ViewModel05
@using Exemple_03.Models
...
<body>
<h3>Action07 - GET</h3>
<p>Choisissez une personne</p>
<form method="post" action="/First/Action07">
....
</form>
</body>
</html>
Sie ist identisch mit der bereits behandelten Ansicht [Action06Get.cshtml]. Der Hauptunterschied liegt in Zeile 7: der Ansicht URL, an die die Werte des Formulars gesendet werden. Diese werden von der folgenden Aktion [Action07] verarbeitet:
// Aktion07-POST
[HttpPost]
public ViewResult Action07(SessionModel session, ActionModel06 modèle)
{
Personne2 personne = session.Personnes.Where(p => p.Id == modèle.PersonneId).First<Personne2>();
string strPersonne = string.Format("{0} {1}", personne.Prénom, personne.Nom);
return View("Action07Post", (object)strPersonne);
}
- Zeile 3: Die übermittelten Werte werden in das zuvor bereits verwendete Aktionsmodell [ActionModel06] (siehe unten) eingebettet:
using System.ComponentModel.DataAnnotations;
namespace Exemple_03.Models
{
public class ActionModel06
{
[Required(ErrorMessage = "Le paramètre [personneId] est requis")]
public int PersonneId { get; set; }
[Required(ErrorMessage = "Le paramètre [valider] est requis")]
public string Valider { get; set; }
}
}
- Zeile 3: Der erste Parameter ist der Bereichswert [Session], der dem Schlüssel [data] zugeordnet ist;
- Zeile 5: Eine Abfrage mit LINQ ruft die Person mit der [Id] ab, die gepostet wurde;
- Zeile 6: Es wird die Zeichenkette erstellt, die von der Ansicht [Action07Post] (Zeile 8) angezeigt werden soll;
- Zeile 7: Um den richtigen Konstruktor [View] aufzurufen, muss der Typ [string] in [object] umtypisiert werden.
Die Ansicht [Action07Post.cshtml] sieht wie folgt aus:
@model string
@{
Layout = null;
}
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width" />
<title>Action07-Post</title>
</head>
<body>
<h3>Action07-POST</h3>
Vous avez sélectionné [@Model].
</body>
</html>
- Zeile 1: Die Vorlage hat den Typ [string];
- Zeile 16: Die Zeichenfolge wird angezeigt.
Hier ein Ausführungsbeispiel:
![]() | ![]() |
5.6. Formular – ein vollständiges Beispiel
In Abschnitt 2.5.2.1 haben wir das folgende Formular HTML behandelt:
1 ![]() |
Wir werden nun eine Aktion [Action08Get] betrachten, die dieses Formular anzeigt (GET), sowie eine Aktion [Action08Post], die die vom Benutzer eingegebenen Werte verarbeitet (POST). Ein klassisches Schema.
Die oben genannte Ansichtvorlage [1] ist eine Instanz der Klasse [ViewModel08]. Diese Klasse ist gleichzeitig:
- das Modell der Ansicht, die von einem GET für die Aktion [Action08Get] erzeugt wird;
- das Modell der Aktion [Action08Post] für eine Anfrage POST.
![]() |
![]() |
5.6.1. Die Bereichsvorlage [Application]
Wir gehen davon aus, dass die von den Optionsfeldern, Kontrollkästchen und verschiedenen Listen angezeigten Elemente Daten des Bereichs [Application] sind. Ein häufiger Fall. Diese Informationen stammen aus einer Konfigurationsdatei oder einer Datenbank, die beim Start der Anwendung in der Methode [Application_Start] von [Global.asax] ausgewertet werden. Diese Methode verläuft wie folgt:
protected void Application_Start()
{
....
// Modellbinder
ModelBinders.Binders.Add(typeof(SessionModel), new SessionModelBinder());
ModelBinders.Binders.Add(typeof(ApplicationModel), new ApplicationModelBinder());
// Scope-Daten [Application]
Application["data"] = new ApplicationModel();
}
- Zeile 7: Der Typ [ApplicationModel], den wir gleich beschreiben werden, ist mit dem Datenbinder [ApplicationModelBinder] verknüpft, den wir bereits auf Seite 82 vorgestellt haben;
- Zeile 10: Eine Instanz des Typs [ApplicationModel] wird im Anwendungswörterbuch unter dem Schlüssel [data] registriert.
Die Klasse [ApplicationModel] dient dazu, alle Daten des Bereichs [Application] zu kapseln. Hier kapselt sie die Daten, die das Formular anzeigen soll:
![]() |
namespace Exemple_03.Models
{
public class ApplicationModel
{
// im Formular anzuzeigende Sammlungen
public Item[] RadioButtonFieldItems { get; set; }
public Item[] CheckBoxesFieldItems { get; set; }
public Item[] DropDownListFieldItems { get; set; }
public Item[] SimpleChoiceListFieldItems { get; set; }
public Item[] MultipleChoiceListFieldItems { get; set; }
// Initialisierung der Felder und Sammlungen
public ApplicationModel()
{
RadioButtonFieldItems = new Item[]{
new Item {Value="1",Label="oui"},
new Item {Value="2", Label="non"}
};
CheckBoxesFieldItems = new Item[]{
new Item {Value="1",Label="1"},
new Item {Value="2", Label="2"},
new Item {Value="3", Label="3"}
};
DropDownListFieldItems = new Item[]{
new Item {Value="1",Label="choix1"},
new Item {Value="2", Label="choix2"},
new Item {Value="3", Label="choix3"}
};
SimpleChoiceListFieldItems = new Item[]{
new Item {Value="1",Label="liste1"},
new Item {Value="2", Label="liste2"},
new Item {Value="3", Label="liste3"},
new Item {Value="4", Label="liste4"},
new Item {Value="5", Label="liste5"}
};
MultipleChoiceListFieldItems = new Item[]{
new Item {Value="1",Label="liste1"},
new Item {Value="2", Label="liste2"},
new Item {Value="3", Label="liste3"},
new Item {Value="4", Label="liste4"},
new Item {Value="5", Label="liste5"}
};
}
// das Element der Sammlungen
public class Item
{
public string Label { get; set; }
public string Value { get; set; }
}
}
}
- Zeilen 45–49: das Element der verschiedenen Sammlungen des Formulars. [Label] ist der vom Formularelement angezeigte Text, [Value] der Wert, der von diesem Element gesendet wird, wenn es ausgewählt wird;
- Zeile 6: Die vom Optionsfeld angezeigte Auswahl;
- Zeile 7: die von den Kontrollkästchen angezeigte Sammlung;
- Zeile 8: die von der Dropdown-Liste angezeigte Auswahl;
- Zeile 9: die von der Einfachauswahlliste angezeigte Sammlung;
- Zeile 10: die durch die Mehrfachauswahlliste angezeigte Sammlung;
- Zeilen 13–43: Diese Sammlungen werden vom Konstruktor ohne Parameter der Klasse initialisiert.
Die verschiedenen Sammlungen werden in das folgende Formular übernommen:
![]() |
5.6.2. Das Modell der Aktion [Action08Get]
Das vorstehende Formular wird durch die folgende Aktion [Action08Get] angezeigt:
// Action08-GET
[HttpGet]
public ViewResult Action08Get(ApplicationModel application)
{
ViewBag.info = string.Format("Contrôleur={0}, Action={1}", RouteData.Values["controller"], RouteData.Values["action"]);
return View("Formulaire", new ViewModel08(application));
}
- Zeile 2: [Action08Get] reagiert nur auf einen Befehl [GET];
- Zeile 3: Sie erhält als Parameter das soeben beschriebene Anwendungsmodell;
- Zeile 5: Sie initialisiert eine Information im dynamischen Container [ViewBag];
- Zeile 6: Sie zeigt die Ansicht [/First/Formulaire.cshtml] mit dem Modell [ViewModel08] an. Bei diesem Modell handelt es sich um das zuvor vorgestellte Formular. Dazu übergeben wir dem Konstruktor das Anwendungsmodell, das die anzuzeigenden Elemente definiert.
5.6.3. Das Modell der Ansicht [Formulaire]
Die Klasse [ViewModel08] dient als Vorlage für das Formular. Diese Klasse sieht wie folgt aus:
using System.ComponentModel.DataAnnotations;
using System.Web.Mvc;
using Exemple_03.Models;
namespace Exemple_03.Models
{
public class ViewModel08
{
// die Eingabefelder
public string RadioButtonField { get; set; }
public string[] CheckBoxesField { get; set; }
public string TextField { get; set; }
public string PasswordField { get; set; }
public string TextAreaField { get; set; }
public string DropDownListField { get; set; }
public string SimpleChoiceListField { get; set; }
public string[] MultipleChoiceListField { get; set; }
// Die im Formular anzuzeigenden Sammlungen
public ApplicationModel.Item[] RadioButtonFieldItems { get; set; }
public ApplicationModel.Item[] CheckBoxesFieldItems { get; set; }
public ApplicationModel.Item[] DropDownListFieldItems { get; set; }
public ApplicationModel.Item[] SimpleChoiceListFieldItems { get; set; }
public ApplicationModel.Item[] MultipleChoiceListFieldItems { get; set; }
// Konstruktoren
public ViewModel08()
{
}
public ViewModel08(ApplicationModel application)
{
// Initialisierung der Sammlungen
RadioButtonFieldItems = application.RadioButtonFieldItems;
CheckBoxesFieldItems = application.CheckBoxesFieldItems;
DropDownListFieldItems = application.DropDownListFieldItems;
SimpleChoiceListFieldItems = application.SimpleChoiceListFieldItems;
MultipleChoiceListFieldItems = application.MultipleChoiceListFieldItems;
// Initialisierung der Felder
RadioButtonField = "2";
CheckBoxesField = new string[] { "2" };
TextField = "quelques mots";
PasswordField = "secret";
TextAreaField = "ligne1\nligne2";
DropDownListField = "2";
SimpleChoiceListField = "3";
MultipleChoiceListField = new string[] { "1", "3" };
}
}
}
- In einem Formular gibt es zwei Arten von Elementen: diejenigen, die angezeigt werden, und diejenigen, die zur Eingabe dienen;
- Die Zeilen 20–24 definieren die anzuzeigenden Elemente. Dabei handelt es sich um die verschiedenen Sammlungen des Formulars. Diese finden sich in der Vorlage der Anwendung (Zeilen 34–38);
- Zeilen 10–17: definieren die Eingabefelder des Formulars;
- Zeile 10: [RadioButtonField] ruft den Wert ab, der in den folgenden Zeilen des Formulars übermittelt wird:
<!-- Optionsfelder -->
<tr>
<td>Etes-vous marié(e)</td>
<td>
<input type="radio" name="RadioButtonField" value="1" />oui
<input type="radio" name="RadioButtonField" value="2" checked="checked"/>non
</td>
</tr>
Beachten Sie in den Zeilen 5 und 6, dass das Attribut [name] der beiden Optionsfelder der Name der Eigenschaft ist, die initialisiert wird. In den übermittelten Daten findet sich eine Zeichenfolge der Form:
param1=val1&RadioButtonField=2¶m2=val2
, wenn der Benutzer die Option mit der Bezeichnung [non] ausgewählt hat. Tatsächlich wird das Attribut [value] der ausgewählten Option übermittelt.
- Zeile 11: [CheckBoxesField] ruft die Werte ab, die in den folgenden Zeilen des Formulars übermittelt wurden:
<!-- die Kontrollkästchen -->
<tr>
<td>Cases à cocher</td>
<td>
<input type="checkbox" name="CheckBoxesField" value="1" />1
<input type="checkbox" name="CheckBoxesField" value="2" checked="checked"/>2
<input type="checkbox" name="CheckBoxesField" value="3" />3
</td>
Beachten Sie in den Zeilen 5 und 6, dass das Attribut [name] der Kontrollkästchen der Name der Eigenschaft ist, die initialisiert wird. In den übermittelten Daten findet sich eine Zeichenfolge der Form:
param1=val1&CheckBoxesField=2&CheckBoxesField=3¶m2=val2
, wenn der Benutzer die Kontrollkästchen mit den Bezeichnungen [2] und [3] aktiviert hat. Es wird das Attribut [value] der aktivierten Optionen übermittelt. Da mehrere Parameter mit demselben Namen gesendet werden können, ist [CheckBoxesField] ein Wertearray und kein einzelner Wert. Wenn kein Kontrollkästchen aktiviert ist, fehlt der Parameter [CheckBoxesField] in der übermittelten Zeichenfolge, und die gleichnamige Eigenschaft des Modells wird nicht initialisiert. Dies kann, wie wir noch sehen werden, zu Problemen führen.
- Zeile 12: [TextField] ruft den Wert ab, der in den folgenden Zeilen des Formulars übermittelt wird:
<!-- einzeiliges Texteingabefeld -->
<tr>
<td>Champ de saisie</td>
<td>
<input type="text" name="TextField" value="quelques mots" size="30" />
</td>
</tr>
In Zeile 5 ist das Attribut [name] des Eingabefelds der Name der Eigenschaft, die initialisiert wird. In den übermittelten Daten findet sich eine Zeichenfolge der Form:
param1=val1&TextField=abcdef¶m2=val2
wenn der Benutzer „[abcdef]“ in das Eingabefeld eingegeben hat.
- Zeile 13: [PasswordField] ruft den Wert ab, der in den folgenden Zeilen des Formulars übermittelt wurde:
<!-- das Passwort-Eingabefeld -->
<tr>
<td>Mot de passe</td>
<td>
<input type="password" name="PasswordField" value="secret" size="30" />
</td>
</tr>
Zeile 5: Das Attribut [name] des Eingabefelds ist der Name der Eigenschaft, die initialisiert wird. In den übermittelten Daten findet sich eine Zeichenfolge der Form:
param1=val1&PasswordField=abcdef¶m2=val2
, wenn der Benutzer „[abcdef]“ in das Eingabefeld eingegeben hat.
- Zeile 14: [TextAreaField] ruft den Wert ab, der in den folgenden Zeilen des Formulars übermittelt wurde:
<!-- das mehrzeilige Texteingabefeld -->
<tr>
<td>Boîte de saisie</td>
<td>
<textarea name="TextAreaField" cols="40" rows="3">ligne1
ligne2</textarea>
</td>
</tr>
Zeile 5: Das Attribut [name] des Eingabefelds ist der Name der Eigenschaft, die initialisiert wird. In den übermittelten Daten findet sich eine Zeichenfolge der Form:
param1=val1&TextAreaField=abcdef%0D%OAhijk¶m2=val2
, wenn der Benutzer im Eingabefeld „[abcdef]“ gefolgt von einem Zeilenumbruch und „[ijk]“ eingegeben hat.
- Zeile 15: [DropDownListField] ruft den Wert ab, der in den folgenden Zeilen des Formulars übermittelt wurde:
<!-- die Dropdown-Liste -->
<tr>
<td>Liste déroulante</td>
<td>
<select name="DropDownListField">
<option value="1" >choix1</option>
<option value="2" selected="selected">choix2</option>
<option value="3" >choix3</option>
</select>
</tr>
Zeile 5: Das Attribut [name] des Tags <select> ist der Name der Eigenschaft, die initialisiert wird. In den übermittelten Daten findet sich eine Zeichenfolge der Form:
param1=val1&DropDownListField=1¶m2=val2
, wenn der Benutzer die Option [choix1] ausgewählt hat. Es wird das Attribut [value] der ausgewählten Option übermittelt.
- Zeile 16: [SingleChoiceListField] ruft den Wert ab, der in den folgenden Zeilen des Formulars übermittelt wurde:
<!-- die Auswahlliste mit einer Auswahlmöglichkeit -->
<tr>
<td>Liste à choix unique</td>
<td>
<select name="SimpleChoiceListField" size="3">
<option value="1" >liste1</option>
<option value="2" >liste2</option>
<option value="3" selected="selected">liste3</option>
<option value="4" >liste4</option>
<option value="5" >liste5</option>
</select>
</tr>
Zeile 5: Das Attribut [name] des Tags <select> ist der Name der Eigenschaft, die initialisiert wird. Das Attribut [size="3"] sorgt dafür, dass keine Dropdown-Liste angezeigt wird. In den übermittelten Daten findet sich eine Zeichenfolge der Form:
param1=val1&SimpleChoiceListField=3¶m2=val2
, wenn der Benutzer die Option [liste3] ausgewählt hat. Es wird das Attribut [value] der ausgewählten Option übermittelt. Der Parameter [SingleChoiceListField] kann in der übermittelten Zeichenkette fehlen, wenn kein Element ausgewählt wurde.
- Zeile 17: [MultipleChoiceListField] ruft die Werte ab, die von den folgenden Zeilen des Formulars übermittelt wurden:
<!-- die Multiple-Choice-Liste -->
<tr>
<td>Liste à choix multiple</td>
<td>
<select name="MultipleChoiceListField" size="3" multiple="multiple">
<option value="1" selected="selected">liste1</option>
<option value="2" >liste2</option>
<option value="3" selected="selected">liste3</option>
<option value="4" >liste4</option>
<option value="5" >liste5</option>
</select>
</tr>
Zeile 5: Das Attribut [name] des Tags <select> ist der Name der Eigenschaft, die initialisiert wird. Das Attribut [size="3"] sorgt dafür, dass keine Dropdown-Liste angezeigt wird, und das Attribut [multiple] ermöglicht es dem Benutzer, mehrere Elemente auszuwählen, indem er die Taste [Ctrl] gedrückt hält. In den übermittelten Daten findet sich eine Zeichenfolge der folgenden Form:
param1=val1&MultipleChoiceListField=1&MultipleChoiceListField=3¶m2=val2
, wenn der Benutzer die Optionen [liste1] und [liste3] ausgewählt hat. Es wird das Attribut [value] der ausgewählten Optionen übermittelt. Da mehrere Parameter mit demselben Namen gesendet werden können, ist [MultipleChoiceListField] ein Wertearray und kein einzelner Wert. Wenn kein Kontrollkästchen aktiviert ist, fehlt der Parameter [MultipleChoiceListField] in der gesendeten Zeichenfolge, und die gleichnamige Eigenschaft des Modells wird nicht initialisiert.
Die zuvor vorgestellten Eingabefelder erhalten die vom Formular übermittelten Werte. Man kann sie auch vor dem Absenden des Formulars initialisieren. Dies wurde hier wie folgt umgesetzt:
// Felder initialisieren
RadioButtonField = "2";
CheckBoxesField = new string[] { "2" };
TextField = "quelques mots";
PasswordField = "secret";
TextAreaField = "ligne1\nligne2";
DropDownListField = "2";
SimpleChoiceListField = "3";
MultipleChoiceListField = new string[] { "1", "3" };
Wären diese Werte nach dem Absenden des Formulars mit dem Code POST ermittelt worden, würde dies bedeuten, dass der Benutzer:
- Zeile 2: die Option [non] des Optionsfelds ausgewählt;
- Zeile 3: die Option „[2]“ bei den Kontrollkästchen markiert;
- Zeile 4: „[quelques mots]“ in das Eingabefeld eingegeben;
- Zeile 5: „[secret]“ als Passwort eingegeben;
- Zeile 6: [ligne1\nligne2] in das mehrzeilige Eingabefeld eingegeben;
- Zeile 7: Wählen Sie die Option „[choix2]“ aus der Dropdown-Liste aus;
- Zeile 8: Die Option „[liste3]“ aus der Einfachauswahlliste ausgewählt;
- Zeile 9: Die Optionen „[liste1]“ und „[liste3]“ aus der Mehrfachauswahlliste ausgewählt;
Wir gehen davon aus, dass ein POST stattgefunden hat und dass das Formular so zurückgesendet werden soll, wie es eingegeben wurde. Dies geschieht insbesondere dann, wenn ein fehlerhaftes Formular an den Benutzer zurückgesendet wird. Dieses wird so zurückgesendet, wie es eingegeben wurde.
5.6.4. Die Ansicht [Formulaire]
Die Ansicht [/First/Formulaire.cshtml] zeigt das Formular an:
![]() |
@model Exemple_03.Models.ViewModel08
@using Exemple_03.Models
@{
Layout = null;
}
<html>
<head>
<meta name="viewport" content="width=device-width" />
<title>Formulaire</title>
</head>
<body>
<form method="post" action="Action08Post">
<h2>Formulaire ASP.NET MVC</h2>
<h3>Affiché par : @ViewBag.info</h3>
<table>
<thead></thead>
<tbody>
<!-- Optionsfelder -->
<tr>
<td>Etes-vous marié(e)</td>
<td>
@foreach (ApplicationModel.Item item in @Model.RadioButtonFieldItems)
{
string strChecked = item.Value == @Model.RadioButtonField ? "checked=\"checked\"" : "";
<input type="radio" name="RadioButtonField" value="@item.Value" @strChecked/>@item.Label
<text/>
}
</td>
</tr>
...
</tbody>
</table>
<input type="submit" value="Valider" />
</form>
</body>
</html>
- Zeile 1: [ViewModel08] ist die Vorlage des Formulars;
- Zeile 12: das Tag <form> des Formulars. Dieses wird mit der Methode [POST] (Attribut method) an die URL [/First/Action08Post] (Attribut action);
- Zeile 33: die Schaltfläche vom Typ [submit], die zum Absenden des Formulars dient;
- Zeilen 22–27: zeigen die Optionsfelder an:
- Zeile 22: Man durchläuft die durch das Optionsfeld angezeigte Sammlung;
- Zeile 24: Die Schaltfläche, deren Attribut [value] den Wert der Eigenschaft [RadioButtonField] enthält, muss ausgewählt sein. Dazu muss sie das Attribut [checked="checked"] haben;
- Zeile 25: Generierung des Tags <input type="radio"> mit dem Wert [@item.Value] und der Beschriftung [@item.Label];
- Zeile 26: Das Tag <text/> ist kein anerkanntes HTML-Tag. Es ist für [Razor] vorgesehen. Bei dessen Auftreten generiert [Razor] einen Zeilenumbruch. Dies hat keine Auswirkungen auf das angezeigte Formular, wohl aber auf den generierten Code HTML. Die Tags <input type="radio"> befinden sich dann auf zwei verschiedenen Zeilen, anstatt auf derselben Zeile zu stehen. Dies macht den Code lesbarer, wenn man im Browser den Quellcode der angezeigten Seite anzeigt;
Wir gehen nun die anderen Elemente der Ansicht durch:
<!-- Kontrollkästchen -->
<tr>
<td>Cases à cocher</td>
<td>
@{
foreach (ApplicationModel.Item item in @Model.CheckBoxesFieldItems)
{
string strChecked = @Model.CheckBoxesField.Contains(item.Value) ? "checked=\"checked\"" : "";
<input type="checkbox" name="CheckBoxesField" value="@item.Value" @strChecked/>@item.Label
<text/>
}
}
</td>
- Zeile 6: Wir durchlaufen die Sammlung, die durch die Kontrollkästchen angezeigt wird;
- Zeile 8: Ein Feld, dessen Attribut [value] einen der Werte der Eigenschaft [CheckBoxesField] annimmt, muss angekreuzt sein. Dazu muss es das Attribut [checked="checked"] aufweisen. Es wird ein Ausdruck LINQ verwendet, mit dem festgestellt werden kann, ob ein Wert in einem Array enthalten ist;
- Zeile 25: Generierung des Tags <input type="checkbox"> mit dem Wert [@item.Value] und der Beschriftung [@item.Label];
<!-- das einzeilige Texteingabefeld -->
<tr>
<td>Champ de saisie</td>
<td>
<input type="text" name="TextField" value="@Model.TextField" size="30" />
</td>
</tr>
<!-- das Passwortfeld -->
<tr>
<td>Mot de passe</td>
<td>
<input type="password" name="PasswordField" value="@Model.PasswordField" size="30" />
</td>
</tr>
<!-- das mehrzeilige Texteingabefeld -->
<tr>
<td>Boîte de saisie</td>
<td>
<textarea name="TextAreaField" cols="40" rows="3">@Model.TextAreaField</textarea>
</td>
</tr>
- Zeilen 5, 12: Dem Attribut [value] des Tags wird der Wert aus der Vorlage zugewiesen;
- Zeile 19: ebenso, jedoch mit einer anderen Syntax.
<!-- die Dropdown-Liste -->
<tr>
<td>Liste déroulante</td>
<td>
<select name="DropDownListField">
@{
foreach (ApplicationModel.Item item in @Model.DropDownListFieldItems)
{
string strChecked = item.Value == @Model.DropDownListField ? "selected=\"selected\"" : "";
<option value="@item.Value" @strChecked>@item.Label</option>
}
}
</select>
</tr>
- Zeile 7: Die durch die Dropdown-Liste angezeigte Sammlung wird durchlaufen;
- Zeile 9: Eine Option, deren Attribut [value] den Wert der Eigenschaft [DropDownListField] hat, muss dann ausgewählt werden. Dazu muss sie das Attribut [selected="selected"] haben;
- Zeile 25: Generierung des Tags <option value="valeur">libellé</option> mit dem Wert [@item.Value] und der Bezeichnung [@item.Label];
<!-- die Einfachauswahlliste -->
<tr>
<td>Liste à choix unique</td>
<td>
<select name="SimpleChoiceListField" size="3">
@{
foreach (ApplicationModel.Item item in @Model.SimpleChoiceListFieldItems)
{
string strChecked = item.Value == @Model.SimpleChoiceListField ? "selected=\"selected\"" : "";
<option value="@item.Value" @strChecked>@item.Label</option>
}
}
</select>
</tr>
Die Erklärung ist dieselbe wie für die Dropdown-Liste.
<!-- die Mehrfachauswahlliste -->
<tr>
<td>Liste à choix multiple</td>
<td>
<select name="MultipleChoiceListField" size="3" multiple="multiple">
@{
foreach (ApplicationModel.Item item in @Model.MultipleChoiceListFieldItems)
{
string strChecked = @Model.MultipleChoiceListField.Contains(item.Value) ? "selected=\"selected\"" : "";
<option value="@item.Value" @strChecked>@item.Label</option>
}
}
</select>
</tr>
- Zeile 7: Die von der Liste angezeigte Sammlung wird durchlaufen;
- Zeile 9: Es muss eine Option ausgewählt werden, deren Attribut [value] einen der Werte der Eigenschaft [MultipleChoiceListField] annimmt. Dazu muss sie das Attribut [selected="selected"] aufweisen. Es wird ein Ausdruck LINQ verwendet, mit dem festgestellt werden kann, ob ein Wert in einem Array enthalten ist;
- Zeile 10: Generierung des Tags libellé/option mit dem Wert [@item.Value] und der Bezeichnung [@item.Label];
5.6.5. Verarbeitung des POST des Formulars
Wir haben gesehen, dass das Formular an die Aktion [Action08Post] übermittelt wird:
<form method="post" action="Action08Post">
Die Aktion [Action08Post] lautet wie folgt:
// Aktion08-POST
[HttpPost]
public ViewResult Action08Post(ApplicationModel application, FormCollection posted)
{
ViewBag.info = string.Format("Contrôleur={0}, Action={1}", RouteData.Values["controller"], RouteData.Values["action"]);
ViewModel08 modèle = new ViewModel08(application);
TryUpdateModel(modèle,posted);
return View("Formulaire", modèle);
}
- Zeile 3: Die Anwendungsvorlage wird als Parameter übergeben, ebenso wie die übermittelten Werte. Diese stehen in einem Typ [FormCollection] zur Verfügung. Der Wert des übermittelten Parameters [RadioButtonField] wird durch den Ausdruck posted[" RadioButtonField"] ermittelt. Das Ergebnis ist entweder eine Zeichenkette oder der Zeiger null. Wenn man posted[" CheckBoxesField"] schreibt, erhält man ein Array von Zeichenketten oder den Zeiger null;
- warum also nicht schreiben:
public ViewResult Action08Post(ApplicationModel application, ViewModel08 posted)
Dafür gibt es zwei Gründe:
- Erstens wird das Framework das Modell „[ViewModel08]“ mit dem Konstruktor ohne Parameter instanziieren, was dazu führt, dass die Sammlungen des Modells nicht initialisiert werden;
- Der zweite ist, dass wir kontrollieren wollen, was in das Modell gelangt. Wir wissen, dass es vier mögliche Quellen für das Modell gibt: die Parameter eines GET, eines POST, der verwendeten Route und die einer Datei uploadé. Hier soll das Modell ausschließlich mit den übermittelten Werten initialisiert werden.
- Zeile 6: Das Modell wird mit dem richtigen Konstruktor instanziiert;
- Zeile 7: Wir initialisieren es mit den übermittelten Werten. Nach diesem Vorgang entspricht das Modell der vom Benutzer vorgenommenen Eingabe;
- Zeile 8: Das Formular wird erneut angezeigt. Der Benutzer sieht es so, wie er es eingegeben hat.
Sehen wir uns ein Beispiel an:
![]() |
In [2] spiegelt das Ergebnis von [POST] genau die Eingaben aus [1] wider.
5.6.6. Behandlung von Anomalien bei POST
Wir haben bereits erwähnt, dass, wenn für die Felder in [CheckBoxesField, SimpleChoiceListField, MultipleChoiceListField] kein Wert angekreuzt oder ausgewählt wurde, die entsprechenden Parameter nicht Teil der gesendeten Zeichenfolge waren und daher die gleichnamigen Eigenschaften des Modells nicht initialisiert wurden.
Betrachten wir das folgende Beispiel:
![]() |
- In [1] wurde kein Kontrollkästchen markiert;
- bei [2] gibt [POST] ein angekreuztes Kontrollkästchen zurück.
Die Erklärung lautet wie folgt:
- Da kein Kontrollkästchen markiert ist, gehört der Parameter [CheckBoxesField] nicht zu den übermittelten Werten;
- Die Aktion [Action08Post] verläuft wie folgt:
[HttpPost]
public ViewResult Action08Post(ApplicationModel application, FormCollection posted)
{
ViewBag.info = ...
ViewModel08 modèle = new ViewModel08(application);
TryUpdateModel(modèle,posted);
return View("Formulaire", modèle);
}
- Zeile 5: Die Formularvorlage wird instanziiert. Der verwendete Konstruktor weist jedoch dem Feld [CheckBoxesField] das Array ["2"] zu;
- Zeile 6: Die übermittelten Werte werden im Formular gespeichert. Da der Parameter [CheckBoxesField] nicht zu den übermittelten Werten gehört, wird die gleichnamige Eigenschaft nicht zugewiesen. Sie behält daher ihren Wert ["2"] bei, was dazu führt, dass bei der Anzeige das Kontrollkästchen Nr. 2 markiert ist, obwohl dies nicht der Fall sein sollte.
Dieses Problem lässt sich auf verschiedene Weise beheben. Wir entscheiden uns dafür, es im Code der Aktion [Action08Post] zu beheben:
// Aktion08-POST
[HttpPost]
public ViewResult Action08Post(ApplicationModel application, FormCollection posted)
{
ViewBag.info = string.Format("Contrôleur={0}, Action={1}", RouteData.Values["controller"], RouteData.Values["action"]);
ViewModel08 modèle = new ViewModel08(application);
TryUpdateModel(modèle,posted);
// Verarbeitung nicht gebuchter Werte
if (posted["CheckBoxesField"] == null)
{
modèle.CheckBoxesField = new string[] { };
}
if (posted["SimpleChoiceListField"] == null)
{
modèle.SimpleChoiceListField = "";
}
if (posted["MultipleChoiceListField"] == null)
{
modèle.MultipleChoiceListField = new string[] { };
}
// Formularanzeige
return View("Formulaire", modèle);
}
- Zeilen 9–20: Es wird geprüft, ob bestimmte Parameter übermittelt wurden oder nicht. Ist dies nicht der Fall, werden sie mit dem Wert initialisiert, der dem Fehlen einer Benutzereingabe entspricht. Die Prüfung wurde nicht für die Dropdown-Liste durchgeführt, bei der immer ein Element ausgewählt ist, was bei den anderen Listen nicht der Fall ist.
Der Leser ist eingeladen, diese neue Version zu testen.
5.7. Verwendung spezieller Methoden zur Formularerstellung
5.7.1. Das neue Formular
Wir erstellen ein neues Formular [Formulaire2.cshtml], das ein mit dem vorherigen identisches Formular ausgibt:
![]() |
Werfen wir noch einmal einen Blick auf den Code, der zur Erstellung der Dropdown-Liste im Formular verwendet wurde:
<!-- Die Dropdown-Liste -->
<tr>
<td>Liste déroulante</td>
<td>
<select name="DropDownListField">
@{
foreach (ApplicationModel.Item item in @Model.DropDownListFieldItems)
{
string strChecked = item.Value == @Model.DropDownListField ? "selected=\"selected\"" : "";
<option value="@item.Value" @strChecked>@item.Label</option>
}
}
</select>
</tr>
Dieser Code hat zwei Nachteile:
- Der wichtigste ist, dass man aufgrund der Komplexität des Codes den Blick für die Art der Komponente – in diesem Fall eine Dropdown-Liste – verliert;
- Zeile 5: Wenn man sich beim Namen der Modelleigenschaft, die als Attribut „[name]“ verwendet werden soll, vertut, wird man dies erst bei der Ausführung bemerken.
ASP.NET MVC bietet spezielle Methoden namens [HTML Helpers], die, wie ihr Name schon sagt, die Generierung von HTML erleichtern sollen, insbesondere für Formulare. Mit diesen Klassen lässt sich die zuvor genannte Dropdown-Liste „ “ wie folgt schreiben:
<!-- die Dropdown-Liste -->
<tr>
<td>Liste déroulante</td>
<td>@Html.DropDownListFor(m => m.DropDownListField,
new SelectList(@Model.DropDownListFieldItems, "Value", "Label"))
</td>
</tr>
Die Dropdown-Liste wird durch die Zeilen 4–5 generiert. Der Code ist deutlich weniger komplex. Der für die Dropdown-Liste generierte HTML-Code lautet wie folgt:
<!-- die Dropdown-Liste -->
<tr>
<td>Liste déroulante</td>
<td><select id="DropDownListField" name="DropDownListField"><option value="1">choix1</option>
<option selected="selected" value="2">choix2</option>
<option value="3">choix3</option>
</select></td>
</tr>
- Zeile 4: Das Attribut [name] ist korrekt;
- Zeilen 4–6: Die Optionen wurden korrekt generiert und die richtige Option wurde ausgewählt.
Kehren wir zu dem Code zurück, der diese Zeilen HTML generiert hat:
@Html.DropDownListFor(m => m.DropDownListField, new SelectList(@Model.DropDownListFieldItems, "Value", "Label"))
- Der erste Parameter ist eine Funktion namens lambda, wobei m das Modell der Ansicht darstellt und m.DropDowListField eine Eigenschaft dieses Modells ist. Der Codegenerator HTML verwendet den Namen dieser Eigenschaft, um die Attribute [id] und [name] des zu generierenden [select] zu generieren. Wird eine nicht vorhandene Eigenschaft verwendet, tritt ein Fehler bereits bei der Kompilierung und nicht erst zur Laufzeit auf. Dies ist eine Verbesserung gegenüber der vorherigen Lösung, bei der Fehler bei der Benennung erst zur Laufzeit erkannt wurden;
- der zweite Parameter dient dazu, die Sammlung von Elementen anzugeben, die die Dropdown-Liste füllen soll. Mit der Klasse [SelectList] lässt sich diese Sammlung erstellen:
- Ihr erster Parameter ist eine beliebige Sammlung von Elementen. Hier handelt es sich um eine Sammlung vom Typ [Item];
- ihr zweiter Parameter ist die Eigenschaft der Elemente, die den Wert des Tags <option> liefert. Hier ist es die Eigenschaft [Value] der Klasse [Item];
- ihr dritter Parameter ist die Eigenschaft der Elemente, die die Bezeichnung des Tags <option> liefert. Hier ist es die Eigenschaft [Label] der Klasse [Item];
- Um herauszufinden, welche Option ausgewählt werden muss (Attribut selected), geht das Framework genauso vor wie wir: Es vergleicht den Wert der Option mit dem aktuellen Wert der Eigenschaft [DropDownListField].
Sehen wir uns nun die anderen Methoden an, die wir verwenden können:
Optionsfelder
Der neue Code lautet wie folgt:
<!-- die Optionsfelder -->
<tr>
<td>Etes-vous marié(e)</td>
<td>
@{
foreach (ApplicationModel.Item item in @Model.RadioButtonFieldItems)
{
@Html.RadioButtonFor(m => m.RadioButtonField, @item.Value)@item.Label
<text/>
}
}
</td>
</tr>
Der generierte Code HTML lautet wie folgt:
<!-- Optionsfelder -->
<tr>
<td>Etes-vous marié(e)</td>
<td>
<input id="RadioButtonField" name="RadioButtonField" type="radio" value="1" />oui
<input checked="checked" id="RadioButtonField" name="RadioButtonField" type="radio" value="2" />non
</td>
</tr>
Die verwendete Methode lautet [Html.RadioButtonFor]:
- Der erste Parameter ist die Eigenschaft des Modells, die dem Optionsfeld zugeordnet werden soll (Attribut [name]);
- der zweite Parameter ist der Wert, der dem Optionsfeld zugewiesen werden soll (Attribut [value]).
Kontrollkästchen
Der Code sieht nun wie folgt aus:
<!-- die Kontrollkästchen -->
<tr>
<td>Cases à cocher</td>
<td>
@{
@Html.CheckBoxFor(m=>m.CheckBoxField1) @Model.CheckBoxesFieldItems[0].Label
@Html.CheckBoxFor(m=>m.CheckBoxField2) @Model.CheckBoxesFieldItems[1].Label
@Html.CheckBoxFor(m=>m.CheckBoxField3) @Model.CheckBoxesFieldItems[2].Label
}
</td>
Die Methode zur Generierung von Kontrollkästchen lautet [Html.CheckBoxFor]:
Der Parameter ist die boolesche Eigenschaft des Modells, die dem Kontrollkästchen zugeordnet wird. Bei [Propriété=true] ist das Kontrollkästchen aktiviert. Bei [Propriété=false] ist das Kontrollkästchen deaktiviert. In jedem Fall hat das Attribut [value] den Wert true. Der generierte Code HTML lautet wie folgt:
<input id="Propriété" name="Propriété" type="checkbox" value="true" />
<input name="Propriété" type="hidden" value="false" />
- Zeile 1: das Kontrollkästchen mit dem Attribut [value="true"];
- Zeile 2: ein verstecktes Feld (type=hidden) mit demselben Namen [Propriété] wie das Kontrollkästchen mit dem Attribut [value="false"]. Warum gibt es zwei Tags mit dem gleichen Namen [input]? Es gibt zwei Fälle:
- Das Kontrollkästchen in Zeile 1 ist aktiviert. Dann lautet die gesendete Parameterzeichenfolge „Eigenschaft=true&Eigenschaft=false“ (Zeilen 1 und 2). Da die Eigenschaft [Propriété] nur einen Wert erwartet, könnte man annehmen, dass das Framework den Wert [true] der Eigenschaft [Propriété] zuweist. Dazu müsste es lediglich eine logische Verknüpfung zwischen den empfangenen Werten herstellen;
- Das Kontrollkästchen in Zeile 1 ist nicht aktiviert. Daher lautet die übermittelte Parameterzeichenfolge „Eigenschaft=false“ (nur Zeile 2), und somit erhält die Eigenschaft [Propriété] den Wert [false], was korrekt ist (das Kontrollkästchen wurde nicht aktiviert).
Einzeiliges Eingabefeld
Der neue Code lautet wie folgt:
<!-- das einzeilige Texteingabefeld -->
<tr>
<td>Champ de saisie</td>
<td>
@Html.TextBoxFor(m => m.TextField, new { size = "30" })
</td>
</tr>
Der generierte Code HTML lautet wie folgt:
<!-- das einzeilige Texteingabefeld -->
<tr>
<td>Champ de saisie</td>
<td>
<input id="TextField" name="TextField" size="30" type="text" value="quelques mots" />
</td>
</tr>
Die verwendete Methode lautet wie folgt:
@Html.TextBoxFor(m => m.TextField, new { size = "30" })
- Der erste Parameter gibt die Eigenschaft des Modells an, das dem Eingabefeld zugeordnet ist. Der Name der Eigenschaft wird in den Attributen [name] und [id] des generierten Tags <input> verwendet, und sein Wert wird dem Attribut [value] zugewiesen;
- Der zweite Parameter ist eine anonyme Klasse, die bestimmte Attribute des generierten Tags HTML festlegt, in diesem Fall das Attribut [size].
Eingabefeld für ein Passwort
Der neue Code lautet wie folgt:
<!-- das Passwort-Eingabefeld -->
<tr>
<td>Mot de passe</td>
<td>
@Html.PasswordFor(m => m.PasswordField, new { size = "15" })
</td>
</tr>
Der generierte Code HTML lautet wie folgt:
<!-- das Passwort-Eingabefeld -->
<tr>
<td>Mot de passe</td>
<td>
<input id="PasswordField" name="PasswordField" size="15" type="password" />
</td>
</tr>
Die verwendete Methode lautet wie folgt:
@Html.PasswordFor(m => m.PasswordField, new { size = "15" })
Die Funktionsweise entspricht der der Methode [Html.TexBoxFor].
Mehrzeiliges Eingabefeld
Der neue Code lautet wie folgt:
<!-- das mehrzeilige Texteingabefeld -->
<tr>
<td>Boîte de saisie</td>
<td>
@Html.TextAreaFor(m => m.TextAreaField, new { cols = "30", rows = "5" })
</td>
</tr>
Der generierte Code HTML lautet wie folgt:
<!-- das mehrzeilige Texteingabefeld -->
<tr>
<td>Boîte de saisie</td>
<td>
<textarea cols="30" id="TextAreaField" name="TextAreaField" rows="5">
ligne1
ligne2</textarea>
</td>
</tr>
Die verwendete Methode lautet wie folgt:
@Html.TextAreaFor(m => m.TextAreaField, new { cols = "30", rows = "5" })
Die Funktionsweise entspricht der der Methode [Html.TexBoxFor].
Auswahlliste mit einer einzigen Option
Der neue Code lautet wie folgt:
<!-- die Auswahlliste mit einer Auswahlmöglichkeit -->
<tr>
<td>Liste à choix unique</td>
<td>
@Html.DropDownListFor(m => m.SimpleChoiceListField, new SelectList(@Model.SimpleChoiceListFieldItems, "Value", "Label"), new { size = "3" })
</tr>
und der generierte Code HTML lautet wie folgt:
<!-- die Einfachauswahlliste -->
<tr>
<td>Liste à choix unique</td>
<td>
<select id="SimpleChoiceListField" name="SimpleChoiceListField" size="3">
<option value="1">liste1</option>
<option value="2">liste2</option>
<option selected="selected" value="3">liste3</option>
<option value="4">liste4</option>
<option value="5">liste5</option>
</select>
</tr>
Wir haben die Methode [Html.DropDownListFor] bereits behandelt. Der einzige Unterschied besteht hier im dritten Parameter, der dazu dient, ein Attribut [size] anzugeben, das ungleich 1 ist. Diese Eigenschaft bewirkt den Wechsel von einer Dropdown-Liste [size=1] zu einer einfachen Liste.
Die Mehrfachauswahlliste
Der neue Code lautet wie folgt:
<!-- die Mehrfachauswahlliste -->
<tr>
<td>Liste à choix multiple</td>
<td>
@Html.ListBoxFor(m => m.MultipleChoiceListField, new SelectList(@Model.MultipleChoiceListFieldItems, "Value", "Label"), new { size = "5" })
</tr>
und der generierte Code HTML lautet wie folgt:
<!-- die Mehrfachauswahlliste -->
<tr>
<td>Liste à choix multiple</td>
<td>
<select id="MultipleChoiceListField" multiple="multiple" name="MultipleChoiceListField" size="5">
<option selected="selected" value="1">liste1</option>
<option value="2">liste2</option>
<option selected="selected" value="3">liste3</option>
<option value="4">liste4</option>
<option value="5">liste5</option>
</select>
</tr>
Die Methode
@Html.ListBoxFor(m => m.MultipleChoiceListField, new SelectList(@Model.MultipleChoiceListFieldItems, "Value", "Label"), new { size = "5" })
funktioniert wie die Methode [Html.DropDownListFor], erzeugt jedoch eine Liste mit Mehrfachauswahl. Die ausgewählten Optionen sind diejenigen, deren Wert (Attribut value) in der Tabelle [MultipleChoiceListField] enthalten ist.
Das Tag <form> kann ebenfalls mit einer Methode generiert werden:
@using (Html.BeginForm("Action09Post", "First"))
{
...
}
Der generierte Code HTML lautet wie folgt:
<form action="/First/Action09Post" method="post">
...
</form>
Die Methode
Html.BeginForm("Action09Post", "First")
hat als ersten Parameter den Namen einer Aktion und als zweiten Parameter den Namen eines Controllers.
5.7.2. Die Aktionen und das Modell
Das Formular wird von der folgenden Aktion [Action09Get] ausgegeben:
// Aktion09-GET
[HttpGet]
public ViewResult Action09Get(ApplicationModel application)
{
ViewBag.info = string.Format("Contrôleur={0}, Action={1}", RouteData.Values["controller"], RouteData.Values["action"]);
return View("Formulaire2", new ViewModel09(application));
}
Die in Zeile 6 ausgegebene Ansicht ist [Formulaire2], die dem folgenden Modell [ViewModel09] zugeordnet ist:
using System.ComponentModel.DataAnnotations;
using System.Web.Mvc;
using Exemple_03.Models;
namespace Exemple_03.Models
{
public class ViewModel09
{
// die Eingabefelder
public string RadioButtonField { get; set; }
public bool CheckBoxField1 { get; set; }
public bool CheckBoxField2 { get; set; }
public bool CheckBoxField3 { get; set; }
public string TextField { get; set; }
public string PasswordField { get; set; }
public string TextAreaField { get; set; }
public string DropDownListField { get; set; }
public string SimpleChoiceListField { get; set; }
public string[] MultipleChoiceListField { get; set; }
// die im Formular anzuzeigenden Sammlungen
public ApplicationModel.Item[] RadioButtonFieldItems { get; set; }
public ApplicationModel.Item[] CheckBoxesFieldItems { get; set; }
public ApplicationModel.Item[] DropDownListFieldItems { get; set; }
public ApplicationModel.Item[] SimpleChoiceListFieldItems { get; set; }
public ApplicationModel.Item[] MultipleChoiceListFieldItems { get; set; }
// Konstruktoren
public ViewModel09()
{
}
public ViewModel09(ApplicationModel application)
{
// Initialisierung der Sammlungen
RadioButtonFieldItems = application.RadioButtonFieldItems;
CheckBoxesFieldItems = application.CheckBoxesFieldItems;
DropDownListFieldItems = application.DropDownListFieldItems;
SimpleChoiceListFieldItems = application.SimpleChoiceListFieldItems;
MultipleChoiceListFieldItems = application.MultipleChoiceListFieldItems;
// Initialisierung der Felder
RadioButtonField = "2";
CheckBoxField2 = true;
TextField = "quelques mots";
PasswordField = "secret";
TextAreaField = "ligne1\nligne2";
DropDownListField = "2";
SimpleChoiceListField = "3";
MultipleChoiceListField = new string[] { "1", "3" };
}
}
}
[ViewModel09] unterscheidet sich von [ViewModel08] durch die Handhabung der Kontrollkästchen. Anstelle einer Tabelle mit drei Kontrollkästchen wurden drei separate Kontrollkästchen verwendet (Zeilen 11–13).
Das Formular wird von der folgenden Aktion [Action09Post] verarbeitet:
// Aktion09-POST
[HttpPost]
public ViewResult Action09Post(ApplicationModel application, FormCollection posted)
{
ViewBag.info = string.Format("Contrôleur={0}, Action={1}", RouteData.Values["controller"], RouteData.Values["action"]);
ViewModel09 modèle = new ViewModel09(application);
TryUpdateModel(modèle, posted);
// Verarbeitung nicht übermittelter Werte
if (posted["SimpleChoiceListField"] == null)
{
modèle.SimpleChoiceListField = "";
}
if (posted["MultipleChoiceListField"] == null)
{
modèle.MultipleChoiceListField = new string[] { };
}
// Formularanzeige
return View("Formulaire2", modèle);
}
Die Aktion [Action09Post] ist bis auf zwei Punkte identisch mit der Aktion [Action08Post]:
- Zeile 18: Anstelle der Ansicht [Formulaire] wird die Ansicht [Formulaire2] verwendet;
- die Verwaltung der nicht markierten Kontrollkästchen entfällt. Dies wird nun korrekt durch die Methode [Html.CheckBoxFor] abgewickelt.
5.8. Erstellung eines Formulars anhand der Metadaten des Modells
Es gibt neben den zuvor genannten noch weitere Methoden zur Generierung eines Formulars. Eine davon besteht darin, einem Feld des Modells Informationen zuzuordnen, anhand derer das Framework MVC erkennen kann, welches Eingabe-Tag es generieren muss. Diese Informationen werden als Metadaten bezeichnet.
Betrachten wir das folgende Ansichtsmodell [ViewModel10]:
![]() |
using System;
using System.ComponentModel.DataAnnotations;
using System.Drawing;
namespace Exemple_03.Models
{
public class ViewModel10
{
[Display(Name="Text")]
[DataType(DataType.Text)]
public string Text { get; set; }
[Display(Name = "TextArea")]
[DataType(DataType.MultilineText)]
public string MultiLineText { get; set; }
[Display(Name = "Number")]
public int Number { get; set; }
[Display(Name = "Decimal")]
[UIHint("Decimal")]
public double Decimal { get; set; }
[Display(Name = "Tel")]
[DataType(DataType.PhoneNumber)]
public string Tel { get; set; }
[Display(Name = "Date")]
[DataType(DataType.Date)]
public DateTime Date { get; set; }
[Display(Name = "Time")]
[DataType(DataType.Time)]
public DateTime Time { get; set; }
[Display(Name = "HiddenInput")]
[UIHint("HiddenInput")]
public string HiddenInput { get; set; }
[Display(Name = "Boolean")]
[UIHint("Boolean")]
public bool Boolean { get; set; }
[Display(Name = "Email")]
[DataType(DataType.EmailAddress)]
public string Email{ get; set; }
[Display(Name = "Url")]
[DataType(DataType.Url)]
public string Url { get; set; }
[Display(Name = "Password")]
[DataType(DataType.Password)]
public string Password { get; set; }
[Display(Name = "Currency")]
[DataType(DataType.Currency)]
public double Currency { get; set; }
[Display(Name = "CreditCard")]
[DataType(DataType.CreditCard)]
public string CreditCard { get; set; }
// Konstruktor
public ViewModel10()
{
Text = "tra la la";
MultiLineText = "ligne1\nligne2";
Number = 4;
Decimal = 10.2;
Tel = "0617181920";
Date = DateTime.Now;
Time = DateTime.Now;
HiddenInput = "caché";
Boolean = true;
Email = "x@y.z";
Url = "http://istia.univ-angers.fr";
Password = "mdp";
Currency = 4.2;
CreditCard = "0123456789012345";
}
}
}
Die Metadaten bestehen aus den Tags [Display, DataType, UIHint].
Diese Ansichtsvorlage wird durch die folgende Aktion „[Action10Get]“ erstellt:
// Aktion10-GET
[HttpGet]
public ViewResult Action10Get()
{
return View(new ViewModel10());
}
In Zeile 5 oben wird die Standardansicht der Aktion [/First/Action10Get.cshtml ] angewiesen, die Ansichtsvorlage vom Typ [ViewModel10] anzuzeigen. Diese Ansicht sieht wie folgt aus:
![]() |
@model Exemple_03.Models.ViewModel10
@{
Layout = null;
}
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width" />
<title>Action10Get</title>
</head>
<body>
<h3>Formulaire ASP.NET MVC - 2</h3>
@using (Html.BeginForm("Action10Post", "First"))
{
<table>
<thead>
<tr>
<th>LabelFor</th>
<th>EditorFor</th>
<th>DisplayFor</th>
</tr>
</thead>
<tbody>
<tr>
<td>@Html.LabelFor(m => m.Text)</td>
<td>@Html.EditorFor(m => m.Text)</td>
<td>@Html.DisplayFor(m => m.Text)</td>
</tr>
<tr>
<td>@Html.LabelFor(m => m.MultiLineText)</td>
<td>@Html.EditorFor(m => m.MultiLineText)</td>
<td>@Html.DisplayFor(m => m.MultiLineText)</td>
</tr>
<tr>
<td>@Html.LabelFor(m => m.Number)</td>
<td>@Html.EditorFor(m => m.Number)</td>
<td>@Html.DisplayFor(m => m.Number)</td>
</tr>
<tr>
<td>@Html.LabelFor(m => m.Decimal)</td>
<td>@Html.EditorFor(m => m.Decimal)</td>
<td>@Html.DisplayFor(m => m.Decimal)</td>
</tr>
<tr>
<td>@Html.LabelFor(m => m.Tel)</td>
<td>@Html.EditorFor(m => m.Tel)</td>
<td>@Html.DisplayFor(m => m.Tel)</td>
</tr>
<tr>
<td>@Html.LabelFor(m => m.Date)</td>
<td>@Html.EditorFor(m => m.Date)</td>
<td>@Html.DisplayFor(m => m.Date)</td>
</tr>
<tr>
<td>@Html.LabelFor(m => m.Time)</td>
<td>@Html.EditorFor(m => m.Time)</td>
<td>@Html.DisplayFor(m => m.Time)</td>
</tr>
<tr>
<td>@Html.LabelFor(m => m.HiddenInput)</td>
<td>@Html.EditorFor(m => m.HiddenInput)</td>
<td>@Html.DisplayFor(m => m.HiddenInput)</td>
</tr>
<tr>
<td>@Html.LabelFor(m => m.Boolean)</td>
<td>@Html.EditorFor(m => m.Boolean)</td>
<td>@Html.DisplayFor(m => m.Boolean)</td>
</tr>
<tr>
<td>@Html.LabelFor(m => m.Email)</td>
<td>@Html.EditorFor(m => m.Email)</td>
<td>@Html.DisplayFor(m => m.Email)</td>
</tr>
<tr>
<td>@Html.LabelFor(m => m.Url)</td>
<td>@Html.EditorFor(m => m.Url)</td>
<td>@Html.DisplayFor(m => m.Url)</td>
</tr>
<tr>
<td>@Html.LabelFor(m => m.Password)</td>
<td>@Html.EditorFor(m => m.Password)</td>
<td>@Html.DisplayFor(m => m.Password)</td>
</tr>
<tr>
<td>@Html.LabelFor(m => m.Currency)</td>
<td>@Html.EditorFor(m => m.Currency)</td>
<td>@Html.DisplayFor(m => m.Currency)</td>
</tr>
<tr>
<td>@Html.LabelFor(m => m.CreditCard)</td>
<td>@Html.EditorFor(m => m.CreditCard)</td>
<td>@Html.DisplayFor(m => m.CreditCard)</td>
</tr>
</tbody>
</table>
<input type="submit" value="Valider" />
}
</body>
</html>
Für jede der Eigenschaften des Modells verwenden wir die Methode:
- Html.LabelFor, um den Wert der Metadaten [DisplayName] der Eigenschaft anzuzeigen;
- Html.EditorFor, um das Tag HTML zur Eingabe des Eigenschaftswerts zu generieren. Diese Methode verwendet die Metadaten [DataType] und [UIHint] der Eigenschaft;
- Html.DisplayFor, um den Wert der Eigenschaft gemäß dem durch die Metadaten [DataType] angegebenen Format anzuzeigen.
Hier ein Ausführungsbeispiel mit dem Chrome-Browser:

Je nach verwendetem Browser können unterschiedliche Seiten angezeigt werden. Die generierte Ansicht nutzt nämlich die neuen Tags, die mit der Version 5 von HTML, genannt HTML5, eingeführt wurden. Nicht alle Browser unterstützen diese Version bereits. Im obigen Beispiel unterstützt der Chrome-Browser sie teilweise.
5.8.1. Das [POST] des Formulars
Das [POST] des Formulars wird von der folgenden Aktion [Action10Post] verarbeitet:
// Aktion10-POST
[HttpPost]
public ContentResult Action10Post(ViewModel10 modèle)
{
string erreurs = getErrorMessagesFor(ModelState);
string texte = string.Format("Contrôleur={0}, Action={1}, valide={2}, erreurs={3}", RouteData.Values["controller"], RouteData.Values["action"], ModelState.IsValid, erreurs);
return Content(texte, "text/plain", Encoding.UTF8);
}
- Zeile 3: Die Aktion [Action10Post] verwendet das übermittelte Formular als Eingabemodell;
- Zeile 5: Die Validierungsfehler dieses Formulars werden abgerufen;
- Zeile 6: Die Textantwort an den Kunden wird vorbereitet;
- Zeile 7: Diese wird versendet.
Betrachten wir nun die Eigenschaften des Modells [ViewModel10] nacheinander und sehen wir uns an, wie die zugehörigen Metadaten das generierte HTML und die Validierung der Eingabefelder beeinflussen.
5.8.2. Eigenschaft [Text]
Definition
[Display(Name="Text")]
[DataType(DataType.Text)]
public string Text { get; set; }
...
Text = "tra la la";
Ansicht
<tr>
<td>@Html.LabelFor(m => m.Text)</td>
<td>@Html.EditorFor(m => m.Text)</td>
<td>@Html.DisplayFor(m => m.Text)</td>
</tr>
Grafik
![]() |
HTML generiert
<tr>
<td><label for="Text">Text</label></td>
<td><input class="text-box single-line" id="Text" name="Text" type="text" value="tra la la" /></td>
<td>tra la la</td>
</tr>
Kommentare
- Die Methode [Html.LabelFor] hat das Tag <label> in Zeile 2 generiert. Der Wert des Attributs [for] ist der Name der Parametereigenschaft der Methode [Html.LabelFor]
public string Text { get; set; }
Der zwischen dem Start- und End-Tag angezeigte Text ist der Metadaten-Text
[Display(Name="Text")]
Die Methode [Html.LabelFor] verfährt immer so. Wir werden bei den anderen Eigenschaften nicht noch einmal darauf zurückkommen.
- Die Methode [Html.EditorFor] hat das Tag <input> in Zeile 3 generiert. Es ist zu beachten, dass sie ein Attribut [class] besitzt, das dem Tag die Klasse CSS [text-box single-line] zuordnet. Die Attribute [id] und [name] haben als Wert den Namen [Text] der Eigenschaft „parameter“ der Methode [Html.EditorFor]. Das Attribut [type] erhielt aufgrund der Metadaten den Wert [text]
[DataType(DataType.Text)]
- Die Methode [Html.DisplayFor] hat den Text in Zeile 4 generiert. Dies ist der Wert der Parameter-Eigenschaft der Methode [Html.DisplayFor ]. Diese Methode wird durch die Metadaten
[DataType(DataType.Text)]
, wodurch der Wert als unformatierter Text angezeigt wird.
5.8.3. Eigenschaft [MultiLineText]
Definition
[Display(Name = "TextArea")]
[DataType(DataType.MultilineText)]
public string MultiLineText { get; set; }
Ansicht
<tr>
<td>@Html.LabelFor(m => m.MultiLineText)</td>
<td>@Html.EditorFor(m => m.MultiLineText)</td>
<td>@Html.DisplayFor(m => m.MultiLineText)</td>
</tr>
Bild
HTML generiert
<tr>
<td><label for="MultiLineText">TextArea</label></td>
<td><textarea class="text-box multi-line" id="MultiLineText" name="MultiLineText">
ligne1
ligne2</textarea></td>
<td>ligne1
ligne2</td>
</tr>
Kommentare
- Die Methode [Html.EditorFor] hat das Tag <textarea> in Zeile 3 generiert. Es ist zu beachten, dass sie ein Attribut [class] besitzt, das dem Tag die Klasse CSS [text-box multi-line] zuordnet. Die Attribute [id] und [name] haben als Wert den Namen [MultiLineText] der Eigenschaft „parameter“ der Methode [Html.EditorFor]. Das ist immer so. Wir werden darauf nicht mehr näher eingehen. Das generierte Tag lautet <textarea> aufgrund der Metadaten
[DataType(DataType.MultilineText)]
, die angab, dass es sich bei der Eigenschaft um einen mehrzeiligen Text handelte.
- Die Methode [Html.DisplayFor] hat den Text der Zeilen 4–5 generiert. Dies ist der Wert der Parameter-Eigenschaft der Methode [Html.DisplayFor ].
5.8.4. Eigenschaft [Number]
Definition
[Display(Name = "Number")]
public int Number { get; set; }
Ansicht
<tr>
<td>@Html.LabelFor(m => m.Number)</td>
<td>@Html.EditorFor(m => m.Number)</td>
<td>@Html.DisplayFor(m => m.Number)</td>
</tr>
Bild
HTML generiert
<tr>
<td><label for="Number">Number</label></td>
<td><input class="text-box single-line" data-val="true" data-val-number="Le champ Number doit être un nombre." data-val-required="Le champ Number est requis." id="Number" name="Number" type="number" value="4" /></td>
<td>4</td>
</tr>
Kommentare
- Die Methode [Html.EditorFor] hat das Tag <input> in Zeile 3 mit einem Attribut [type] vom Typ [number] generiert. Offenbar einfach deshalb, weil die Eigenschaft den Typ [int] hat. Die Attribute [data-val], [data-val-number] und [data-val-required] werden von HTML5 nicht erkannt. Sie werden von einem JavaScript-Framework zur serverseitigen Datenvalidierung verwendet;
- die Methode [Html.DisplayFor] hat den Text in Zeile 4, den Wert der Eigenschaft, generiert.
Validierung
Die Attribute [data-x] beeinflussen die clientseitige Datenvalidierung. Hier sind zwei Beispiele:
Man gibt eine falsche Zahl ein und führt die Validierung durch:
![]() |
Im obigen Beispiel erfolgte die Validierung auf der Client-Seite. Das Formular wird erst abgeschickt, wenn der Fehler behoben wurde.
Ein weiteres Beispiel: Es wird nichts eingegeben:
![]() |
Bei [1] oben meldet [Action10Post] einen Fehler. Vielleicht erinnern wir uns, dass wir dieses Verhalten bereits erzielt hatten, indem wir das Attribut [Required] auf die zu prüfende Eigenschaft angewendet haben (siehe Seite 69), hier die Eigenschaft [Number]. In diesem Fall war dies jedoch nicht erforderlich.
5.8.5. Eigenschaft [Decimal]
Definition
[Display(Name = "Decimal")]
[UIHint("Decimal")]
public double Decimal { get; set; }
Ansicht
<tr>
<td>@Html.LabelFor(m => m.Decimal)</td>
<td>@Html.EditorFor(m => m.Decimal)</td>
<td>@Html.DisplayFor(m => m.Decimal)</td>
</tr>
Grafik
HTML generiert
<tr>
<td><label for="Decimal">Decimal</label></td>
<td><input class="text-box single-line" data-val="true" data-val-number="Le champ Decimal doit être un nombre." data-val-required="Le champ Decimal est requis." id="Decimal" name="Decimal" type="text" value="10,20" /></td>
<td>10,20</td>
</tr>
Kommentare
- Die Methode [Html.EditorFor] hat das Tag <input> in Zeile 3 mit einem Attribut [type] vom Typ [text] generiert. Die übrigen Attribute sind identisch mit denen, die für die vorherige Eigenschaft [Number] generiert wurden. Die Metadaten:
[UIHint("Decimal")]
bewirkt, dass der Wert der Eigenschaft bei den beiden Methoden [Html.EditorFor] und [Html.DisplayFor] mit zwei Dezimalstellen angezeigt wird
Validierung
Im Gegensatz zum vorherigen Fall wird auf der Client-Seite kein Validierungsfehler gemeldet. Der Fehler wird nur durch die Aktion [Action10Post] gemeldet. Auch hier ist die Dezimalzahl erforderlich, ohne dass das Attribut [Required] gesetzt werden muss.
5.8.6. Eigenschaft [Tel]
Definition
[Display(Name = "Tel")]
[DataType(DataType.PhoneNumber)]
public string Tel { get; set; }
Ansicht
<tr>
<td>@Html.LabelFor(m => m.Tel)</td>
<td>@Html.EditorFor(m => m.Tel)</td>
<td>@Html.DisplayFor(m => m.Tel)</td>
</tr>
Bild
HTML generiert
<tr>
<td><label for="Tel">Tel</label></td>
<td><input class="text-box single-line" id="Tel" name="Tel" type="tel" value="0617181920" /></td>
<td>0617181920</td>
</tr>
Kommentare
- Die Methode [Html.EditorFor] hat das Tag <input> in Zeile 3 mit einem Attribut [type] vom Typ [tel] generiert. Dieser Wert wurde aufgrund der Metadaten generiert:
[DataType(DataType.PhoneNumber)]
Der Typ [tel] für ein <input>-Tag ist eine Neuerung gegenüber HTML5. Der Chrome-Browser hat es als <input>-Tag mit dem Typ [text] verarbeitet.
Validierung
Es werden weder auf Client- noch auf Serverseite Validierungsfehler gemeldet. Es kann beliebiger Inhalt eingegeben werden.
5.8.7. Eigenschaft [Date]
Definition
[Display(Name = "Date")]
[DataType(DataType.Date)]
public DateTime Date { get; set; }
Ansicht
<tr>
<td>@Html.LabelFor(m => m.Date)</td>
<td>@Html.EditorFor(m => m.Date)</td>
<td>@Html.DisplayFor(m => m.Date)</td>
</tr>
Bild
![]() |
HTML generiert
<tr>
<td><label for="Date">Date</label></td>
<td><input class="text-box single-line" data-val="true" data-val-date="Le champ Date doit être une date." data-val-required="Le champ Date est requis." id="Date" name="Date" type="date" value="11/10/2013" /></td>
<td>11/10/2013</td>
</tr>
Kommentare
- Die Methode [Html.EditorFor] hat das Tag <input> in Zeile 3 mit einem Attribut [type] vom Typ [date] generiert. Dieser Wert wurde aufgrund der Metadaten generiert:
[DataType(DataType.Date)]
Der Typ [date] für ein <input>-Tag ist eine Neuerung gegenüber HTML5. Der Chrome-Browser erkennt ihn und ermöglicht die Eingabe des Datums über einen Kalender. Außerdem wird das eingegebene Datum im Format [jj/mm/aaaa] dargestellt, d. h., Chrome passt das Datumsformat an das [locale] des Browsers an.
- Auch die Methode [Html.DisplayFor] hat das Datum in der Form [jj/mm/aaaa] geschrieben, was ebenfalls auf das Vorhandensein der Metadaten [Date] zurückzuführen ist.
Validierung
Ein ungültiges Datum wird auf der Client-Seite als [1] gemeldet, wodurch die Übermittlung des POST aus dem Formular an den Server verhindert wird.
![]() |
Das Fehlen eines Datums wird auf der Client-Seite nicht gemeldet, wohl aber auf der Server-Seite: [2].
5.8.8. Eigenschaft [Time]
Definition
[Display(Name = "Time")]
[DataType(DataType.Time)]
public DateTime Time { get; set; }
Ansicht
<tr>
<td>@Html.LabelFor(m => m.Time)</td>
<td>@Html.EditorFor(m => m.Time)</td>
<td>@Html.DisplayFor(m => m.Time)</td>
</tr>
Grafik
HTML generiert
<tr>
<td><label for="Time">Time</label></td>
<td><input class="text-box single-line" data-val="true" data-val-required="Le champ Time est requis." id="Time" name="Time" type="time" value="11:17" /></td>
<td>11:17</td>
</tr>
Kommentare
- Die Methode [Html.EditorFor] hat das Tag <input> in Zeile 3 mit einem Attribut [type] vom Typ [time] generiert. Dieser Wert wurde aufgrund der Metadaten generiert:
[DataType(DataType.Time)]
Der Typ [time] für ein <input>-Tag ist eine Neuerung gegenüber HTML5. Der Chrome-Browser erkennt ihn und ermöglicht die Eingabe einer Uhrzeit im Format [hh:mm];
- die Methode [Html.DisplayFor] schrieb die Uhrzeit ebenfalls im Format [hh:mm], ebenfalls aufgrund des Vorhandenseins der Metadaten [Time].
Validierung
Es ist technisch nicht möglich, eine ungültige Uhrzeit einzugeben. Das Fehlen einer Uhrzeit wird serverseitig gemeldet:
![]() |
5.8.9. Eigenschaft [HiddenInput]
Definition
[Display(Name = "HiddenInput")]
[UIHint("HiddenInput")]
public string HiddenInput { get; set; }
Ansicht
<tr>
<td>@Html.LabelFor(m => m.HiddenInput)</td>
<td>@Html.EditorFor(m => m.HiddenInput)</td>
<td>@Html.DisplayFor(m => m.HiddenInput)</td>
</tr>
Grafik
HTML generiert
<tr>
<td><label for="HiddenInput">HiddenInput</label></td>
<td>caché<input id="HiddenInput" name="HiddenInput" type="hidden" value="verborgen" /></td>
<td>caché</td>
</tr>
Kommentare
- Die Methode [Html.EditorFor] hat das Tag <input> in Zeile 3 mit einem Attribut [type] vom Typ [hidden] generiert, d. h. ein verstecktes (aber dennoch übermitteltes) Feld. Dieser Wert wurde aufgrund der Metadaten generiert:
[UIHint("HiddenInput")]
- Die Methode [Html.DisplayFor] hat den Wert des versteckten Feldes geschrieben.
5.8.10. Eigenschaft [Boolean]
Definition
[Display(Name = "Boolean")]
public bool Boolean { get; set; }
Ansicht
<tr>
<td>@Html.LabelFor(m => m.Boolean)</td>
<td>@Html.EditorFor(m => m.Boolean)</td>
<td>@Html.DisplayFor(m => m.Boolean)</td>
</tr>
Bild
HTML generiert
<tr>
<td><label for="Boolean">Boolean</label></td>
<td><input checked="checked" class="check-box" data-val="true" data-val-required="Le champ Boolean est requis." id="Boolean" name="Boolean" type="checkbox" value="true" /><input name="Boolean" type="hidden" value="false" /></td>
<td><input checked="checked" class="check-box" disabled="disabled" type="checkbox" /></td>
</tr>
Kommentare
- Die Methode [Html.EditorFor] hat das Tag <input> in Zeile 3 mit einem Attribut [type] vom Typ [checkbox] generiert, d. h. ein Kontrollkästchen. Dieser Wert wurde generiert, da die Eigenschaft boolesch ist:
public bool Boolean { get; set; }
- Die Methode [Html.DisplayFor] hat Zeile 4 generiert, ebenfalls ein Kontrollkästchen (Attribut type), das jedoch deaktiviert ist (Attribut disabled).
5.8.11. Eigenschaft [Email]
Definition
[Display(Name = "Email")]
[DataType(DataType.EmailAddress)]
public string Email{ get; set; }
Ansicht
<tr>
<td>@Html.LabelFor(m => m.Email)</td>
<td>@Html.EditorFor(m => m.Email)</td>
<td>@Html.DisplayFor(m => m.Email)</td>
</tr>
Bild
HTML generiert
<tr>
<td><label for="Email">Email</label></td>
<td><input class="text-box single-line" id="Email" name="Email" type="email" value="x@y.z" /></td>
<td><a href="mailto:x@y.z">x@y.z</a></td>
</tr>
Kommentare
- Die Methode [Html.EditorFor] hat das Tag <input> in Zeile 3 mit einem Attribut [type] vom Typ [email] generiert. Dieser Typ ist neu in HTML5. Dieser Typ wurde aufgrund der folgenden Metadaten generiert:
[DataType(DataType.EmailAddress)]
Chrome scheint diesen Typ als Typ [text] behandelt zu haben.
- Die Methode [Html.DisplayFor] hat Zeile 4 generiert: einen Link zur E-Mail-Adresse.
Validierung
Auf der Client-Seite wird eine ungültige Adresse gemeldet: [1]:
![]() |
Eine fehlende Eingabe führt zu keinem Fehler.
5.8.12. Eigenschaft [Url]
Definition
[Display(Name = "Url")]
[DataType(DataType.Url)]
public string Url { get; set; }
Ansicht
<tr>
<td>@Html.LabelFor(m => m.Url)</td>
<td>@Html.EditorFor(m => m.Url)</td>
<td>@Html.DisplayFor(m => m.Url)</td>
</tr>
Bild
HTML generiert
<tr>
<td><label for="Url">Url</label></td>
<td><input class="text-box single-line" id="Url" name="Url" type="url" value="http://istia.univ-angers.fr" /></td>
<td><a href="http://istia.univ-angers.fr">http://istia.univ-angers.fr</a></td>
</tr>
Kommentare
- Die Methode [Html.EditorFor] hat das Tag <input> in Zeile 3 mit einem Attribut [type] vom Typ [url] generiert. Dieser Typ ist neu in HTML5. Er wurde aufgrund der folgenden Metadaten generiert:
[DataType(DataType.Url)]
Chrome scheint diesen Typ als Typ [text] zu behandeln.
- Die Methode [Html.DisplayFor] hat Zeile 4 generiert: einen Link zum URL.
Validierung
Ein ungültiger URL wird auf der Client-Seite als [1] gemeldet:
![]() |
Eine fehlende Eingabe führt zu keinem Fehler.
5.8.13. Eigenschaft [Password]
Definition
[Display(Name = "Password")]
[DataType(DataType.Password)]
public string Password { get; set; }
Ansicht
<tr>
<td>@Html.LabelFor(m => m.Password)</td>
<td>@Html.EditorFor(m => m.Password)</td>
<td>@Html.DisplayFor(m => m.Password)</td>
</tr>
Bild
HTML generiert
<tr>
<td><label for="Password">Password</label></td>
<td><input class="text-box single-line password" id="Password" name="Password" type="password" value="mdp" /></td>
<td>mdp</td>
</tr>
Kommentare
- Die Methode [Html.EditorFor] hat das Tag <input> in Zeile 3 mit einem Attribut [type] vom Typ [password] generiert. Dieser Typ wurde aufgrund der Metadaten generiert:
[DataType(DataType.Password)]
- Die Methode [Html.DisplayFor] hat Zeile 4 generiert.
5.8.14. Eigenschaft [Currency]
Definition
[Display(Name = "Currency")]
[DataType(DataType.Currency)]
public double Currency { get; set; }
Ansicht
<tr>
<td>@Html.LabelFor(m => m.Currency)</td>
<td>@Html.EditorFor(m => m.Currency)</td>
<td>@Html.DisplayFor(m => m.Currency)</td>
</tr>
Bild
HTML generiert
<tr>
<td><label for="Currency">Currency</label></td>
<td><input class="text-box single-line" data-val="true" data-val-number="Le champ Currency doit être un nombre." data-val-required="Le champ Currency est requis." id="Currency" name="Currency" type="text" value="4,2" /></td>
<td>4,20 €</td>
</tr>
Kommentare
- Die Methode [Html.EditorFor] hat das Tag <input> in Zeile 3 mit einem Attribut [type] vom Typ [text] generiert;
- Die Methode [Html.DisplayFor] hat Zeile 4 generiert, eine Zahl mit zwei Dezimalstellen und einem Währungssymbol. Dieses Format wurde aufgrund der Metadaten verwendet:
[DataType(DataType.Currency)]
Validierung
Ein ungültiger Wert [1] oder das Fehlen eines Werts [2] wird serverseitig gemeldet:
![]() |
5.8.15. Eigenschaft [CreditCard]
Definition
[Display(Name = "CreditCard")]
[DataType(DataType.CreditCard)]
public string CreditCard { get; set; }
Ansicht
<tr>
<td>@Html.LabelFor(m => m.CreditCard)</td>
<td>@Html.EditorFor(m => m.CreditCard)</td>
<td>@Html.DisplayFor(m => m.CreditCard)</td>
</tr>
Bild
HTML generiert
<tr>
<td><label for="CreditCard">CreditCard</label></td>
<td><input class="text-box single-line" id="CreditCard" name="CreditCard" type="text" value="0123456789012345" /></td>
<td>0123456789012345</td>
</tr>
Kommentare
- Die Methode [Html.EditorFor] hat das Tag <input> in Zeile 3 mit einem Attribut [type] vom Typ [text] generiert. Die Methode [Html.DisplayFor] hat Zeile 4 generiert. Hier ist nicht ersichtlich, welchen Beitrag die Metadaten leisten:
[DataType(DataType.CreditCard)]
Validierung
Es wird weder auf Client- noch auf Serverseite eine Überprüfung durchgeführt.
5.9. Validierung eines Formulars
Wir sind bereits in Abschnitt 4.5 und den folgenden Abschnitten auf das Problem der Validierung des Modells einer Aktion eingegangen. Wir greifen diese Problematik im Zusammenhang mit einem Formular erneut auf:
- Wie lassen sich Eingabefehler dem Benutzer melden?
- Validierungen sowohl clientseitig als auch serverseitig durchführen, um Fehler dem Benutzer schneller anzuzeigen.
5.9.1. Serverseitige Validierung
Betrachten wir das folgende Modell:
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Net.Mail;
namespace Exemple_03.Models
{
public class ViewModel11 : IValidatableObject
{
[Required(ErrorMessage = "Information requise")]
[Display(Name = "Chaîne d'au moins quatre caractères")]
[RegularExpression(@"^.{4,}$", ErrorMessage = "Information incorrecte")]
public string Chaine1 { get; set; }
[Display(Name = "Chaîne d'au plus quatre caractères")]
[Required(ErrorMessage = "Information requise")]
[RegularExpression(@"^.{1,4}$", ErrorMessage = "Information incorrecte")]
public string Chaine2 { get; set; }
[Required(ErrorMessage = "Information requise")]
[Display(Name = "Chaîne de quatre caractères exactement")]
[RegularExpression(@"^.{4,4}$", ErrorMessage = "Information incorrecte")]
public string Chaine3 { get; set; }
[Required(ErrorMessage = "Information requise")]
[Display(Name = "Nombre entier")]
public int Entier1 { get; set; }
[Display(Name = "Nombre entier dans l'intervalle [1,100]")]
[Required(ErrorMessage = "Information requise")]
[Range(1, 100, ErrorMessage = "Information incorrecte")]
public int Entier2 { get; set; }
[Display(Name = "Nombre réel")]
[Required(ErrorMessage = "Information requise")]
public double Reel1 { get; set; }
[Display(Name = "Nombre réel dans l'intervalle [10.2, 11.3]")]
[Required(ErrorMessage = "Information requise")]
[Range(10.2, 11.3, ErrorMessage = "Information incorrecte")]
public double Reel2 { get; set; }
[Display(Name = "Adresse mail")]
[Required(ErrorMessage = "Information requise")]
public string Email1 { get; set; }
[Display(Name = "Date sous la forme dd/jj/aaaa")]
[RegularExpression(@"\s*\d{2}/\d{2}/\d{4}\s*", ErrorMessage = "Information incorrecte")]
[Required(ErrorMessage = "Information requise")]
public string Regexp1 { get; set; }
[Display(Name = "Date postérieure à celle d'aujourd'hui")]
[Required(ErrorMessage = "Information requise")]
[DataType(DataType.Date)]
public DateTime Date1 { get; set; }
// Validierung
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
List<ValidationResult> résultats = new List<ValidationResult>();
// Datum 1
if (Date1.Date <= DateTime.Now.Date)
{
résultats.Add(new ValidationResult("Information incorrecte", new string[] { "Date1" }));
}
// E-Mail 1
try
{
new MailAddress(Email1);
}
catch
{
résultats.Add(new ValidationResult("Information incorrecte", new string[] { "Email1" }));
}
// Ausgabe der Fehlerliste
return résultats;
}
}
}
Dieses Muster wird von der folgenden Ansicht [Action11Get.cshtml] angezeigt:
![]() |
@model Exemple_03.Models.ViewModel11
@{
Layout = null;
}
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width" />
<title>Action11Get</title>
<link rel="stylesheet" href="~/Content/Site.css" />
</head>
<body>
<h3>Formulaire ASP.NET MVC – Validation 1</h3>
@using (Html.BeginForm("Action11Post", "First"))
{
<table>
<thead>
<tr>
<th>Type attendu</th>
<th>Valeur saisie</th>
<th>Message d'erreur</th>
</tr>
</thead>
<tbody>
<tr>
<td>@Html.LabelFor(m => m.Chaine1)</td>
<td>@Html.EditorFor(m => m.Chaine1)</td>
<td>@Html.ValidationMessageFor(m => m.Chaine1)</td>
</tr>
<tr>
<td>@Html.LabelFor(m => m.Chaine2)</td>
<td>@Html.EditorFor(m => m.Chaine2)</td>
<td>@Html.ValidationMessageFor(m => m.Chaine2)</td>
</tr>
<tr>
<td>@Html.LabelFor(m => m.Chaine3)</td>
<td>@Html.EditorFor(m => m.Chaine3)</td>
<td>@Html.ValidationMessageFor(m => m.Chaine3)</td>
</tr>
<tr>
<td>@Html.LabelFor(m => m.Entier1)</td>
<td>@Html.EditorFor(m => m.Entier1)</td>
<td>@Html.ValidationMessageFor(m => m.Entier1)</td>
</tr>
<tr>
<td>@Html.LabelFor(m => m.Entier2)</td>
<td>@Html.EditorFor(m => m.Entier2)</td>
<td>@Html.ValidationMessageFor(m => m.Entier2)</td>
</tr>
<tr>
<td>@Html.LabelFor(m => m.Reel1)</td>
<td>@Html.EditorFor(m => m.Reel1)</td>
<td>@Html.ValidationMessageFor(m => m.Reel1)</td>
</tr>
<tr>
<td>@Html.LabelFor(m => m.Reel2)</td>
<td>@Html.EditorFor(m => m.Reel2)</td>
<td>@Html.ValidationMessageFor(m => m.Reel2)</td>
</tr>
<tr>
<td>@Html.LabelFor(m => m.Email1)</td>
<td>@Html.EditorFor(m => m.Email1)</td>
<td>@Html.ValidationMessageFor(m => m.Email1)</td>
</tr>
<tr>
<td>@Html.LabelFor(m => m.Regexp1)</td>
<td>@Html.EditorFor(m => m.Regexp1)</td>
<td>@Html.ValidationMessageFor(m => m.Regexp1)</td>
</tr>
<tr>
<td>@Html.LabelFor(m => m.Date1)</td>
<td>@Html.EditorFor(m => m.Date1)</td>
<td>@Html.ValidationMessageFor(m => m.Date1)</td>
</tr>
</tbody>
</table>
<p>
<input type="submit" value="Valider" />
</p>
}
</body>
</html>
- Zeile 12: Es wird auf das Stylesheet [Site.css] verwiesen. Dieses enthält standardmäßig Klassen, die zur Hervorhebung von Eingabefehlern im Formular verwendet werden;
- Zeilen 18–25: eine Tabelle mit drei Spalten:
- Spalte 1 zeigt Text mit der Methode [Html.LabelFor] an,
- Spalte 2 zeigt die Eingabe mit der Methode [Html.EditorFor] an,
- Spalte 3 zeigt eventuelle Eingabefehler mit der Methode [Html.ValidationMessageFor] an;
Die Aktion [Action11Get] dient zur Anzeige des Formulars:
// Aktion11-GET
[HttpGet]
public ViewResult Action11Get()
{
return View("Action11Get", new ViewModel11());
}
Die Aktion [Action11Post] dient dazu, das Formular mit eventuellen Eingabefehlern erneut anzuzeigen:
// Aktion11-POST
[HttpPost]
public ViewResult Action11Post(ViewModel11 modèle)
{
return View("Action11Get", modèle);
}
- Zeile 3: Die Vorlage [ViewModel11] wird erstellt und anschließend mit den übermittelten Werten initialisiert. Dabei können Fehler auftreten. Jeder fehlerhaften Eigenschaft P der Vorlage ist eine Fehlermeldung zugeordnet. Diese Meldung wird über die Methode [Html.ValidationMessageFor] des Formulars abgerufen.
Hier ein Ausführungsbeispiel:
![]() | ![]() |
Hier ist ein weiteres Beispiel:
![]() |
Es ist zu beachten, dass beide Datumsangaben falsch sind (es ist der 11.10.2013), die Fehler jedoch nicht gemeldet werden. Diese Fehler werden von der Methode [Validate] des Modells erkannt:
// Validierung
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
List<ValidationResult> résultats = new List<ValidationResult>();
// Datum 1
if (Date1.Date <= DateTime.Now.Date)
{
résultats.Add(new ValidationResult("Information incorrecte", new string[] { "Date1" }));
}
// E-Mail 1
try
{
new MailAddress(Email1);
}
catch
{
résultats.Add(new ValidationResult("Information incorrecte", new string[] { "Email1" }));
}
// Regexp1
try
{
DateTime.ParseExact(Regexp1, "dd/MM/yyyy", CultureInfo.CreateSpecificCulture("fr-FR"));
}
catch
{
résultats.Add(new ValidationResult("Information incorrecte", new string[] { "Regexp1" }));
}
// Die Fehlerliste wird ausgegeben
return résultats;
}
Die Methode [Validate] wird erst ausgeführt, wenn alle Attributprüfungen bestanden sind. Dies zeigt ein letztes Beispiel:
![]() |
5.9.2. Clientseitige Validierung
Alle bisherigen Validierungen erfolgten serverseitig. Es ist daher ein Hin- und Rücklauf zwischen Client und Server erforderlich, damit der Benutzer seine Fehler bemerkt. Die clientseitige Validierung nutzt JavaScript-Code, um den Benutzer so früh wie möglich und auf jeden Fall vor der Ausführung von POST auf seine Fehler hinzuweisen. Letztere kann erst stattfinden, wenn alle erkannten Fehler behoben wurden.
Wir greifen das vorherige Modell [ViewModel11] wieder auf, zeigen es nun jedoch mit der folgenden Ansicht [Action12Get.cshtml] an:
![]() |
@model Exemple_03.Models.ViewModel11
@{
Layout = null;
}
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width" />
<title>Action12Get</title>
<link rel="stylesheet" href="~/Content/Site.css" />
<script type="text/javascript" src="~/Scripts/jquery-1.8.2.min.js" ></script>
<script type="text/javascript" src="~/Scripts/jquery.validate.min.js" ></script>
<script type="text/javascript" src="~/Scripts/jquery.validate.unobtrusive.min.js" ></script>
</head>
<body>
<h3>Formulaire ASP.NET MVC - Validation 1</h3>
@using (Html.BeginForm("Action11Post", "First"))
{
<table>
<thead>
<tr>
<th>Type attendu</th>
<th>Valeur saisie</th>
<th>Message d'erreur</th>
</tr>
</thead>
<tbody>
...
</tbody>
</table>
<p>
<input type="submit" value="Valider" />
</p>
}
</body>
</html>
Hinweis: Zeile 13 – Passen Sie die Version von jQuery an die Ihrer Visual Studio-Version an (siehe unten).
Für die clientseitige Validierung muss die folgende Zeile 3 in der Datei [Web.config] der Anwendung vorhanden sein.
<appSettings>
...
<add key="ClientValidationEnabled" value="true" />
</appSettings>
- Zeilen 1–4: Der Abschnitt [appSettings] muss ein direktes untergeordnetes Element des Abschnitts [configuration] in der Datei [Web.config] sein;
Die Ansicht [Action12Get] ist bis auf die Zeilen 13–15 identisch mit der vorherigen Ansicht [Action11Get]. Diese fügen der Ansicht die für die clientseitige Validierung erforderlichen JavaScript-Skripte hinzu. Diese Skripte befinden sich im Ordner [Scripts] des Projekts:
![]() |
Jedes Skript verfügt über eine normale Version ([.js]) und eine minimierte Version ([min.js]). Letztere ist kleiner, aber unlesbar. Sie wird in der Produktion verwendet. Die lesbare Version wird in der Entwicklung verwendet.
Die Ansicht [Action12Get.cshtml] wird durch die folgende Aktion [Action12Get] angezeigt:
// Aktion12-GET
[HttpGet]
public ViewResult Action12Get()
{
return View("Action12Get", new ViewModel11());
}
Das ausgefüllte Formular wird durch die folgende Aktion [Action12Post] verarbeitet:
// Aktion12-POST
[HttpPost]
public ViewResult Action12Post(ViewModel11 modèle)
{
return View("Action12Get", modèle);
}
Schauen wir uns anhand eines Beispiels an, was sich dadurch ändert:
![]() |
Sobald man in [1] ein Zeichen eingibt, wird die Meldung in [2] angezeigt, da der erwartete Wert mindestens vier Zeichen haben muss. Die Validierung erfolgt also bei jedem neu eingegebenen Zeichen. Die Fehlermeldung verschwindet nach dem vierten eingegebenen Zeichen. Anschließend validieren wir das Formular:
![]() |
Die Meldung URL [3] zeigt uns, dass [POST] nicht stattgefunden hat. Der Klick auf die Schaltfläche „[Valider]“ hat jedoch alle clientseitigen Validierungen ausgelöst, und es sind neue Fehlermeldungen erschienen.
Schauen wir uns zum Beispiel den Code „HTML“ an, der bei der ersten Eingabe generiert wurde:
<tr>
<td><label for="Chaine1">Chaîmindestens vier Zeichen lang</label></td>
<td><input class="text-box single-line" data-val="true" data-val-regex="Information incorrecte" data-val-regex-pattern="^.{4,}$" data-val-required="Information requise" id="Chaine1" name="Chaine1" type="text" value="" /></td>
<td><span class="field-validation-valid" data-valmsg-for="Chaine1" data-valmsg-replace="true"></span></td>
</tr>
- In Zeile 3 finden wir:
- die Fehlermeldung für den Fall, dass die Eingabe fehlt: [data-val-required],
- die Fehlermeldung für den Fall, dass die Eingabe fehlerhaft ist: [data-val-regex],
- den regulären Ausdruck für die eingegebene Zeichenfolge [data-val-regex-pattern];
- Zeile 4: weitere Attribute [data-x], die zur Anzeige einer eventuellen Fehlermeldung verwendet werden;
Die Attribute [data-x] der generierten Tags werden von dem JavaScript ausgewertet, das wir in die Ansicht eingebettet haben. Fehlt dieses, werden diese Attribute einfach ignoriert, und es findet keine clientseitige Validierung statt. Die Funktionsweise entspricht der im vorherigen Beispiel. Daher der Begriff [unobtrusive] für diese Technik.
5.10. Verwaltung von Navigations- und Aktionslinks
Wir werden die folgenden beiden Ansichten erstellen, um die Verwaltung von Links in einer Ansicht zu veranschaulichen:
![]() |
- In [1] und [2] gibt es zwei Navigationslinks;
- in [3] gibt es einen Aktionslink, der das Formular absendet. Er dient nicht zur Navigation.
Seite 1 wird durch die folgende Ansicht [Action16Get.cshtml] generiert:
@{
Layout = null;
}
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width" />
<title>Action16Get</title>
<script>
function postForm() {
// Das Formular aus dem Dokument wird abgerufen
var form = document.forms[0];
// Absenden
form.submit();
}
</script>
</head>
<body>
<h3>Navigation - page 1</h3>
<h4>@ViewBag.info</h4>
@using (Html.BeginForm("Action16Post", "Second"))
{
@Html.Label("data", "Tapez un texte")
@Html.TextBox("data")
<a href="javascript:postForm()">Valider</a>
}
<p>
@Html.ActionLink("Page 2", "Action17Get", "Second")
</p>
</body>
</html>
- Zeile 22: eine Information, die von der Aktion initialisiert wird, die die Ansicht ausliefert;
- Zeilen 23–28: ein Formular;
- Zeile 25: eine Beschriftung für das Feld [data];
- Zeile 26: ein Eingabefeld mit dem Namen [data];
- Zeile 27: ein Link vom Typ [submit]. Beim Anklicken wird die JavaScript-Funktion [postForm] ausgeführt (Attribut „href“). Diese ist in den Zeilen 12–17 definiert;
- Zeile 14: Es wird eine Referenz auf das erste Formular des Dokuments abgerufen, nämlich das in Zeile 23;
- Zeile 16: Dieses Formular wird gesendet. Letztendlich läuft alles so ab, als hätte man auf eine Schaltfläche vom Typ [submit] geklickt. Das Formular wird an den in Zeile 23 angegebenen Controller und die dort angegebene Aktion gesendet;
- Zeile 30: Ein Navigationslink. Der generierte Code HTML lautet wie folgt:
<a href="/Second/Action17Get">Page 2</a>
Die verwendete Methode ist ActionLink(Text, Aktion, Controller).
Seite 2 wird durch die folgende Ansicht [Action17Get.cshtml] generiert:
@{
Layout = null;
}
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width" />
<title>Action17Get</title>
</head>
<body>
<h3>Navigation - Page 2</h3>
<h4>@ViewBag.info</h4>
<p>
@Html.ActionLink("Page 1", "Action16Get", "Second")
</p>
</body>
</html>
Die Aktionen, die diese Ansichten generieren, lauten wie folgt:
// Aktion16-GET
[HttpGet]
public ViewResult Action16Get()
{
ViewBag.info = string.Format("Contrôleur={0}, Action={1}", RouteData.Values["controller"], RouteData.Values["action"]);
return View("Action16Get");
}
// Aktion16-POST
[HttpPost]
public ViewResult Action16Post(string data)
{
ViewBag.info = string.Format("Contrôleur={0}, Action={1}, Data={2}", RouteData.Values["controller"], RouteData.Values["action"], data);
return View("Action16Get");
}
// Aktion17-GET
[HttpGet]
public ViewResult Action17Get()
{
ViewBag.info = string.Format("Contrôleur={0}, Action={1}", RouteData.Values["controller"], RouteData.Values["action"]);
return View();
}
- In Zeile 6 generiert die Aktion [Action16Get] die Ansicht [Action16Get.cshtml], d. h. Seite 1 des Beispiels. Diese Ansicht basiert auf der Vorlage [ViewBag] (Zeile 5);
- Zeile 19: Die Aktion [Action17Get] generiert die Ansicht [Action17Get.cshtml], d. h. Seite 2 des Beispiels. Diese Ansicht basiert auf der Vorlage [ViewBag] (Zeile 21);
- Zeile 11: Die Aktion [Action16Post] verarbeitet das Feld POST aus dem Formular der Ansicht [Action16Get.cshtml]. Sie erhält den Parameter mit dem Namen [data]. Zur Erinnerung: Dies ist der Name des Eingabefelds im Formular;
- Zeile 13: Eine Information wird in das Feld [ViewBag] geschrieben;
- Zeile 14: Die Ansicht [Action16Get.cshtml] wird angezeigt.
Der Leser ist eingeladen, dieses Beispiel auszuprobieren.































































