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

Hinweis

Dies ist nicht die neueste Version dieses Artikels. 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.

Informationen zum aktuellen Release finden Sie in der .NET 8-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 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 Taskvon 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.cshtmlRazor-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 Helpers (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 RazorPagesMovie, Home und Privacy aus. 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

  1. Ändern Sie das <title>-Element in der Pages/Shared/_Layout.cshtml-Datei, 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). Taghilfsattribut und -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 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>

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.

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 Taskvon 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.cshtmlRazor-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 Helpers (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 RazorPagesMovie, Home und Privacy aus. 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

  1. Ändern Sie das <title>-Element in der Pages/Shared/_Layout.cshtml-Datei, 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). Taghilfsattribut und -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 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>

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.

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 Taskvon 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.csOnPostAsync-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.cshtmlRazor-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 Helpers (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 RazorPagesMovie, Home und Privacy aus. 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

  1. Ändern Sie das <title>-Element in der Pages/Shared/_Layout.cshtml-Datei, 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). Taghilfsattribut und -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 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>

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.

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 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. Ein Beispiel ist die Pages/Movies/Create.cshtml.csOnPostAsync-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.cshtmlRazor-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 Helpers (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 RazorPagesMovie, Home und Privacy aus. 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

  1. Ändern Sie das <title>-Element in der Pages/Shared/_Layout.cshtml-Datei, 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). Taghilfsattribut und -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 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>

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.

Nächste Schritte