Part 3: Gerüstbau mit Razor Pages in ASP.NET Core

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“

Überprüfen Sie das Seitenmodell Pages/Movies/Index.cshtml.cs:

// 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 Taskvon 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. Dies kann z. B. die OnPostAsync-Methode Pages/Movies/Create.cshtml.cs sein:

    public async Task<IActionResult> OnPostAsync()
    {
        if (!ModelState.IsValid)
        {
            return Page();
        }

        _context.Movie.Add(Movie);
        await _context.SaveChangesAsync();

        return RedirectToPage("./Index");
    }
}

Sehen Sie sich die Razor-Seite Pages/Movies/Index.cshtml an:

@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 DisplayNameExtensions.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“

Klicken Sie auf die Menülinks 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 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 auf den Link Privacy klicken, wird die Ansicht Pages/Privacy.cshtml in der Methode RenderBody gerendert.

ViewData und Layout

Sehen Sie sich das folgenden Markup in 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 Eigenschaft Title wird in der Datei Pages/Shared/_Layout.cshtml verwendet. Das folgende Markup zeigt die ersten Zeilen der Datei Pages/_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

  1. Ändern Sie das <title>-Element in der Datei Pages/Shared/_Layout.cshtml, um Movie anstelle von RazorPagesMovie anzuzeigen.

    <!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>
    
  2. Suchen Sie in der Datei Pages/Shared/_Layout.cshtml das folgende Ankerelement.

    <a class="navbar-brand" asp-area="" asp-page="/Index">RazorPagesMovie</a>
    
  3. 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). Das Taghilfsattribut und der -wert asp-page="/Movies/Index" erstellen einen Link zur Razor-Seite /Movies/Index. Das asp-area-Attribut ist leer, daher wird der Bereich im Link nicht verwendet. Weitere Informationen finden Sie unter Bereiche.

  4. 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.

  5. 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 Eigenschaft Layout wird in der Datei Pages/_ViewStart.cshtml festgelegt:

@{
    Layout = "_Layout";
}

Das vorhergehende Markup legt die Layoutdatei für alle Razor-Dateien unter dem Ordner Pages auf Pages/Shared/_Layout.cshtml 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 Seite Index 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>

VS17-Ansicht der Create.cshtml-Seite

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.

Zusätzliche Ressourcen

Die Seiten „Create“, „Delete“, „Details“ und „Edit“

Überprüfen Sie das Seitenmodell Pages/Movies/Index.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.EntityFrameworkCore;
using RazorPagesMovie.Models;

namespace RazorPagesMovie.Pages.Movies
{
    public class IndexModel : PageModel
    {
        private readonly RazorPagesMovie.Models.RazorPagesMovieContext _context;

        public IndexModel(RazorPagesMovie.Models.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. Die per Gerüstbau erstellten Seiten folgen diesem Muster. 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. OnGetAsync oder OnGet werden für eine Razor-Seite aufgerufen, um den Zustand 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ückgabemethode verwendet. Wenn der Rückgabetyp IActionResult oder Task<IActionResult> ist, muss eine Rückgabeanweisung bereitgestellt werden. Dies kann z. B. die OnPostAsync-Methode Pages/Movies/Create.cshtml.cs sein:

public async Task<IActionResult> OnPostAsync()
{
    if (!ModelState.IsValid)
    {
        return Page();
    }

    _context.Movie.Add(Movie);
    await _context.SaveChangesAsync();

    return RedirectToPage("./Index");
}

Sehen Sie sich die Razor-Seite Pages/Movies/Index.cshtml an:

@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 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 ist ein Beispiel für einen Übergang in ein 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.

HTML-Hilfsprogramme

Überprüfen Sie den Lambdaausdruck, der im folgenden HTML-Hilfsprogramm verwendet wird:

@Html.DisplayNameFor(model => model.Movie[0].Title)

Das HTML-Hilfsprogramm DisplayNameExtensions.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 sind. Wenn der Lambdaausdruck ausgewertet wird, (z. B. mit @Html.DisplayFor(modelItem => item.Title)), werden die Eigenschaftswerte ausgewertet.

Die Seite „Layout“

Klicken Sie auf die Menülinks 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 und untersuchen Sie die Datei Pages/Shared/_Layout.cshtml.

Layout-Vorlagen ermöglichen Ihnen, das HTML-Containerlayout einer Website zentral anzugeben und dann auf mehrere Seiten der Website anzuwenden. Suchen Sie die Zeile @RenderBody(). RenderBody ist ein Platzhalter, bei dem alle seitenspezifischen Ansichten, die Sie erstellen, von der Layoutseite umschlossen angezeigt werden. Wenn Sie beispielsweise auf den Link Privacy klicken, wird die Ansicht Pages/Privacy.cshtml in der Methode RenderBody gerendert.

ViewData und Layout

Sehen Sie sich den folgenden Code aus der Datei Pages/Movies/Index.cshtml an:

@page
@model RazorPagesMovie.Pages.Movies.IndexModel

@{
    ViewData["Title"] = "Index";
}

Der oben markierte Code 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 Hinzufügen von Daten verwendet werden kann, die an eine Ansicht übergeben werden sollen. 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 Eigenschaft Title wird in der Datei Pages/Shared/_Layout.cshtml verwendet. Das folgende Markup zeigt die ersten Zeilen der Datei Pages/_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 Datei Pages/Shared/_Layout.cshtml, um Movie anstelle von RazorPagesMovie anzuzeigen.

<!DOCTYPE html>
<html>
<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). Das Taghilfsattribut und der -wert asp-page="/Movies/Index" erstellen einen Link zur Razor-Seite /Movies/Index. Das asp-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 auf den Link RpMovie klicken. Wenn Probleme auftreten, sehen Sie sich die Datei _Layout.cshtml in GitHub an.

Testen Sie die anderen 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 Eigenschaft Layout wird in der Datei Pages/_ViewStart.cshtml festgelegt:

@{
    Layout = "_Layout";
}

Das vorhergehende Markup legt die Layoutdatei für alle Razor-Dateien unter dem Ordner Pages auf Pages/Shared/_Layout.cshtml fest. Weitere Informationen finden Sie unter Layout.

Das Seitenmodell „Create“

Überprüfen Sie das Seitenmodell Pages/Movies/Create.cshtml.cs:

// Unused usings removed.
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.Models.RazorPagesMovieContext _context;

        public CreateModel(RazorPagesMovie.Models.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. Im späteren Verlauf des Tutorials initialisiert die Methode OnGet einen Zustand. Die Methode Page erstellt ein PageResult-Objekt, das die Seite Create.cshtml rendert.

Die Eigenschaft Movie verwendet das Attribut [[BindProperty]BindPropertyAttribute, 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 auftreten, werden die Daten gespeichert und der Browser zur Seite Index 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 das <form method="post">-Tag in einer bestimmten Schriftart an, die für Taghilfsprogramme verwendet wird:

VS17-Ansicht der Create.cshtml-Seite

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.

Zusätzliche Ressourcen