Part 3: Gerüstbau mit Razor Pages in ASP.NET Core
Hinweis
Dies ist nicht die neueste Version dieses Artikels. Die aktuelle Version finden Sie in der .NET 9-Version dieses Artikels.
Warnung
Diese Version von ASP.NET Core wird nicht mehr unterstützt. Weitere Informationen finden Sie in der Supportrichtlinie für .NET und .NET Core. Informationen zum aktuellen Release finden Sie in der .NET 8-Version dieses Artikels.
Wichtig
Diese Informationen beziehen sich auf ein Vorabversionsprodukt, das vor der kommerziellen Freigabe möglicherweise noch wesentlichen Änderungen unterliegt. Microsoft gibt keine Garantie, weder ausdrücklich noch impliziert, hinsichtlich der hier bereitgestellten Informationen.
Die aktuelle Version finden Sie in der .NET 9-Version dieses Artikels.
Von Rick Anderson
In diesem Tutorial werden die Razor Pages näher untersucht, die durch den Gerüstbau im vorherigen Tutorial erstellt wurden.
Die Seiten „Create“, „Delete“, „Details“ und „Edit“
Betrachten Sie das Modell der Pages/Movies/Index.cshtml.cs
-Seite:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.EntityFrameworkCore;
using RazorPagesMovie.Data;
using RazorPagesMovie.Models;
using Microsoft.AspNetCore.Mvc.Rendering;
namespace RazorPagesMovie.Pages.Movies
{
public class IndexModel : PageModel
{
private readonly RazorPagesMovie.Data.RazorPagesMovieContext _context;
public IndexModel(RazorPagesMovie.Data.RazorPagesMovieContext context)
{
_context = context;
}
public IList<Movie> Movie { get;set; } = default!;
public async Task OnGetAsync()
{
Movie = await _context.Movie.ToListAsync();
}
}
}
Razor-Seiten werden von PageModel abgeleitet. Gemäß der Konvention wird die von PageModel
abgeleitete Klasse PageNameModel
genannt. Die Indexseite heißt beispielsweise IndexModel
.
Der Konstruktor verwendet Abhängigkeitsinjektion, um RazorPagesMovieContext
zur Seite hinzuzufügen:
public class IndexModel : PageModel
{
private readonly RazorPagesMovie.Data.RazorPagesMovieContext _context;
public IndexModel(RazorPagesMovie.Data.RazorPagesMovieContext context)
{
_context = context;
}
Weitere Informationen zum asynchronen Programmieren mit Entity Framework finden Sie unter Asynchroner Code.
Wenn eine GET
-Anforderung für die Seite erfolgt, gibt die OnGetAsync
-Methode eine Filmliste an die Razor-Seite zurück. Auf einer Razor Page wird OnGetAsync
oder OnGet
aufgerufen, um den Status der Seite zu initialisieren. In diesem Fall ruft OnGetAsync
eine Liste von Filmen ab und zeigt diese an.
Wenn void
von OnGet
oder Task
von OnGetAsync
zurückgegeben wird, wird keine Rückgabeanweisung verwendet. Sehen Sie sich beispielsweise die Seite Privacy an:
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
namespace RazorPagesMovie.Pages
{
public class PrivacyModel : PageModel
{
private readonly ILogger<PrivacyModel> _logger;
public PrivacyModel(ILogger<PrivacyModel> logger)
{
_logger = logger;
}
public void OnGet()
{
}
}
}
Wenn der Rückgabetyp IActionResult oder Task<IActionResult>
ist, muss eine Rückgabeanweisung bereitgestellt werden. Ein Beispiel ist die Pages/Movies/Create.cshtml.cs OnPostAsync
-Methode:
public async Task<IActionResult> OnPostAsync()
{
if (!ModelState.IsValid)
{
return Page();
}
_context.Movie.Add(Movie);
await _context.SaveChangesAsync();
return RedirectToPage("./Index");
}
Betrachten Sie die Pages/Movies/Index.cshtml
Razor-Seite:
@page
@model RazorPagesMovie.Pages.Movies.IndexModel
@{
ViewData["Title"] = "Index";
}
<h1>Index</h1>
<p>
<a asp-page="Create">Create New</a>
</p>
<table class="table">
<thead>
<tr>
<th>
@Html.DisplayNameFor(model => model.Movie[0].Title)
</th>
<th>
@Html.DisplayNameFor(model => model.Movie[0].ReleaseDate)
</th>
<th>
@Html.DisplayNameFor(model => model.Movie[0].Genre)
</th>
<th>
@Html.DisplayNameFor(model => model.Movie[0].Price)
</th>
<th></th>
</tr>
</thead>
<tbody>
@foreach (var item in Model.Movie) {
<tr>
<td>
@Html.DisplayFor(modelItem => item.Title)
</td>
<td>
@Html.DisplayFor(modelItem => item.ReleaseDate)
</td>
<td>
@Html.DisplayFor(modelItem => item.Genre)
</td>
<td>
@Html.DisplayFor(modelItem => item.Price)
</td>
<td>
<a asp-page="./Edit" asp-route-id="@item.Id">Edit</a> |
<a asp-page="./Details" asp-route-id="@item.Id">Details</a> |
<a asp-page="./Delete" asp-route-id="@item.Id">Delete</a>
</td>
</tr>
}
</tbody>
</table>
Razor kann aus HTML in C# oder ein Razor-spezifisches Markup übergehen. Wenn auf ein @
-Symbol ein für Razor reserviertes Schlüsselwort folgt, wechselt es in ein Razor-spezifisches Markup. Andernfalls geht es in C# über.
Die @page -Direktive
Die Razor-Anweisung @page
wandelt die Datei in eine MVC-Aktion um. Das bedeutet, dass sie Anforderungen verarbeiten kann. @page
muss die erste Razor-Anweisung auf einer Seite sein. @page
und @model
sind Beispiele für einen Übergang in ein für Razor spezifisches Markup. Unter Razor-Syntax finden Sie weitere Informationen.
Die @model -Direktive
@page
@model RazorPagesMovie.Pages.Movies.IndexModel
Die @model
-Anweisung gibt den Typ des Modells an, das an die Razor-Seite weitergegeben wird. Im vorherigen Beispiel macht die Zeile @model
die von PageModel
abgeleitete Klasse für die Razor Page verfügbar. Das Modell wird in den HTML-Hilfsprogrammen @Html.DisplayNameFor
und @Html.DisplayFor
auf der Seite verwendet.
Überprüfen Sie den Lambdaausdruck, der im folgenden HTML-Hilfsprogramm verwendet wird:
@Html.DisplayNameFor(model => model.Movie[0].Title)
Das HTML-Hilfsprogramm DisplayNameFor überprüft die Eigenschaft Title
, auf die im Lambdaausdruck verwiesen wird, um den Anzeigenamen zu bestimmen. Der Lambdaausdruck wird überprüft und nicht ausgewertet. Das bedeutet, dass keine Zugriffsverletzung auftritt, wenn model
, model.Movie
oder model.Movie[0]
null
oder leer ist. Wenn der Lambdaausdruck ausgewertet wird, (z.B. mit @Html.DisplayFor(modelItem => item.Title)
), werden die Eigenschaftswerte ausgewertet.
Die Seite „Layout“
Wählen Sie die Menülinks aus (RazorPagesMovie, Home und Privacy). Auf jeder Seite wird dasselbe Menülayout gezeigt. Das Menülayout wird mithilfe der Datei Pages/Shared/_Layout.cshtml
implementiert.
Öffnen Sie die Datei, und untersuchen Sie die Datei Pages/Shared/_Layout.cshtml
.
Durch Layout-Vorlagen kann das HTML-Containerlayout:
- An einem Ort angegeben werden.
- Auf mehreren Seiten der Website angewendet werden.
Suchen Sie die Zeile @RenderBody()
. RenderBody
ist ein Platzhalter, bei dem alle seitenspezifischen Ansichten von der Layoutseite umschlossen angezeigt werden. Wenn Sie beispielsweise den Link Privacy auswählen, wird die Ansicht Pages/Privacy.cshtml
in der RenderBody
-Methode gerendert.
ViewData und Layout
Sehen Sie sich das folgenden Markup aus der Datei Pages/Movies/Index.cshtml
an:
@page
@model RazorPagesMovie.Pages.Movies.IndexModel
@{
ViewData["Title"] = "Index";
}
Das oben markierte Markup ist ein Beispiel vom Übergang von Razor in C#. Die Zeichen {
und }
schließen einen Block mit C#-Code ein.
Die Basisklasse PageModel
verfügt über eine ViewData
-Wörterbucheigenschaft, die zum Übergeben von Daten an eine Ansicht verwendet werden kann. Mithilfe eines Schlüssel-Wert-Musters können dem ViewData
-Wörterbuch Objekte hinzugefügt werden. Im vorherigen Beispiel wurde dem Title
-Wörterbuch die Eigenschaft ViewData
hinzugefügt.
Die Title
-Eigenschaft wird in der Pages/Shared/_Layout.cshtml
-Datei verwendet. Das folgende Markup zeigt die ersten Zeilen der Datei _Layout.cshtml
an.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>@ViewData["Title"] - RazorPagesMovie</title>
<link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.css" />
<link rel="stylesheet" href="~/css/site.css" asp-append-version="true" />
<link rel="stylesheet" href="~/RazorPagesMovie.styles.css" asp-append-version="true" />
Aktualisieren des Layouts
Ändern Sie das
<title>
-Element in der DateiPages/Shared/_Layout.cshtml
so, dass es Movie anstelle von RazorPagesMovie anzeigt.<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>@ViewData["Title"] - Movie</title>
Suchen Sie in der Datei
Pages/Shared/_Layout.cshtml
das folgende Ankerelement.<a class="navbar-brand" asp-area="" asp-page="/Index">RazorPagesMovie</a>
Ersetzen Sie das vorhergehende Element durch das folgende Markup.
<a class="navbar-brand" asp-page="/Movies/Index">RpMovie</a>
Das vorangehende Ankerelement ist ein Tag Helper (Taghilfsprogramm). In diesem Fall handelt es sich um ein Anchor Tag Helper (Anchor-Taghilfsprogramm). Taghilfsattribut und -wert
asp-page="/Movies/Index"
erstellen einen Link zur Razor-Seite/Movies/Index
. Dasasp-area
-Attribut ist leer, daher wird der Bereich im Link nicht verwendet. Weitere Informationen finden Sie unter Bereiche.Speichern Sie Ihre Änderungen, und testen Sie die App, indem Sie den Link RpMovie auswählen. Wenn Probleme auftreten, sehen Sie sich die Datei _Layout.cshtml in GitHub an.
Testen Sie die folgenden Links: Home, RpMovie, Create (Erstellen), Edit (Bearbeiten) und Delete (Löschen). Jede Seite legt den Titel fest, der in der Browserregisterkarte angezeigt wird. Wenn Sie eine Seite mit einem Lesezeichen versehen, wird dieser Titel für das Lesezeichen verwendet.
Hinweis
Sie können unter Umständen in das Feld Price
keine Kommas als Dezimaltrennzeichen eingeben. Zur Unterstützung der jQuery-Validierung für nicht englische Gebietsschemas, in denen ein Komma („,“) als Dezimaltrennzeichen verwendet wird, und Nicht-US-englische Datums- und Uhrzeitformate müssen Sie Schritte zur Globalisierung der App ausführen. In diesem GitHub-Problem 4076 finden Sie Anweisungen zum Hinzufügen von Kommas als Dezimaltrennzeichen.
Die Layout
-Eigenschaft wird in der Pages/_ViewStart.cshtml
-Datei festgelegt:
@{
Layout = "_Layout";
}
Das vorhergehende Markup legt die Layoutdatei auf Pages/Shared/_Layout.cshtml
für alle Razor-Dateien unter dem Ordner Pages fest. Weitere Informationen finden Sie unter Layout.
Das Seitenmodell „Create“
Überprüfen Sie das Seitenmodell Pages/Movies/Create.cshtml.cs
:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.AspNetCore.Mvc.Rendering;
using RazorPagesMovie.Data;
using RazorPagesMovie.Models;
namespace RazorPagesMovie.Pages.Movies
{
public class CreateModel : PageModel
{
private readonly RazorPagesMovie.Data.RazorPagesMovieContext _context;
public CreateModel(RazorPagesMovie.Data.RazorPagesMovieContext context)
{
_context = context;
}
public IActionResult OnGet()
{
return Page();
}
[BindProperty]
public Movie Movie { get; set; } = default!;
// To protect from overposting attacks, see https://aka.ms/RazorPagesCRUD
public async Task<IActionResult> OnPostAsync()
{
if (!ModelState.IsValid)
{
return Page();
}
_context.Movie.Add(Movie);
await _context.SaveChangesAsync();
return RedirectToPage("./Index");
}
}
}
Die Methode OnGet
initialisiert einen beliebigen Zustand, der für die Seite erforderlich ist. Die Seite „Create“ (Erstellen) verfügt nicht über einen initialisierbaren Zustand. Deshalb wird Page
zurückgegeben. Später in diesem Tutorial wird ein Beispiel für OnGet
zur Initialisierung des Zustands gezeigt. Die Methode Page
erstellt ein PageResult
-Objekt, das die Seite Create.cshtml
rendert.
Die Eigenschaft Movie
verwendet das Attribut [BindProperty], um die Modellbindung zu aktivieren. Wenn das Formular „Create“ die Formularwerte bereitstellt, bindet die ASP.NET Core-Laufzeit die bereitgestellten Werte an das Movie
-Modell.
Die Methode OnPostAsync
wird ausgeführt, wenn die Seite Formulardaten bereitstellt:
public async Task<IActionResult> OnPostAsync()
{
if (!ModelState.IsValid)
{
return Page();
}
_context.Movie.Add(Movie);
await _context.SaveChangesAsync();
return RedirectToPage("./Index");
}
Wenn es zu Modellfehlern kommt, wird das Formular mit allen bereitgestellten Formulardaten erneut angezeigt. Die meisten Modellfehler können clientseitig abgefangen werden, bevor das Formular bereitgestellt wird. Ein Beispiel für einen Modellfehler ist die Bereitstellung eines Werts für das Datumsfeld, der nicht in ein Datum konvertiert werden kann. Die clientseitige Validierung und die Modellvalidierung werden später in diesem Tutorial erläutert.
Wenn keine Modellfehler vorliegen:
- Die Daten werden gespeichert.
- Der Browser wird zur Indexseite umgeleitet.
Razor-Seite „Erstellen“
Betrachten Sie die Datei Pages/Movies/Create.cshtml
der Razor-Seite:
@page
@model RazorPagesMovie.Pages.Movies.CreateModel
@{
ViewData["Title"] = "Create";
}
<h1>Create</h1>
<h4>Movie</h4>
<hr />
<div class="row">
<div class="col-md-4">
<form method="post">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group">
<label asp-for="Movie.Title" class="control-label"></label>
<input asp-for="Movie.Title" class="form-control" />
<span asp-validation-for="Movie.Title" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Movie.ReleaseDate" class="control-label"></label>
<input asp-for="Movie.ReleaseDate" class="form-control" />
<span asp-validation-for="Movie.ReleaseDate" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Movie.Genre" class="control-label"></label>
<input asp-for="Movie.Genre" class="form-control" />
<span asp-validation-for="Movie.Genre" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Movie.Price" class="control-label"></label>
<input asp-for="Movie.Price" class="form-control" />
<span asp-validation-for="Movie.Price" class="text-danger"></span>
</div>
<div class="form-group">
<input type="submit" value="Create" class="btn btn-primary" />
</div>
</form>
</div>
</div>
<div>
<a asp-page="Index">Back to List</a>
</div>
@section Scripts {
@{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}
Visual Studio zeigt die folgenden Tags in einer bestimmten Schriftart an, die für Taghilfsprogramme verwendet wird:
<form method="post">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<label asp-for="Movie.Title" class="control-label"></label>
<input asp-for="Movie.Title" class="form-control" />
<span asp-validation-for="Movie.Title" class="text-danger"></span>
Das Element <form method="post">
ist ein Form Tag Helper (Hilfsprogramm für Formulartags). Das Hilfsprogramm für Formulartags enthält automatisch ein antiforgery token (Antifälschungstoken).
Die Gerüstbau-Engine erstellt Razor-Markup für jedes Feld im Modell (ausgenommen die ID) ähnlich wie folgt:
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group">
<label asp-for="Movie.Title" class="control-label"></label>
<input asp-for="Movie.Title" class="form-control" />
<span asp-validation-for="Movie.Title" class="text-danger"></span>
</div>
Das Hilfsprogramm für Validierungstags (<div asp-validation-summary
und <span asp-validation-for
) zeigt Validierungsfehler. Die Validierung wird an späterer Stelle in dieser Reihe detaillierter beschrieben.
Das Label Tag Helper (Taghilfsprogramm für Label) (<label asp-for="Movie.Title" class="control-label"></label>
) generiert den Titel des Labels und das [for]
-Attribut für die Eigenschaft Title
.
Das Hilfsprogramm für Eingabetags (<input asp-for="Movie.Title" class="form-control">
) verwendet die Attribute von DataAnnotations und generiert HTML-Attribute, die auf der Clientseite für die jQuery-Validierung erforderlich sind.
Weitere Informationen zu Taghilfsprogrammen wie <form method="post">
finden Sie unter Taghilfsprogramme in ASP.NET Core.
Nächste Schritte
Die Seiten „Create“, „Delete“, „Details“ und „Edit“
Betrachten Sie das Modell der Pages/Movies/Index.cshtml.cs
-Seite:
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.EntityFrameworkCore;
using RazorPagesMovie.Models;
namespace RazorPagesMovie.Pages.Movies;
public class IndexModel : PageModel
{
private readonly RazorPagesMovie.Data.RazorPagesMovieContext _context;
public IndexModel(RazorPagesMovie.Data.RazorPagesMovieContext context)
{
_context = context;
}
public IList<Movie> Movie { get;set; } = default!;
public async Task OnGetAsync()
{
if (_context.Movie != null)
{
Movie = await _context.Movie.ToListAsync();
}
}
}
Razor-Seiten werden von PageModel abgeleitet. Gemäß der Konvention wird die von PageModel
abgeleitete Klasse PageNameModel
genannt. Die Indexseite heißt beispielsweise IndexModel
.
Der Konstruktor verwendet Abhängigkeitsinjektion, um RazorPagesMovieContext
zur Seite hinzuzufügen:
public class IndexModel : PageModel
{
private readonly RazorPagesMovie.Data.RazorPagesMovieContext _context;
public IndexModel(RazorPagesMovie.Data.RazorPagesMovieContext context)
{
_context = context;
}
Weitere Informationen zum asynchronen Programmieren mit Entity Framework finden Sie unter Asynchroner Code.
Wenn eine GET
-Anforderung für die Seite erfolgt, gibt die OnGetAsync
-Methode eine Filmliste an die Razor-Seite zurück. Auf einer Razor Page wird OnGetAsync
oder OnGet
aufgerufen, um den Status der Seite zu initialisieren. In diesem Fall ruft OnGetAsync
eine Liste von Filmen ab und zeigt diese an.
Wenn void
von OnGet
oder Task
von OnGetAsync
zurückgegeben wird, wird keine Rückgabeanweisung verwendet. Sehen Sie sich beispielsweise die Seite Privacy an:
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
namespace RazorPagesMovie.Pages
{
public class PrivacyModel : PageModel
{
private readonly ILogger<PrivacyModel> _logger;
public PrivacyModel(ILogger<PrivacyModel> logger)
{
_logger = logger;
}
public void OnGet()
{
}
}
}
Wenn der Rückgabetyp IActionResult oder Task<IActionResult>
ist, muss eine Rückgabeanweisung bereitgestellt werden. Ein Beispiel ist die Pages/Movies/Create.cshtml.cs OnPostAsync
-Methode:
public async Task<IActionResult> OnPostAsync()
{
if (!ModelState.IsValid)
{
return Page();
}
_context.Movie.Add(Movie);
await _context.SaveChangesAsync();
return RedirectToPage("./Index");
}
Betrachten Sie die Pages/Movies/Index.cshtml
Razor-Seite:
@page
@model RazorPagesMovie.Pages.Movies.IndexModel
@{
ViewData["Title"] = "Index";
}
<h1>Index</h1>
<p>
<a asp-page="Create">Create New</a>
</p>
<table class="table">
<thead>
<tr>
<th>
@Html.DisplayNameFor(model => model.Movie[0].Title)
</th>
<th>
@Html.DisplayNameFor(model => model.Movie[0].ReleaseDate)
</th>
<th>
@Html.DisplayNameFor(model => model.Movie[0].Genre)
</th>
<th>
@Html.DisplayNameFor(model => model.Movie[0].Price)
</th>
<th></th>
</tr>
</thead>
<tbody>
@foreach (var item in Model.Movie) {
<tr>
<td>
@Html.DisplayFor(modelItem => item.Title)
</td>
<td>
@Html.DisplayFor(modelItem => item.ReleaseDate)
</td>
<td>
@Html.DisplayFor(modelItem => item.Genre)
</td>
<td>
@Html.DisplayFor(modelItem => item.Price)
</td>
<td>
<a asp-page="./Edit" asp-route-id="@item.Id">Edit</a> |
<a asp-page="./Details" asp-route-id="@item.Id">Details</a> |
<a asp-page="./Delete" asp-route-id="@item.Id">Delete</a>
</td>
</tr>
}
</tbody>
</table>
Razor kann aus HTML in C# oder ein Razor-spezifisches Markup übergehen. Wenn auf ein @
-Symbol ein für Razor reserviertes Schlüsselwort folgt, wechselt es in ein Razor-spezifisches Markup. Andernfalls geht es in C# über.
Die @page -Direktive
Die Razor-Anweisung @page
wandelt die Datei in eine MVC-Aktion um. Das bedeutet, dass sie Anforderungen verarbeiten kann. @page
muss die erste Razor-Anweisung auf einer Seite sein. @page
und @model
sind Beispiele für einen Übergang in ein für Razor spezifisches Markup. Unter Razor-Syntax finden Sie weitere Informationen.
Die @model -Direktive
@page
@model RazorPagesMovie.Pages.Movies.IndexModel
Die @model
-Anweisung gibt den Typ des Modells an, das an die Razor-Seite weitergegeben wird. Im vorherigen Beispiel macht die Zeile @model
die von PageModel
abgeleitete Klasse für die Razor Page verfügbar. Das Modell wird in den HTML-Hilfsprogrammen @Html.DisplayNameFor
und @Html.DisplayFor
auf der Seite verwendet.
Überprüfen Sie den Lambdaausdruck, der im folgenden HTML-Hilfsprogramm verwendet wird:
@Html.DisplayNameFor(model => model.Movie[0].Title)
Das HTML-Hilfsprogramm DisplayNameFor überprüft die Eigenschaft Title
, auf die im Lambdaausdruck verwiesen wird, um den Anzeigenamen zu bestimmen. Der Lambdaausdruck wird überprüft und nicht ausgewertet. Das bedeutet, dass keine Zugriffsverletzung auftritt, wenn model
, model.Movie
oder model.Movie[0]
null
oder leer ist. Wenn der Lambdaausdruck ausgewertet wird, (z.B. mit @Html.DisplayFor(modelItem => item.Title)
), werden die Eigenschaftswerte ausgewertet.
Die Seite „Layout“
Wählen Sie die Menülinks aus (RazorPagesMovie, Home und Privacy). Auf jeder Seite wird dasselbe Menülayout gezeigt. Das Menülayout wird mithilfe der Datei Pages/Shared/_Layout.cshtml
implementiert.
Öffnen Sie die Datei, und untersuchen Sie die Datei Pages/Shared/_Layout.cshtml
.
Durch Layout-Vorlagen kann das HTML-Containerlayout:
- An einem Ort angegeben werden.
- Auf mehreren Seiten der Website angewendet werden.
Suchen Sie die Zeile @RenderBody()
. RenderBody
ist ein Platzhalter, bei dem alle seitenspezifischen Ansichten von der Layoutseite umschlossen angezeigt werden. Wenn Sie beispielsweise den Link Privacy auswählen, wird die Ansicht Pages/Privacy.cshtml
in der RenderBody
-Methode gerendert.
ViewData und Layout
Sehen Sie sich das folgenden Markup aus der Datei Pages/Movies/Index.cshtml
an:
@page
@model RazorPagesMovie.Pages.Movies.IndexModel
@{
ViewData["Title"] = "Index";
}
Das oben markierte Markup ist ein Beispiel vom Übergang von Razor in C#. Die Zeichen {
und }
schließen einen Block mit C#-Code ein.
Die Basisklasse PageModel
verfügt über eine ViewData
-Wörterbucheigenschaft, die zum Übergeben von Daten an eine Ansicht verwendet werden kann. Mithilfe eines Schlüssel-Wert-Musters können dem ViewData
-Wörterbuch Objekte hinzugefügt werden. Im vorherigen Beispiel wurde dem Title
-Wörterbuch die Eigenschaft ViewData
hinzugefügt.
Die Title
-Eigenschaft wird in der Pages/Shared/_Layout.cshtml
-Datei verwendet. Das folgende Markup zeigt die ersten Zeilen der Datei _Layout.cshtml
an.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>@ViewData["Title"] - RazorPagesMovie</title>
<link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.min.css" />
<link rel="stylesheet" href="~/css/site.css" asp-append-version="true" />
<link rel="stylesheet" href="~/RazorPagesMovie.styles.css" asp-append-version="true" />
Aktualisieren des Layouts
Ändern Sie das
<title>
-Element in der DateiPages/Shared/_Layout.cshtml
so, dass es Movie anstelle von RazorPagesMovie anzeigt.<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>@ViewData["Title"] - Movie</title>
Suchen Sie in der Datei
Pages/Shared/_Layout.cshtml
das folgende Ankerelement.<a class="navbar-brand" asp-area="" asp-page="/Index">RazorPagesMovie</a>
Ersetzen Sie das vorhergehende Element durch das folgende Markup.
<a class="navbar-brand" asp-page="/Movies/Index">RpMovie</a>
Das vorangehende Ankerelement ist ein Tag Helper (Taghilfsprogramm). In diesem Fall handelt es sich um ein Anchor Tag Helper (Anchor-Taghilfsprogramm). Taghilfsattribut und -wert
asp-page="/Movies/Index"
erstellen einen Link zur Razor-Seite/Movies/Index
. Dasasp-area
-Attribut ist leer, daher wird der Bereich im Link nicht verwendet. Weitere Informationen finden Sie unter Bereiche.Speichern Sie Ihre Änderungen, und testen Sie die App, indem Sie den Link RpMovie auswählen. Wenn Probleme auftreten, sehen Sie sich die Datei _Layout.cshtml in GitHub an.
Testen Sie die folgenden Links: Home, RpMovie, Create (Erstellen), Edit (Bearbeiten) und Delete (Löschen). Jede Seite legt den Titel fest, der in der Browserregisterkarte angezeigt wird. Wenn Sie eine Seite mit einem Lesezeichen versehen, wird dieser Titel für das Lesezeichen verwendet.
Hinweis
Sie können unter Umständen in das Feld Price
keine Kommas als Dezimaltrennzeichen eingeben. Zur Unterstützung der jQuery-Validierung für nicht englische Gebietsschemas, in denen ein Komma („,“) als Dezimaltrennzeichen verwendet wird, und Nicht-US-englische Datums- und Uhrzeitformate müssen Sie Schritte zur Globalisierung der App ausführen. In diesem GitHub-Problem 4076 finden Sie Anweisungen zum Hinzufügen von Kommas als Dezimaltrennzeichen.
Die Layout
-Eigenschaft wird in der Pages/_ViewStart.cshtml
-Datei festgelegt:
@{
Layout = "_Layout";
}
Das vorhergehende Markup legt die Layoutdatei auf Pages/Shared/_Layout.cshtml
für alle Razor-Dateien unter dem Ordner Pages fest. Weitere Informationen finden Sie unter Layout.
Das Seitenmodell „Create“
Überprüfen Sie das Seitenmodell Pages/Movies/Create.cshtml.cs
:
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using RazorPagesMovie.Models;
namespace RazorPagesMovie.Pages.Movies
{
public class CreateModel : PageModel
{
private readonly RazorPagesMovie.Data.RazorPagesMovieContext _context;
public CreateModel(RazorPagesMovie.Data.RazorPagesMovieContext context)
{
_context = context;
}
public IActionResult OnGet()
{
return Page();
}
[BindProperty]
public Movie Movie { get; set; } = default!;
// To protect from overposting attacks, see https://aka.ms/RazorPagesCRUD
public async Task<IActionResult> OnPostAsync()
{
if (!ModelState.IsValid || _context.Movie == null || Movie == null)
{
return Page();
}
_context.Movie.Add(Movie);
await _context.SaveChangesAsync();
return RedirectToPage("./Index");
}
}
}
Die Methode OnGet
initialisiert einen beliebigen Zustand, der für die Seite erforderlich ist. Die Seite „Create“ (Erstellen) verfügt nicht über einen initialisierbaren Zustand. Deshalb wird Page
zurückgegeben. Später in diesem Tutorial wird ein Beispiel für OnGet
zur Initialisierung des Zustands gezeigt. Die Methode Page
erstellt ein PageResult
-Objekt, das die Seite Create.cshtml
rendert.
Die Eigenschaft Movie
verwendet das Attribut [BindProperty], um die Modellbindung zu aktivieren. Wenn das Formular „Create“ die Formularwerte bereitstellt, bindet die ASP.NET Core-Laufzeit die bereitgestellten Werte an das Movie
-Modell.
Die Methode OnPostAsync
wird ausgeführt, wenn die Seite Formulardaten bereitstellt:
public async Task<IActionResult> OnPostAsync()
{
if (!ModelState.IsValid)
{
return Page();
}
_context.Movie.Add(Movie);
await _context.SaveChangesAsync();
return RedirectToPage("./Index");
}
Wenn es zu Modellfehlern kommt, wird das Formular mit allen bereitgestellten Formulardaten erneut angezeigt. Die meisten Modellfehler können clientseitig abgefangen werden, bevor das Formular bereitgestellt wird. Ein Beispiel für einen Modellfehler ist die Bereitstellung eines Werts für das Datumsfeld, der nicht in ein Datum konvertiert werden kann. Die clientseitige Validierung und die Modellvalidierung werden später in diesem Tutorial erläutert.
Wenn keine Modellfehler vorliegen:
- Die Daten werden gespeichert.
- Der Browser wird zur Indexseite umgeleitet.
Razor-Seite „Erstellen“
Betrachten Sie die Datei Pages/Movies/Create.cshtml
der Razor-Seite:
@page
@model RazorPagesMovie.Pages.Movies.CreateModel
@{
ViewData["Title"] = "Create";
}
<h1>Create</h1>
<h4>Movie</h4>
<hr />
<div class="row">
<div class="col-md-4">
<form method="post">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group">
<label asp-for="Movie.Title" class="control-label"></label>
<input asp-for="Movie.Title" class="form-control" />
<span asp-validation-for="Movie.Title" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Movie.ReleaseDate" class="control-label"></label>
<input asp-for="Movie.ReleaseDate" class="form-control" />
<span asp-validation-for="Movie.ReleaseDate" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Movie.Genre" class="control-label"></label>
<input asp-for="Movie.Genre" class="form-control" />
<span asp-validation-for="Movie.Genre" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Movie.Price" class="control-label"></label>
<input asp-for="Movie.Price" class="form-control" />
<span asp-validation-for="Movie.Price" class="text-danger"></span>
</div>
<div class="form-group">
<input type="submit" value="Create" class="btn btn-primary" />
</div>
</form>
</div>
</div>
<div>
<a asp-page="Index">Back to List</a>
</div>
@section Scripts {
@{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}
Visual Studio zeigt die folgenden Tags in einer bestimmten Schriftart an, die für Taghilfsprogramme verwendet wird:
<form method="post">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<label asp-for="Movie.Title" class="control-label"></label>
<input asp-for="Movie.Title" class="form-control" />
<span asp-validation-for="Movie.Title" class="text-danger"></span>
Das Element <form method="post">
ist ein Form Tag Helper (Hilfsprogramm für Formulartags). Das Hilfsprogramm für Formulartags enthält automatisch ein antiforgery token (Antifälschungstoken).
Die Gerüstbau-Engine erstellt Razor-Markup für jedes Feld im Modell (ausgenommen die ID) ähnlich wie folgt:
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group">
<label asp-for="Movie.Title" class="control-label"></label>
<input asp-for="Movie.Title" class="form-control" />
<span asp-validation-for="Movie.Title" class="text-danger"></span>
</div>
Das Hilfsprogramm für Validierungstags (<div asp-validation-summary
und <span asp-validation-for
) zeigt Validierungsfehler. Die Validierung wird an späterer Stelle in dieser Reihe detaillierter beschrieben.
Das Label Tag Helper (Taghilfsprogramm für Label) (<label asp-for="Movie.Title" class="control-label"></label>
) generiert den Titel des Labels und das [for]
-Attribut für die Eigenschaft Title
.
Das Hilfsprogramm für Eingabetags (<input asp-for="Movie.Title" class="form-control">
) verwendet die Attribute von DataAnnotations und generiert HTML-Attribute, die auf der Clientseite für die jQuery-Validierung erforderlich sind.
Weitere Informationen zu Taghilfsprogrammen wie <form method="post">
finden Sie unter Taghilfsprogramme in ASP.NET Core.
Nächste Schritte
Die Seiten „Create“, „Delete“, „Details“ und „Edit“
Betrachten Sie das Modell der Pages/Movies/Index.cshtml.cs
-Seite:
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.EntityFrameworkCore;
using RazorPagesMovie.Models;
namespace RazorPagesMovie.Pages.Movies;
public class IndexModel : PageModel
{
private readonly RazorPagesMovie.Data.RazorPagesMovieContext _context;
public IndexModel(RazorPagesMovie.Data.RazorPagesMovieContext context)
{
_context = context;
}
public IList<Movie> Movie { get;set; } = default!;
public async Task OnGetAsync()
{
if (_context.Movie != null)
{
Movie = await _context.Movie.ToListAsync();
}
}
}
Razor-Seiten werden von PageModel abgeleitet. Gemäß der Konvention wird die von PageModel
abgeleitete Klasse PageNameModel
genannt. Die Indexseite heißt beispielsweise IndexModel
.
Der Konstruktor verwendet Abhängigkeitsinjektion, um RazorPagesMovieContext
zur Seite hinzuzufügen:
public class IndexModel : PageModel
{
private readonly RazorPagesMovie.Data.RazorPagesMovieContext _context;
public IndexModel(RazorPagesMovie.Data.RazorPagesMovieContext context)
{
_context = context;
}
Weitere Informationen zum asynchronen Programmieren mit Entity Framework finden Sie unter Asynchroner Code.
Wenn eine GET
-Anforderung für die Seite erfolgt, gibt die OnGetAsync
-Methode eine Filmliste an die Razor-Seite zurück. Auf einer Razor Page wird OnGetAsync
oder OnGet
aufgerufen, um den Status der Seite zu initialisieren. In diesem Fall ruft OnGetAsync
eine Liste von Filmen ab und zeigt diese an.
Wenn void
von OnGet
oder Task
von OnGetAsync
zurückgegeben wird, wird keine Rückgabeanweisung verwendet. Sehen Sie sich beispielsweise die Seite Privacy an:
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
namespace RazorPagesMovie.Pages
{
public class PrivacyModel : PageModel
{
private readonly ILogger<PrivacyModel> _logger;
public PrivacyModel(ILogger<PrivacyModel> logger)
{
_logger = logger;
}
public void OnGet()
{
}
}
}
Wenn der Rückgabetyp IActionResult oder Task<IActionResult>
ist, muss eine Rückgabeanweisung bereitgestellt werden. Ein Beispiel ist die Pages/Movies/Create.cshtml.cs OnPostAsync
-Methode:
public async Task<IActionResult> OnPostAsync()
{
if (!ModelState.IsValid)
{
return Page();
}
_context.Movie.Add(Movie);
await _context.SaveChangesAsync();
return RedirectToPage("./Index");
}
Betrachten Sie die Pages/Movies/Index.cshtml
Razor-Seite:
@page
@model RazorPagesMovie.Pages.Movies.IndexModel
@{
ViewData["Title"] = "Index";
}
<h1>Index</h1>
<p>
<a asp-page="Create">Create New</a>
</p>
<table class="table">
<thead>
<tr>
<th>
@Html.DisplayNameFor(model => model.Movie[0].Title)
</th>
<th>
@Html.DisplayNameFor(model => model.Movie[0].ReleaseDate)
</th>
<th>
@Html.DisplayNameFor(model => model.Movie[0].Genre)
</th>
<th>
@Html.DisplayNameFor(model => model.Movie[0].Price)
</th>
<th></th>
</tr>
</thead>
<tbody>
@foreach (var item in Model.Movie) {
<tr>
<td>
@Html.DisplayFor(modelItem => item.Title)
</td>
<td>
@Html.DisplayFor(modelItem => item.ReleaseDate)
</td>
<td>
@Html.DisplayFor(modelItem => item.Genre)
</td>
<td>
@Html.DisplayFor(modelItem => item.Price)
</td>
<td>
<a asp-page="./Edit" asp-route-id="@item.Id">Edit</a> |
<a asp-page="./Details" asp-route-id="@item.Id">Details</a> |
<a asp-page="./Delete" asp-route-id="@item.Id">Delete</a>
</td>
</tr>
}
</tbody>
</table>
Razor kann aus HTML in C# oder ein Razor-spezifisches Markup übergehen. Wenn auf ein @
-Symbol ein für Razor reserviertes Schlüsselwort folgt, wechselt es in ein Razor-spezifisches Markup. Andernfalls geht es in C# über.
Die @page -Direktive
Die Razor-Anweisung @page
wandelt die Datei in eine MVC-Aktion um. Das bedeutet, dass sie Anforderungen verarbeiten kann. @page
muss die erste Razor-Anweisung auf einer Seite sein. @page
und @model
sind Beispiele für einen Übergang in ein für Razor spezifisches Markup. Unter Razor-Syntax finden Sie weitere Informationen.
Die @model -Direktive
@page
@model RazorPagesMovie.Pages.Movies.IndexModel
Die @model
-Anweisung gibt den Typ des Modells an, das an die Razor-Seite weitergegeben wird. Im vorherigen Beispiel macht die Zeile @model
die von PageModel
abgeleitete Klasse für die Razor Page verfügbar. Das Modell wird in den HTML-Hilfsprogrammen @Html.DisplayNameFor
und @Html.DisplayFor
auf der Seite verwendet.
Überprüfen Sie den Lambdaausdruck, der im folgenden HTML-Hilfsprogramm verwendet wird:
@Html.DisplayNameFor(model => model.Movie[0].Title)
Das HTML-Hilfsprogramm DisplayNameFor überprüft die Eigenschaft Title
, auf die im Lambdaausdruck verwiesen wird, um den Anzeigenamen zu bestimmen. Der Lambdaausdruck wird überprüft und nicht ausgewertet. Das bedeutet, dass keine Zugriffsverletzung auftritt, wenn model
, model.Movie
oder model.Movie[0]
null
oder leer ist. Wenn der Lambdaausdruck ausgewertet wird, (z.B. mit @Html.DisplayFor(modelItem => item.Title)
), werden die Eigenschaftswerte ausgewertet.
Die Seite „Layout“
Wählen Sie die Menülinks aus (RazorPagesMovie, Home und Privacy). Auf jeder Seite wird dasselbe Menülayout gezeigt. Das Menülayout wird mithilfe der Datei Pages/Shared/_Layout.cshtml
implementiert.
Öffnen Sie die Datei, und untersuchen Sie die Datei Pages/Shared/_Layout.cshtml
.
Durch Layout-Vorlagen kann das HTML-Containerlayout:
- An einem Ort angegeben werden.
- Auf mehreren Seiten der Website angewendet werden.
Suchen Sie die Zeile @RenderBody()
. RenderBody
ist ein Platzhalter, bei dem alle seitenspezifischen Ansichten von der Layoutseite umschlossen angezeigt werden. Wenn Sie beispielsweise den Link Privacy auswählen, wird die Ansicht Pages/Privacy.cshtml
in der RenderBody
-Methode gerendert.
ViewData und Layout
Sehen Sie sich das folgenden Markup aus der Datei Pages/Movies/Index.cshtml
an:
@page
@model RazorPagesMovie.Pages.Movies.IndexModel
@{
ViewData["Title"] = "Index";
}
Das oben markierte Markup ist ein Beispiel vom Übergang von Razor in C#. Die Zeichen {
und }
schließen einen Block mit C#-Code ein.
Die Basisklasse PageModel
verfügt über eine ViewData
-Wörterbucheigenschaft, die zum Übergeben von Daten an eine Ansicht verwendet werden kann. Mithilfe eines Schlüssel-Wert-Musters können dem ViewData
-Wörterbuch Objekte hinzugefügt werden. Im vorherigen Beispiel wurde dem Title
-Wörterbuch die Eigenschaft ViewData
hinzugefügt.
Die Title
-Eigenschaft wird in der Pages/Shared/_Layout.cshtml
-Datei verwendet. Das folgende Markup zeigt die ersten Zeilen der Datei _Layout.cshtml
an.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>@ViewData["Title"] - RazorPagesMovie</title>
<link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.min.css" />
<link rel="stylesheet" href="~/css/site.css" asp-append-version="true" />
<link rel="stylesheet" href="~/RazorPagesMovie.styles.css" asp-append-version="true" />
Die Zeile @*Markup removed for brevity.*@
ist ein Razor-Kommentar. Im Gegensatz zu HTML-Kommentaren (<!-- -->
) werden Razor-Kommentare nicht an den Client gesendet. Weitere Informationen finden Sie unter MDN-Webdokumentation: Erste Schritte mit HTML.
Aktualisieren des Layouts
Ändern Sie das
<title>
-Element in der DateiPages/Shared/_Layout.cshtml
so, dass es Movie anstelle von RazorPagesMovie anzeigt.<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>@ViewData["Title"] - Movie</title>
Suchen Sie in der Datei
Pages/Shared/_Layout.cshtml
das folgende Ankerelement.<a class="navbar-brand" asp-area="" asp-page="/Index">RazorPagesMovie</a>
Ersetzen Sie das vorhergehende Element durch das folgende Markup.
<a class="navbar-brand" asp-page="/Movies/Index">RpMovie</a>
Das vorangehende Ankerelement ist ein Tag Helper (Taghilfsprogramm). In diesem Fall handelt es sich um ein Anchor Tag Helper (Anchor-Taghilfsprogramm). Taghilfsattribut und -wert
asp-page="/Movies/Index"
erstellen einen Link zur Razor-Seite/Movies/Index
. Dasasp-area
-Attribut ist leer, daher wird der Bereich im Link nicht verwendet. Weitere Informationen finden Sie unter Bereiche.Speichern Sie Ihre Änderungen, und testen Sie die App, indem Sie den Link RpMovie auswählen. Wenn Probleme auftreten, sehen Sie sich die Datei _Layout.cshtml in GitHub an.
Testen Sie die folgenden Links: Home, RpMovie, Create (Erstellen), Edit (Bearbeiten) und Delete (Löschen). Jede Seite legt den Titel fest, der in der Browserregisterkarte angezeigt wird. Wenn Sie eine Seite mit einem Lesezeichen versehen, wird dieser Titel für das Lesezeichen verwendet.
Hinweis
Sie können unter Umständen in das Feld Price
keine Kommas als Dezimaltrennzeichen eingeben. Zur Unterstützung der jQuery-Validierung für nicht englische Gebietsschemas, in denen ein Komma („,“) als Dezimaltrennzeichen verwendet wird, und Nicht-US-englische Datums- und Uhrzeitformate müssen Sie Schritte zur Globalisierung der App ausführen. In diesem GitHub-Problem 4076 finden Sie Anweisungen zum Hinzufügen von Kommas als Dezimaltrennzeichen.
Die Layout
-Eigenschaft wird in der Pages/_ViewStart.cshtml
-Datei festgelegt:
@{
Layout = "_Layout";
}
Das vorhergehende Markup legt die Layoutdatei auf Pages/Shared/_Layout.cshtml
für alle Razor-Dateien unter dem Ordner Pages fest. Weitere Informationen finden Sie unter Layout.
Das Seitenmodell „Create“
Überprüfen Sie das Seitenmodell Pages/Movies/Create.cshtml.cs
:
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using RazorPagesMovie.Models;
namespace RazorPagesMovie.Pages.Movies
{
public class CreateModel : PageModel
{
private readonly RazorPagesMovie.Data.RazorPagesMovieContext _context;
public CreateModel(RazorPagesMovie.Data.RazorPagesMovieContext context)
{
_context = context;
}
public IActionResult OnGet()
{
return Page();
}
[BindProperty]
public Movie Movie { get; set; } = default!;
// To protect from overposting attacks, see https://aka.ms/RazorPagesCRUD
public async Task<IActionResult> OnPostAsync()
{
if (!ModelState.IsValid || _context.Movie == null || Movie == null)
{
return Page();
}
_context.Movie.Add(Movie);
await _context.SaveChangesAsync();
return RedirectToPage("./Index");
}
}
}
Die Methode OnGet
initialisiert einen beliebigen Zustand, der für die Seite erforderlich ist. Die Seite „Create“ (Erstellen) verfügt nicht über einen initialisierbaren Zustand. Deshalb wird Page
zurückgegeben. Später in diesem Tutorial wird ein Beispiel für OnGet
zur Initialisierung des Zustands gezeigt. Die Methode Page
erstellt ein PageResult
-Objekt, das die Seite Create.cshtml
rendert.
Die Eigenschaft Movie
verwendet das Attribut [BindProperty], um die Modellbindung zu aktivieren. Wenn das Formular „Create“ die Formularwerte bereitstellt, bindet die ASP.NET Core-Laufzeit die bereitgestellten Werte an das Movie
-Modell.
Die Methode OnPostAsync
wird ausgeführt, wenn die Seite Formulardaten bereitstellt:
public async Task<IActionResult> OnPostAsync()
{
if (!ModelState.IsValid)
{
return Page();
}
_context.Movie.Add(Movie);
await _context.SaveChangesAsync();
return RedirectToPage("./Index");
}
Wenn es zu Modellfehlern kommt, wird das Formular mit allen bereitgestellten Formulardaten erneut angezeigt. Die meisten Modellfehler können clientseitig abgefangen werden, bevor das Formular bereitgestellt wird. Ein Beispiel für einen Modellfehler ist die Bereitstellung eines Werts für das Datumsfeld, der nicht in ein Datum konvertiert werden kann. Die clientseitige Validierung und die Modellvalidierung werden später in diesem Tutorial erläutert.
Wenn keine Modellfehler vorliegen:
- Die Daten werden gespeichert.
- Der Browser wird zur Indexseite umgeleitet.
Razor-Seite „Erstellen“
Betrachten Sie die Datei Pages/Movies/Create.cshtml
der Razor-Seite:
@page
@model RazorPagesMovie.Pages.Movies.CreateModel
@{
ViewData["Title"] = "Create";
}
<h1>Create</h1>
<h4>Movie</h4>
<hr />
<div class="row">
<div class="col-md-4">
<form method="post">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group">
<label asp-for="Movie.Title" class="control-label"></label>
<input asp-for="Movie.Title" class="form-control" />
<span asp-validation-for="Movie.Title" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Movie.ReleaseDate" class="control-label"></label>
<input asp-for="Movie.ReleaseDate" class="form-control" />
<span asp-validation-for="Movie.ReleaseDate" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Movie.Genre" class="control-label"></label>
<input asp-for="Movie.Genre" class="form-control" />
<span asp-validation-for="Movie.Genre" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Movie.Price" class="control-label"></label>
<input asp-for="Movie.Price" class="form-control" />
<span asp-validation-for="Movie.Price" class="text-danger"></span>
</div>
<div class="form-group">
<input type="submit" value="Create" class="btn btn-primary" />
</div>
</form>
</div>
</div>
<div>
<a asp-page="Index">Back to List</a>
</div>
@section Scripts {
@{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}
Visual Studio zeigt die folgenden Tags in einer bestimmten Schriftart an, die für Taghilfsprogramme verwendet wird:
<form method="post">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<label asp-for="Movie.Title" class="control-label"></label>
<input asp-for="Movie.Title" class="form-control" />
<span asp-validation-for="Movie.Title" class="text-danger"></span>
Das Element <form method="post">
ist ein Form Tag Helper (Hilfsprogramm für Formulartags). Das Hilfsprogramm für Formulartags enthält automatisch ein antiforgery token (Antifälschungstoken).
Die Gerüstbau-Engine erstellt Razor-Markup für jedes Feld im Modell (ausgenommen die ID) ähnlich wie folgt:
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group">
<label asp-for="Movie.Title" class="control-label"></label>
<input asp-for="Movie.Title" class="form-control" />
<span asp-validation-for="Movie.Title" class="text-danger"></span>
</div>
Das Hilfsprogramm für Validierungstags (<div asp-validation-summary
und <span asp-validation-for
) zeigt Validierungsfehler. Die Validierung wird an späterer Stelle in dieser Reihe detaillierter beschrieben.
Das Label Tag Helper (Taghilfsprogramm für Label) (<label asp-for="Movie.Title" class="control-label"></label>
) generiert den Titel des Labels und das [for]
-Attribut für die Eigenschaft Title
.
Das Hilfsprogramm für Eingabetags (<input asp-for="Movie.Title" class="form-control">
) verwendet die Attribute von DataAnnotations und generiert HTML-Attribute, die auf der Clientseite für die jQuery-Validierung erforderlich sind.
Weitere Informationen zu Taghilfsprogrammen wie <form method="post">
finden Sie unter Taghilfsprogramme in ASP.NET Core.
Nächste Schritte
Die Seiten „Create“, „Delete“, „Details“ und „Edit“
Betrachten Sie das Modell der Pages/Movies/Index.cshtml.cs
-Seite:
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.EntityFrameworkCore;
using RazorPagesMovie.Models;
namespace RazorPagesMovie.Pages.Movies
{
public class IndexModel : PageModel
{
private readonly RazorPagesMovie.Data.RazorPagesMovieContext _context;
public IndexModel(RazorPagesMovie.Data.RazorPagesMovieContext context)
{
_context = context;
}
public IList<Movie> Movie { get;set; } = default!;
public async Task OnGetAsync()
{
if (_context.Movie != null)
{
Movie = await _context.Movie.ToListAsync();
}
}
}
}
Razor-Seiten werden von PageModel abgeleitet. Gemäß der Konvention wird die von PageModel
abgeleitete Klasse PageNameModel
genannt. Die Indexseite heißt beispielsweise IndexModel
.
Der Konstruktor verwendet Abhängigkeitsinjektion, um RazorPagesMovieContext
zur Seite hinzuzufügen:
public class IndexModel : PageModel
{
private readonly RazorPagesMovie.Data.RazorPagesMovieContext _context;
public IndexModel(RazorPagesMovie.Data.RazorPagesMovieContext context)
{
_context = context;
}
Weitere Informationen zum asynchronen Programmieren mit Entity Framework finden Sie unter Asynchroner Code.
Wenn eine Anforderung an die Seite erfolgt, gibt die Methode OnGetAsync
eine Filmliste an die Razor-Seite zurück. Auf einer Razor Page wird OnGetAsync
oder OnGet
aufgerufen, um den Status der Seite zu initialisieren. In diesem Fall ruft OnGetAsync
eine Liste von Filmen ab und zeigt diese an.
Wenn void
von OnGet
oder Task
von OnGetAsync
zurückgegeben wird, wird keine Rückgabeanweisung verwendet. Sehen Sie sich beispielsweise die Seite Privacy an:
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
namespace RazorPagesMovie.Pages
{
public class PrivacyModel : PageModel
{
private readonly ILogger<PrivacyModel> _logger;
public PrivacyModel(ILogger<PrivacyModel> logger)
{
_logger = logger;
}
public void OnGet()
{
}
}
}
Wenn der Rückgabetyp IActionResult oder Task<IActionResult>
ist, muss eine Rückgabeanweisung bereitgestellt werden. Ein Beispiel ist die Pages/Movies/Create.cshtml.cs
OnPostAsync
-Methode:
public async Task<IActionResult> OnPostAsync()
{
if (!ModelState.IsValid || _context.Movie == null || Movie == null)
{
return Page();
}
_context.Movie.Add(Movie);
await _context.SaveChangesAsync();
return RedirectToPage("./Index");
}
Betrachten Sie die Pages/Movies/Index.cshtml
Razor-Seite:
@page
@model RazorPagesMovie.Pages.Movies.IndexModel
@{
ViewData["Title"] = "Index";
}
<h1>Index</h1>
<p>
<a asp-page="Create">Create New</a>
</p>
<table class="table">
<thead>
<tr>
<th>
@Html.DisplayNameFor(model => model.Movie[0].Title)
</th>
<th>
@Html.DisplayNameFor(model => model.Movie[0].ReleaseDate)
</th>
<th>
@Html.DisplayNameFor(model => model.Movie[0].Genre)
</th>
<th>
@Html.DisplayNameFor(model => model.Movie[0].Price)
</th>
<th></th>
</tr>
</thead>
<tbody>
@foreach (var item in Model.Movie) {
<tr>
<td>
@Html.DisplayFor(modelItem => item.Title)
</td>
<td>
@Html.DisplayFor(modelItem => item.ReleaseDate)
</td>
<td>
@Html.DisplayFor(modelItem => item.Genre)
</td>
<td>
@Html.DisplayFor(modelItem => item.Price)
</td>
<td>
<a asp-page="./Edit" asp-route-id="@item.ID">Edit</a> |
<a asp-page="./Details" asp-route-id="@item.ID">Details</a> |
<a asp-page="./Delete" asp-route-id="@item.ID">Delete</a>
</td>
</tr>
}
</tbody>
</table>
Razor kann aus HTML in C# oder ein Razor-spezifisches Markup übergehen. Wenn auf ein @
-Symbol ein für Razor reserviertes Schlüsselwort folgt, wechselt es in ein Razor-spezifisches Markup. Andernfalls geht es in C# über.
Die @page -Direktive
Die Razor-Anweisung @page
wandelt die Datei in eine MVC-Aktion um. Das bedeutet, dass sie Anforderungen verarbeiten kann. @page
muss die erste Razor-Anweisung auf einer Seite sein. @page
und @model
sind Beispiele für einen Übergang in ein für Razor spezifisches Markup. Unter Razor-Syntax finden Sie weitere Informationen.
Die @model -Direktive
@page
@model RazorPagesMovie.Pages.Movies.IndexModel
Die @model
-Anweisung gibt den Typ des Modells an, das an die Razor-Seite weitergegeben wird. Im vorherigen Beispiel macht die Zeile @model
die von PageModel
abgeleitete Klasse für die Razor Page verfügbar. Das Modell wird in den HTML-Hilfsprogrammen @Html.DisplayNameFor
und @Html.DisplayFor
auf der Seite verwendet.
Überprüfen Sie den Lambdaausdruck, der im folgenden HTML-Hilfsprogramm verwendet wird:
@Html.DisplayNameFor(model => model.Movie[0].Title)
Das HTML-Hilfsprogramm DisplayNameFor überprüft die Eigenschaft Title
, auf die im Lambdaausdruck verwiesen wird, um den Anzeigenamen zu bestimmen. Der Lambdaausdruck wird überprüft und nicht ausgewertet. Das bedeutet, dass keine Zugriffsverletzung auftritt, wenn model
, model.Movie
oder model.Movie[0]
null
oder leer ist. Wenn der Lambdaausdruck ausgewertet wird, (z.B. mit @Html.DisplayFor(modelItem => item.Title)
), werden die Eigenschaftswerte ausgewertet.
Die Seite „Layout“
Wählen Sie die Menülinks aus (RazorPagesMovie, Home und Privacy). Auf jeder Seite wird dasselbe Menülayout gezeigt. Das Menülayout wird mithilfe der Datei Pages/Shared/_Layout.cshtml
implementiert.
Öffnen Sie die Datei, und untersuchen Sie die Datei Pages/Shared/_Layout.cshtml
.
Durch Layout-Vorlagen kann das HTML-Containerlayout:
- An einem Ort angegeben werden.
- Auf mehreren Seiten der Website angewendet werden.
Suchen Sie die Zeile @RenderBody()
. RenderBody
ist ein Platzhalter, bei dem alle seitenspezifischen Ansichten von der Layoutseite umschlossen angezeigt werden. Wenn Sie beispielsweise den Link Privacy auswählen, wird die Ansicht Pages/Privacy.cshtml
in der RenderBody
-Methode gerendert.
ViewData und Layout
Sehen Sie sich das folgenden Markup aus der Datei Pages/Movies/Index.cshtml
an:
@page
@model RazorPagesMovie.Pages.Movies.IndexModel
@{
ViewData["Title"] = "Index";
}
Das oben markierte Markup ist ein Beispiel vom Übergang von Razor in C#. Die Zeichen {
und }
schließen einen Block mit C#-Code ein.
Die Basisklasse PageModel
verfügt über eine ViewData
-Wörterbucheigenschaft, die zum Übergeben von Daten an eine Ansicht verwendet werden kann. Mithilfe eines Schlüssel-Wert-Musters können dem ViewData
-Wörterbuch Objekte hinzugefügt werden. Im vorherigen Beispiel wurde dem Title
-Wörterbuch die Eigenschaft ViewData
hinzugefügt.
Die Title
-Eigenschaft wird in der Pages/Shared/_Layout.cshtml
-Datei verwendet. Das folgende Markup zeigt die ersten Zeilen der Datei _Layout.cshtml
an.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>@ViewData["Title"] - RazorPagesMovie</title>
@*Markup removed for brevity.*@
<link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.css" />
Die Zeile @*Markup removed for brevity.*@
ist ein Razor-Kommentar. Im Gegensatz zu HTML-Kommentaren (<!-- -->
) werden Razor-Kommentare nicht an den Client gesendet. Weitere Informationen finden Sie unter MDN-Webdokumentation: Erste Schritte mit HTML.
Aktualisieren des Layouts
Ändern Sie das
<title>
-Element in der DateiPages/Shared/_Layout.cshtml
so, dass es Movie anstelle von RazorPagesMovie anzeigt.<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>@ViewData["Title"] - Movie</title>
Suchen Sie in der Datei
Pages/Shared/_Layout.cshtml
das folgende Ankerelement.<a class="navbar-brand" asp-area="" asp-page="/Index">RazorPagesMovie</a>
Ersetzen Sie das vorhergehende Element durch das folgende Markup.
<a class="navbar-brand" asp-page="/Movies/Index">RpMovie</a>
Das vorangehende Ankerelement ist ein Tag Helper (Taghilfsprogramm). In diesem Fall handelt es sich um ein Anchor Tag Helper (Anchor-Taghilfsprogramm). Taghilfsattribut und -wert
asp-page="/Movies/Index"
erstellen einen Link zur Razor-Seite/Movies/Index
. Dasasp-area
-Attribut ist leer, daher wird der Bereich im Link nicht verwendet. Weitere Informationen finden Sie unter Bereiche.Speichern Sie Ihre Änderungen, und testen Sie die App, indem Sie den Link RpMovie auswählen. Wenn Probleme auftreten, sehen Sie sich die Datei _Layout.cshtml in GitHub an.
Testen Sie die folgenden Links: Home, RpMovie, Create (Erstellen), Edit (Bearbeiten) und Delete (Löschen). Jede Seite legt den Titel fest, der in der Browserregisterkarte angezeigt wird. Wenn Sie eine Seite mit einem Lesezeichen versehen, wird dieser Titel für das Lesezeichen verwendet.
Hinweis
Sie können unter Umständen in das Feld Price
keine Kommas als Dezimaltrennzeichen eingeben. Zur Unterstützung der jQuery-Validierung für nicht englische Gebietsschemas, in denen ein Komma („,“) als Dezimaltrennzeichen verwendet wird, und Nicht-US-englische Datums- und Uhrzeitformate müssen Sie Schritte zur Globalisierung der App ausführen. In diesem GitHub-Problem 4076 finden Sie Anweisungen zum Hinzufügen von Kommas als Dezimaltrennzeichen.
Die Layout
-Eigenschaft wird in der Pages/_ViewStart.cshtml
-Datei festgelegt:
@{
Layout = "_Layout";
}
Das vorhergehende Markup legt die Layoutdatei auf Pages/Shared/_Layout.cshtml
für alle Razor-Dateien unter dem Ordner Pages fest. Weitere Informationen finden Sie unter Layout.
Das Seitenmodell „Create“
Überprüfen Sie das Seitenmodell Pages/Movies/Create.cshtml.cs
:
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using RazorPagesMovie.Models;
namespace RazorPagesMovie.Pages.Movies
{
public class CreateModel : PageModel
{
private readonly RazorPagesMovie.Data.RazorPagesMovieContext _context;
public CreateModel(RazorPagesMovie.Data.RazorPagesMovieContext context)
{
_context = context;
}
public IActionResult OnGet()
{
return Page();
}
[BindProperty]
public Movie Movie { get; set; } = default!;
// To protect from overposting attacks, see https://aka.ms/RazorPagesCRUD
public async Task<IActionResult> OnPostAsync()
{
if (!ModelState.IsValid || _context.Movie == null || Movie == null)
{
return Page();
}
_context.Movie.Add(Movie);
await _context.SaveChangesAsync();
return RedirectToPage("./Index");
}
}
}
Die Methode OnGet
initialisiert einen beliebigen Zustand, der für die Seite erforderlich ist. Die Seite „Create“ (Erstellen) verfügt nicht über einen initialisierbaren Zustand. Deshalb wird Page
zurückgegeben. Später in diesem Tutorial wird ein Beispiel für OnGet
zur Initialisierung des Zustands gezeigt. Die Methode Page
erstellt ein PageResult
-Objekt, das die Seite Create.cshtml
rendert.
Die Eigenschaft Movie
verwendet das Attribut [BindProperty], um die Modellbindung zu aktivieren. Wenn das Formular „Create“ die Formularwerte bereitstellt, bindet die ASP.NET Core-Laufzeit die bereitgestellten Werte an das Movie
-Modell.
Die Methode OnPostAsync
wird ausgeführt, wenn die Seite Formulardaten bereitstellt:
public async Task<IActionResult> OnPostAsync()
{
if (!ModelState.IsValid || _context.Movie == null || Movie == null)
{
return Page();
}
_context.Movie.Add(Movie);
await _context.SaveChangesAsync();
return RedirectToPage("./Index");
}
Wenn es zu Modellfehlern kommt, wird das Formular mit allen bereitgestellten Formulardaten erneut angezeigt. Die meisten Modellfehler können clientseitig abgefangen werden, bevor das Formular bereitgestellt wird. Ein Beispiel für einen Modellfehler ist die Bereitstellung eines Werts für das Datumsfeld, der nicht in ein Datum konvertiert werden kann. Die clientseitige Validierung und die Modellvalidierung werden später in diesem Tutorial erläutert.
Wenn keine Modellfehler vorliegen:
- Die Daten werden gespeichert.
- Der Browser wird zur Indexseite umgeleitet.
Razor-Seite „Erstellen“
Betrachten Sie die Datei Pages/Movies/Create.cshtml
der Razor-Seite:
@page
@model RazorPagesMovie.Pages.Movies.CreateModel
@{
ViewData["Title"] = "Create";
}
<h1>Create</h1>
<h4>Movie</h4>
<hr />
<div class="row">
<div class="col-md-4">
<form method="post">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group">
<label asp-for="Movie.Title" class="control-label"></label>
<input asp-for="Movie.Title" class="form-control" />
<span asp-validation-for="Movie.Title" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Movie.ReleaseDate" class="control-label"></label>
<input asp-for="Movie.ReleaseDate" class="form-control" />
<span asp-validation-for="Movie.ReleaseDate" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Movie.Genre" class="control-label"></label>
<input asp-for="Movie.Genre" class="form-control" />
<span asp-validation-for="Movie.Genre" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Movie.Price" class="control-label"></label>
<input asp-for="Movie.Price" class="form-control" />
<span asp-validation-for="Movie.Price" class="text-danger"></span>
</div>
<div class="form-group">
<input type="submit" value="Create" class="btn btn-primary" />
</div>
</form>
</div>
</div>
<div>
<a asp-page="Index">Back to List</a>
</div>
@section Scripts {
@{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}
Visual Studio zeigt die folgenden Tags in einer bestimmten Schriftart an, die für Taghilfsprogramme verwendet wird:
<form method="post">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<label asp-for="Movie.Title" class="control-label"></label>
<input asp-for="Movie.Title" class="form-control" />
<span asp-validation-for="Movie.Title" class="text-danger"></span>
Das Element <form method="post">
ist ein Form Tag Helper (Hilfsprogramm für Formulartags). Das Hilfsprogramm für Formulartags enthält automatisch ein antiforgery token (Antifälschungstoken).
Die Gerüstbau-Engine erstellt Razor-Markup für jedes Feld im Modell (ausgenommen die ID) ähnlich wie folgt:
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group">
<label asp-for="Movie.Title" class="control-label"></label>
<input asp-for="Movie.Title" class="form-control" />
<span asp-validation-for="Movie.Title" class="text-danger"></span>
</div>
Das Hilfsprogramm für Validierungstags (<div asp-validation-summary
und <span asp-validation-for
) zeigt Validierungsfehler. Die Validierung wird an späterer Stelle in dieser Reihe detaillierter beschrieben.
Das Label Tag Helper (Taghilfsprogramm für Label) (<label asp-for="Movie.Title" class="control-label"></label>
) generiert den Titel des Labels und das [for]
-Attribut für die Eigenschaft Title
.
Das Hilfsprogramm für Eingabetags (<input asp-for="Movie.Title" class="form-control">
) verwendet die Attribute von DataAnnotations und generiert HTML-Attribute, die auf der Clientseite für die jQuery-Validierung erforderlich sind.
Weitere Informationen zu Taghilfsprogrammen wie <form method="post">
finden Sie unter Taghilfsprogramme in ASP.NET Core.
Nächste Schritte
Die Seiten „Create“, „Delete“, „Details“ und „Edit“
Betrachten Sie das Modell der Pages/Movies/Index.cshtml.cs
-Seite:
// Unused usings removed.
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.EntityFrameworkCore;
using RazorPagesMovie.Models;
using System.Collections.Generic;
using System.Threading.Tasks;
namespace RazorPagesMovie.Pages.Movies
{
public class IndexModel : PageModel
{
private readonly RazorPagesMovie.Data.RazorPagesMovieContext _context;
public IndexModel(RazorPagesMovie.Data.RazorPagesMovieContext context)
{
_context = context;
}
public IList<Movie> Movie { get;set; }
public async Task OnGetAsync()
{
Movie = await _context.Movie.ToListAsync();
}
}
}
Razor-Seiten werden von PageModel
abgeleitet. Gemäß der Konvention wird die von PageModel
abgeleitete Klasse <PageName>Model
genannt. Der Konstruktor verwendet Abhängigkeitsinjektion, um RazorPagesMovieContext
zur Seite hinzuzufügen:
public class IndexModel : PageModel
{
private readonly RazorPagesMovie.Data.RazorPagesMovieContext _context;
public IndexModel(RazorPagesMovie.Data.RazorPagesMovieContext context)
{
_context = context;
}
Weitere Informationen zum asynchronen Programmieren mit Entity Framework finden Sie unter Asynchroner Code.
Wenn eine Anforderung an die Seite erfolgt, gibt die Methode OnGetAsync
eine Filmliste an die Razor-Seite zurück. Auf einer Razor Page wird OnGetAsync
oder OnGet
aufgerufen, um den Status der Seite zu initialisieren. In diesem Fall ruft OnGetAsync
eine Liste von Filmen ab und zeigt diese an.
Wenn void
von OnGet
oder Task
von OnGetAsync
zurückgegeben wird, wird keine Rückgabeanweisung verwendet. Dies ist zum Beispiel auf der Seite Privacy der Fall:
public class PrivacyModel : PageModel
{
private readonly ILogger<PrivacyModel> _logger;
public PrivacyModel(ILogger<PrivacyModel> logger)
{
_logger = logger;
}
public void OnGet()
{
}
}
Wenn der Rückgabetyp IActionResult
oder Task<IActionResult>
ist, muss eine Rückgabeanweisung bereitgestellt werden. Ein Beispiel ist die Pages/Movies/Create.cshtml.cs
OnPostAsync
-Methode:
public async Task<IActionResult> OnPostAsync()
{
if (!ModelState.IsValid)
{
return Page();
}
_context.Movie.Add(Movie);
await _context.SaveChangesAsync();
return RedirectToPage("./Index");
}
}
Betrachten Sie die Pages/Movies/Index.cshtml
Razor-Seite:
@page
@model RazorPagesMovie.Pages.Movies.IndexModel
@{
ViewData["Title"] = "Index";
}
<h1>Index</h1>
<p>
<a asp-page="Create">Create New</a>
</p>
<table class="table">
<thead>
<tr>
<th>
@Html.DisplayNameFor(model => model.Movie[0].Title)
</th>
<th>
@Html.DisplayNameFor(model => model.Movie[0].ReleaseDate)
</th>
<th>
@Html.DisplayNameFor(model => model.Movie[0].Genre)
</th>
<th>
@Html.DisplayNameFor(model => model.Movie[0].Price)
</th>
<th></th>
</tr>
</thead>
<tbody>
@foreach (var item in Model.Movie) {
<tr>
<td>
@Html.DisplayFor(modelItem => item.Title)
</td>
<td>
@Html.DisplayFor(modelItem => item.ReleaseDate)
</td>
<td>
@Html.DisplayFor(modelItem => item.Genre)
</td>
<td>
@Html.DisplayFor(modelItem => item.Price)
</td>
<td>
<a asp-page="./Edit" asp-route-id="@item.ID">Edit</a> |
<a asp-page="./Details" asp-route-id="@item.ID">Details</a> |
<a asp-page="./Delete" asp-route-id="@item.ID">Delete</a>
</td>
</tr>
}
</tbody>
</table>
Razor kann aus HTML in C# oder ein Razor-spezifisches Markup übergehen. Wenn auf ein @
-Symbol ein für Razor reserviertes Schlüsselwort folgt, wechselt es in ein Razor-spezifisches Markup. Andernfalls geht es in C# über.
Die @page -Direktive
Die Razor-Anweisung @page
wandelt die Datei in eine MVC-Aktion um. Das bedeutet, dass sie Anforderungen verarbeiten kann. @page
muss die erste Razor-Anweisung auf einer Seite sein. @page
und @model
sind Beispiele für einen Übergang in ein für Razor spezifisches Markup. Unter Razor-Syntax finden Sie weitere Informationen.
Die @model -Direktive
@page
@model RazorPagesMovie.Pages.Movies.IndexModel
Die @model
-Anweisung gibt den Typ des Modells an, das an die Razor-Seite weitergegeben wird. Im vorherigen Beispiel macht die @model
-Linie die von PageModel
abgeleitete Klasse der Razor-Seite verfügbar. Das Modell wird in den HTML-Hilfsprogrammen @Html.DisplayNameFor
und @Html.DisplayFor
auf der Seite verwendet.
Überprüfen Sie den Lambdaausdruck, der im folgenden HTML-Hilfsprogramm verwendet wird:
@Html.DisplayNameFor(model => model.Movie[0].Title)
Das HTML-Hilfsprogramm DisplayNameFor überprüft die Eigenschaft Title
, auf die im Lambdaausdruck verwiesen wird, um den Anzeigenamen zu bestimmen. Der Lambdaausdruck wird überprüft und nicht ausgewertet. Das bedeutet, dass keine Zugriffsverletzung auftritt, wenn model
, model.Movie
oder model.Movie[0]
null
oder leer ist. Wenn der Lambdaausdruck ausgewertet wird, (z.B. mit @Html.DisplayFor(modelItem => item.Title)
), werden die Eigenschaftswerte ausgewertet.
Die Seite „Layout“
Wählen Sie die Menülinks aus (RazorPagesMovie, Home und Privacy). Auf jeder Seite wird dasselbe Menülayout gezeigt. Das Menülayout wird mithilfe der Datei Pages/Shared/_Layout.cshtml
implementiert.
Öffnen Sie die Datei, und untersuchen Sie die Datei Pages/Shared/_Layout.cshtml
.
Durch Layout-Vorlagen kann das HTML-Containerlayout:
- An einem Ort angegeben werden.
- Auf mehreren Seiten der Website angewendet werden.
Suchen Sie die Zeile @RenderBody()
. RenderBody
ist ein Platzhalter, bei dem alle seitenspezifischen Ansichten von der Layoutseite umschlossen angezeigt werden. Wenn Sie beispielsweise den Link Privacy auswählen, wird die Ansicht Pages/Privacy.cshtml
in der RenderBody
-Methode gerendert.
ViewData und Layout
Sehen Sie sich das folgenden Markup aus der Datei Pages/Movies/Index.cshtml
an:
@page
@model RazorPagesMovie.Pages.Movies.IndexModel
@{
ViewData["Title"] = "Index";
}
Das oben markierte Markup ist ein Beispiel vom Übergang von Razor in C#. Die Zeichen {
und }
schließen einen Block mit C#-Code ein.
Die Basisklasse PageModel
verfügt über eine ViewData
-Wörterbucheigenschaft, die zum Übergeben von Daten an eine Ansicht verwendet werden kann. Mithilfe eines Schlüssel-Wert-Musters können dem ViewData
-Wörterbuch Objekte hinzugefügt werden. Im vorherigen Beispiel wurde dem Title
-Wörterbuch die Eigenschaft ViewData
hinzugefügt.
Die Title
-Eigenschaft wird in der Pages/Shared/_Layout.cshtml
-Datei verwendet. Das folgende Markup zeigt die ersten Zeilen der Datei _Layout.cshtml
an.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>@ViewData["Title"] - RazorPagesMovie</title>
@*Markup removed for brevity.*@
Die Zeile @*Markup removed for brevity.*@
ist ein Razor-Kommentar. Im Gegensatz zu HTML-Kommentaren (<!-- -->
) werden Razor-Kommentare nicht an den Client gesendet. Weitere Informationen finden Sie unter MDN-Webdokumentation: Erste Schritte mit HTML.
Aktualisieren des Layouts
Ändern Sie das
<title>
-Element in der DateiPages/Shared/_Layout.cshtml
so, dass es Movie anstelle von RazorPagesMovie anzeigt.<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>@ViewData["Title"] - Movie</title>
Suchen Sie in der Datei
Pages/Shared/_Layout.cshtml
das folgende Ankerelement.<a class="navbar-brand" asp-area="" asp-page="/Index">RazorPagesMovie</a>
Ersetzen Sie das vorhergehende Element durch das folgende Markup.
<a class="navbar-brand" asp-page="/Movies/Index">RpMovie</a>
Das vorangehende Ankerelement ist ein Tag Helper (Taghilfsprogramm). In diesem Fall handelt es sich um ein Anchor Tag Helper (Anchor-Taghilfsprogramm). Taghilfsattribut und -wert
asp-page="/Movies/Index"
erstellen einen Link zur Razor-Seite/Movies/Index
. Dasasp-area
-Attribut ist leer, daher wird der Bereich im Link nicht verwendet. Weitere Informationen finden Sie unter Bereiche.Speichern Sie Ihre Änderungen, und testen Sie die App, indem Sie den Link RpMovie auswählen. Wenn Probleme auftreten, sehen Sie sich die Datei _Layout.cshtml in GitHub an.
Testen Sie die folgenden Links: Home, RpMovie, Create (Erstellen), Edit (Bearbeiten) und Delete (Löschen). Jede Seite legt den Titel fest, der in der Browserregisterkarte angezeigt wird. Wenn Sie eine Seite mit einem Lesezeichen versehen, wird dieser Titel für das Lesezeichen verwendet.
Hinweis
Sie können unter Umständen in das Feld Price
keine Kommas als Dezimaltrennzeichen eingeben. Zur Unterstützung der jQuery-Validierung für nicht englische Gebietsschemas, in denen ein Komma („,“) als Dezimaltrennzeichen verwendet wird, und Nicht-US-englische Datums- und Uhrzeitformate müssen Sie Schritte zur Globalisierung der App ausführen. In diesem GitHub-Problem 4076 finden Sie Anweisungen zum Hinzufügen von Kommas als Dezimaltrennzeichen.
Die Layout
-Eigenschaft wird in der Pages/_ViewStart.cshtml
-Datei festgelegt:
@{
Layout = "_Layout";
}
Das vorhergehende Markup legt die Layoutdatei auf Pages/Shared/_Layout.cshtml
für alle Razor-Dateien unter dem Ordner Pages fest. Weitere Informationen finden Sie unter Layout.
Das Seitenmodell „Create“
Überprüfen Sie das Seitenmodell Pages/Movies/Create.cshtml.cs
:
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using RazorPagesMovie.Models;
using System;
using System.Threading.Tasks;
namespace RazorPagesMovie.Pages.Movies
{
public class CreateModel : PageModel
{
private readonly RazorPagesMovie.Data.RazorPagesMovieContext _context;
public CreateModel(RazorPagesMovie.Data.RazorPagesMovieContext context)
{
_context = context;
}
public IActionResult OnGet()
{
return Page();
}
[BindProperty]
public Movie Movie { get; set; }
public async Task<IActionResult> OnPostAsync()
{
if (!ModelState.IsValid)
{
return Page();
}
_context.Movie.Add(Movie);
await _context.SaveChangesAsync();
return RedirectToPage("./Index");
}
}
}
Die Methode OnGet
initialisiert einen beliebigen Zustand, der für die Seite erforderlich ist. Die Seite „Create“ (Erstellen) verfügt nicht über einen initialisierbaren Zustand. Deshalb wird Page
zurückgegeben. Später in diesem Tutorial wird ein Beispiel für OnGet
zur Initialisierung des Zustands gezeigt. Die Methode Page
erstellt ein PageResult
-Objekt, das die Seite Create.cshtml
rendert.
Die Eigenschaft Movie
verwendet das Attribut [BindProperty], um die Modellbindung zu aktivieren. Wenn das Formular „Create“ die Formularwerte bereitstellt, bindet die ASP.NET Core-Laufzeit die bereitgestellten Werte an das Movie
-Modell.
Die Methode OnPostAsync
wird ausgeführt, wenn die Seite Formulardaten bereitstellt:
public async Task<IActionResult> OnPostAsync()
{
if (!ModelState.IsValid)
{
return Page();
}
_context.Movie.Add(Movie);
await _context.SaveChangesAsync();
return RedirectToPage("./Index");
}
Wenn es zu Modellfehlern kommt, wird das Formular mit allen bereitgestellten Formulardaten erneut angezeigt. Die meisten Modellfehler können clientseitig abgefangen werden, bevor das Formular bereitgestellt wird. Ein Beispiel für einen Modellfehler ist die Bereitstellung eines Werts für das Datumsfeld, der nicht in ein Datum konvertiert werden kann. Die clientseitige Validierung und die Modellvalidierung werden später in diesem Tutorial erläutert.
Wenn keine Modellfehler vorliegen:
- Die Daten werden gespeichert.
- Der Browser wird zur Indexseite umgeleitet.
Razor-Seite „Erstellen“
Betrachten Sie die Datei Pages/Movies/Create.cshtml
der Razor-Seite:
@page
@model RazorPagesMovie.Pages.Movies.CreateModel
@{
ViewData["Title"] = "Create";
}
<h1>Create</h1>
<h4>Movie</h4>
<hr />
<div class="row">
<div class="col-md-4">
<form method="post">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group">
<label asp-for="Movie.Title" class="control-label"></label>
<input asp-for="Movie.Title" class="form-control" />
<span asp-validation-for="Movie.Title" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Movie.ReleaseDate" class="control-label"></label>
<input asp-for="Movie.ReleaseDate" class="form-control" />
<span asp-validation-for="Movie.ReleaseDate" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Movie.Genre" class="control-label"></label>
<input asp-for="Movie.Genre" class="form-control" />
<span asp-validation-for="Movie.Genre" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Movie.Price" class="control-label"></label>
<input asp-for="Movie.Price" class="form-control" />
<span asp-validation-for="Movie.Price" class="text-danger"></span>
</div>
<div class="form-group">
<input type="submit" value="Create" class="btn btn-primary" />
</div>
</form>
</div>
</div>
<div>
<a asp-page="Index">Back to List</a>
</div>
@section Scripts {
@{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}
Visual Studio zeigt die folgenden Tags in einer bestimmten Schriftart an, die für Taghilfsprogramme verwendet wird:
<form method="post">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<label asp-for="Movie.Title" class="control-label"></label>
<input asp-for="Movie.Title" class="form-control" />
<span asp-validation-for="Movie.Title" class="text-danger"></span>
Das Element <form method="post">
ist ein Form Tag Helper (Hilfsprogramm für Formulartags). Das Hilfsprogramm für Formulartags enthält automatisch ein antiforgery token (Antifälschungstoken).
Die Gerüstbau-Engine erstellt Razor-Markup für jedes Feld im Modell (ausgenommen die ID) ähnlich wie folgt:
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group">
<label asp-for="Movie.Title" class="control-label"></label>
<input asp-for="Movie.Title" class="form-control" />
<span asp-validation-for="Movie.Title" class="text-danger"></span>
</div>
Das Hilfsprogramm für Validierungstags (<div asp-validation-summary
und <span asp-validation-for
) zeigt Validierungsfehler. Die Validierung wird an späterer Stelle in dieser Reihe detaillierter beschrieben.
Das Label Tag Helper (Taghilfsprogramm für Label) (<label asp-for="Movie.Title" class="control-label"></label>
) generiert den Titel des Labels und das [for]
-Attribut für die Eigenschaft Title
.
Das Hilfsprogramm für Eingabetags (<input asp-for="Movie.Title" class="form-control">
) verwendet die Attribute von DataAnnotations und generiert HTML-Attribute, die auf der Clientseite für die jQuery-Validierung erforderlich sind.
Weitere Informationen zu Taghilfsprogrammen wie <form method="post">
finden Sie unter Taghilfsprogramme in ASP.NET Core.