Część 3, strony szkieletowe Razor w ASP.NET Core

Uwaga

Nie jest to najnowsza wersja tego artykułu. Aby zapoznać się z bieżącą wersją, zapoznaj się z wersją tego artykułu platformy .NET 8.

Ważne

Te informacje odnoszą się do produktu w wersji wstępnej, który może zostać znacząco zmodyfikowany, zanim zostanie wydany komercyjnie. Firma Microsoft nie udziela żadnych gwarancji, jawnych lub domniemanych, w odniesieniu do informacji podanych w tym miejscu.

Aby zapoznać się z bieżącą wersją, zapoznaj się z wersją tego artykułu platformy .NET 8.

Autor: Rick Anderson

Ten samouczek analizuje Razor strony utworzone przez tworzenie szkieletów w poprzednim samouczku.

Strony Tworzenie, Usuwanie, Szczegóły i Edytowanie

Pages/Movies/Index.cshtml.cs Sprawdź model strony:

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 Strony pochodzą z elementu PageModel. Zgodnie z konwencją klasa pochodna PageModel nosi nazwę PageNameModel. Na przykład strona Indeks ma nazwę IndexModel.

Konstruktor używa iniekcji zależności, aby dodać element RazorPagesMovieContext do strony:

public class IndexModel : PageModel
{
    private readonly RazorPagesMovie.Data.RazorPagesMovieContext _context;

    public IndexModel(RazorPagesMovie.Data.RazorPagesMovieContext context)
    {
        _context = context;
    }

Zobacz Kod asynchroniczny, aby uzyskać więcej informacji na temat programowania asynchronicznego w programie Entity Framework.

GET Po wysłaniu żądania dla strony OnGetAsync metoda zwraca listę filmów do stronyRazor. Razor Na stronie lub OnGet jest wywoływana w OnGetAsync celu zainicjowania stanu strony. W tym przypadku OnGetAsync pobiera listę filmów i wyświetla je.

Gdy OnGet zwraca void lub OnGetAsync zwraca Taskwartość , nie jest używana żadna instrukcja return. Na przykład sprawdź Privacy stronę:

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()
        {
        }
    }
}

Gdy zwracany typ to IActionResult lub Task<IActionResult>, należy podać instrukcję return. Na przykład Pages/Movies/Create.cshtml.cs OnPostAsync metoda:

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

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

    return RedirectToPage("./Index");
}

Sprawdź stronę Pages/Movies/Index.cshtmlRazor :

@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 może przejść z kodu HTML do języka C# lub do Razorznaczników specyficznych. Gdy po Razor symbolu @ następuje zastrzeżone słowo kluczowe, przechodzi do znaczników specyficznych dla języka C#. W przeciwnym razie przechodzi do Razorjęzyka C#.

Dyrektywa @page

Dyrektywa @pageRazor sprawia, że plik jest akcją MVC, co oznacza, że może obsługiwać żądania. Dyrektywa @page musi być pierwszą dyrektywą Razor na stronie. @page i @model to przykłady przejścia na Razorznaczniki specyficzne dla języka . Zobacz Razor składnię , aby uzyskać więcej informacji.

Dyrektywa @model

@page
@model RazorPagesMovie.Pages.Movies.IndexModel

Dyrektywa @model określa typ modelu przekazanego Razor do strony. W poprzednim przykładzie wiersz sprawia, @model że klasa pochodna PageModel jest dostępna dla strony Razor . Model jest używany w pomocnikach @Html.DisplayNameFor HTML i @Html.DisplayForna stronie.

Sprawdź wyrażenie lambda używane w następującym pomocniku HTML:

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

Pomocnik DisplayNameFor HTML sprawdza Title właściwość przywoływane w wyrażeniu lambda, aby określić nazwę wyświetlaną. Wyrażenie lambda jest sprawdzane, a nie oceniane. Oznacza to, że nie ma naruszenia dostępu, gdy modelwartość , model.Movielub model.Movie[0] jest pusta null . Gdy wyrażenie lambda jest obliczane, na przykład przy @Html.DisplayFor(modelItem => item.Title)użyciu metody , wartości właściwości modelu są oceniane.

Strona układu

Wybierz łącza Razormenu PagesFilmy, Homei Privacy. Każda strona zawiera ten sam układ menu. Układ menu jest implementowany w Pages/Shared/_Layout.cshtml pliku.

Otwórz plik i sprawdź go Pages/Shared/_Layout.cshtml .

Szablony układów umożliwiają układ kontenera HTML:

  • Określone w jednym miejscu.
  • Zastosowane na wielu stronach w witrynie.

@RenderBody() Znajdź wiersz. RenderBody to symbol zastępczy, w którym są wyświetlane wszystkie widoki specyficzne dla strony, opakowane na stronie układu. Na przykład wybierz Privacy link, a Pages/Privacy.cshtml widok jest renderowany wewnątrz RenderBody metody .

ViewData i układ

Rozważ następujące znaczniki z Pages/Movies/Index.cshtml pliku:

@page
@model RazorPagesMovie.Pages.Movies.IndexModel

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

Powyższy wyróżniony znacznik jest przykładem Razor przejścia do języka C#. Znaki { i } otaczają blok kodu języka C#.

Klasa PageModel bazowa zawiera właściwość słownika ViewData , która może służyć do przekazywania danych do widoku. Obiekty są dodawane do słownika ViewData przy użyciu wzorca wartości klucza. W poprzednim przykładzie Title właściwość jest dodawana do słownika ViewData .

Właściwość Title jest używana w Pages/Shared/_Layout.cshtml pliku . Poniższy znacznik przedstawia kilka pierwszych wierszy _Layout.cshtml pliku.

<!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" />

Aktualizowanie układu

  1. <title> Zmień element w pliku, Pages/Shared/_Layout.cshtml aby wyświetlić film, a nie RazorPagesPanel.

    <!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. Znajdź następujący element zakotwiczenia w Pages/Shared/_Layout.cshtml pliku.

    <a class="navbar-brand" asp-area="" asp-page="/Index">RazorPagesMovie</a>
    
  3. Zastąp poprzedni element następującym znacznikiem:

    <a class="navbar-brand" asp-page="/Movies/Index">RpMovie</a>
    

    Poprzedni element kotwicy jest pomocnikem tagów. W tym przypadku jest to pomocnik tagu kotwicy. Atrybut asp-page="/Movies/Index" i wartość Pomocnika tagów /Movies/IndexRazor tworzą link do strony. Wartość atrybutu asp-area jest pusta, więc obszar nie jest używany w linku. Aby uzyskać więcej informacji, zobacz Obszary .

  4. Zapisz zmiany i przetestuj aplikację, wybierając link RpFilm . Jeśli masz jakiekolwiek problemy, zobacz plik _Layout.cshtml w usłudze GitHub.

  5. Przetestuj Homełącza , RpFilm, Create, Edit i Delete. Każda strona ustawia tytuł, który można wyświetlić na karcie przeglądarki. Podczas tworzenia zakładek tytuł jest używany dla zakładki.

Uwaga

W polu może nie być możliwe wprowadzenie przecinków dziesiętnych Price . Aby obsługiwać walidację jQuery dla ustawień regionalnych innych niż angielski, które używają przecinka (",") dla punktu dziesiętnego i formatów dat innych niż angielskie stany USA, należy wykonać kroki w celu globalizacji aplikacji. Zobacz ten problem z usługą GitHub 4076 , aby uzyskać instrukcje dotyczące dodawania przecinka dziesiętnego.

Właściwość Layout jest ustawiana w Pages/_ViewStart.cshtml pliku:

@{
    Layout = "_Layout";
}

Powyższy znacznik ustawia plik układu na Pages/Shared/_Layout.cshtml dla wszystkich Razor plików w folderze Pages . Aby uzyskać więcej informacji, zobacz Układ .

Model tworzenia strony

Pages/Movies/Create.cshtml.cs Sprawdź model strony:

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");
        }
    }
}

Metoda OnGet inicjuje dowolny stan wymagany dla strony. Strona Tworzenie nie ma żadnego stanu do zainicjowania, dlatego Page jest zwracana. W dalszej części samouczka zostanie wyświetlony przykład inicjowania OnGet stanu. Metoda Page tworzy PageResult obiekt renderujący Create.cshtml stronę.

Właściwość Movie używa atrybutu [BindProperty], aby wyrazić zgodę na powiązanie modelu. Gdy formularz Tworzenie publikuje wartości formularza, środowisko uruchomieniowe ASP.NET Core wiąże opublikowane wartości z modelem Movie .

Metoda OnPostAsync jest uruchamiana, gdy strona publikuje dane formularza:

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

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

    return RedirectToPage("./Index");
}

Jeśli występują jakiekolwiek błędy modelu, formularz jest odtwarzany ponownie wraz z dowolnymi opublikowanymi danymi formularza. Większość błędów modelu można przechwycić po stronie klienta przed opublikowaniem formularza. Przykładem błędu modelu jest opublikowanie wartości pola daty, którego nie można przekonwertować na datę. Walidacja po stronie klienta i walidacja modelu zostały omówione w dalszej części tego samouczka.

Jeśli nie ma żadnych błędów modelu:

  • Dane są zapisywane.
  • Przeglądarka jest przekierowywana do strony Indeks.

Strona tworzenia Razor

Pages/Movies/Create.cshtmlRazor Sprawdź plik strony:

@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");}
}

Program Visual Studio wyświetla następujące tagi w charakterystycznej czcionki pogrubionej używanej dla pomocników tagów:

  • <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>

Widok vs17 strony Create.cshtml

Element <form method="post"> jest pomocnikiem tagu formularza. Pomocnik tagu formularza automatycznie zawiera token antyforgery.

Aparat tworzenia szkieletów tworzy Razor znaczniki dla każdego pola w modelu, z wyjątkiem identyfikatora, podobnego do następującego:

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

Pomocnicy tagów walidacji (<div asp-validation-summary i <span asp-validation-for) wyświetlają błędy walidacji. Walidacja zostanie szczegółowo omówiona w dalszej części tej serii.

Pomocnik tagów etykiet (<label asp-for="Movie.Title" class="control-label"></label>) generuje etykietę podpis i [for] atrybut właściwościTitle.

Pomocnik tagów wejściowych (<input asp-for="Movie.Title" class="form-control">) używa atrybutów DataAnnotations i tworzy atrybuty HTML wymagane do weryfikacji jQuery po stronie klienta.

Aby uzyskać więcej informacji na temat pomocników tagów, takich jak <form method="post">, zobacz Pomocnicy tagów w ASP.NET Core.

Następne kroki

Strony Tworzenie, Usuwanie, Szczegóły i Edytowanie

Pages/Movies/Index.cshtml.cs Sprawdź model strony:

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 Strony pochodzą z elementu PageModel. Zgodnie z konwencją klasa pochodna PageModel nosi nazwę PageNameModel. Na przykład strona Indeks ma nazwę IndexModel.

Konstruktor używa iniekcji zależności, aby dodać element RazorPagesMovieContext do strony:

public class IndexModel : PageModel
{
    private readonly RazorPagesMovie.Data.RazorPagesMovieContext _context;

    public IndexModel(RazorPagesMovie.Data.RazorPagesMovieContext context)
    {
        _context = context;
    }

Zobacz Kod asynchroniczny, aby uzyskać więcej informacji na temat programowania asynchronicznego w programie Entity Framework.

GET Po wysłaniu żądania dla strony OnGetAsync metoda zwraca listę filmów do stronyRazor. Razor Na stronie lub OnGet jest wywoływana w OnGetAsync celu zainicjowania stanu strony. W tym przypadku OnGetAsync pobiera listę filmów i wyświetla je.

Gdy OnGet zwraca void lub OnGetAsync zwraca Taskwartość , nie jest używana żadna instrukcja return. Na przykład sprawdź Privacy stronę:

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()
        {
        }
    }
}

Gdy zwracany typ to IActionResult lub Task<IActionResult>, należy podać instrukcję return. Na przykład Pages/Movies/Create.cshtml.cs OnPostAsync metoda:

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

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

    return RedirectToPage("./Index");
}

Sprawdź stronę Pages/Movies/Index.cshtmlRazor :

@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 może przejść z kodu HTML do języka C# lub do Razorznaczników specyficznych. Gdy po Razor symbolu @ następuje zastrzeżone słowo kluczowe, przechodzi do znaczników specyficznych dla języka C#. W przeciwnym razie przechodzi do Razorjęzyka C#.

Dyrektywa @page

Dyrektywa @pageRazor sprawia, że plik jest akcją MVC, co oznacza, że może obsługiwać żądania. Dyrektywa @page musi być pierwszą dyrektywą Razor na stronie. @page i @model to przykłady przejścia na Razorznaczniki specyficzne dla języka . Zobacz Razor składnię , aby uzyskać więcej informacji.

Dyrektywa @model

@page
@model RazorPagesMovie.Pages.Movies.IndexModel

Dyrektywa @model określa typ modelu przekazanego Razor do strony. W poprzednim przykładzie wiersz sprawia, @model że klasa pochodna PageModel jest dostępna dla strony Razor . Model jest używany w pomocnikach @Html.DisplayNameFor HTML i @Html.DisplayForna stronie.

Sprawdź wyrażenie lambda używane w następującym pomocniku HTML:

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

Pomocnik DisplayNameFor HTML sprawdza Title właściwość przywoływane w wyrażeniu lambda, aby określić nazwę wyświetlaną. Wyrażenie lambda jest sprawdzane, a nie oceniane. Oznacza to, że nie ma naruszenia dostępu, gdy modelwartość , model.Movielub model.Movie[0] jest pusta null . Gdy wyrażenie lambda jest obliczane, na przykład przy @Html.DisplayFor(modelItem => item.Title)użyciu metody , wartości właściwości modelu są oceniane.

Strona układu

Wybierz łącza Razormenu PagesFilmy, Homei Privacy. Każda strona zawiera ten sam układ menu. Układ menu jest implementowany w Pages/Shared/_Layout.cshtml pliku.

Otwórz plik i sprawdź go Pages/Shared/_Layout.cshtml .

Szablony układów umożliwiają układ kontenera HTML:

  • Określone w jednym miejscu.
  • Zastosowane na wielu stronach w witrynie.

@RenderBody() Znajdź wiersz. RenderBody to symbol zastępczy, w którym są wyświetlane wszystkie widoki specyficzne dla strony, opakowane na stronie układu. Na przykład wybierz Privacy link, a Pages/Privacy.cshtml widok jest renderowany wewnątrz RenderBody metody .

ViewData i układ

Rozważ następujące znaczniki z Pages/Movies/Index.cshtml pliku:

@page
@model RazorPagesMovie.Pages.Movies.IndexModel

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

Powyższy wyróżniony znacznik jest przykładem Razor przejścia do języka C#. Znaki { i } otaczają blok kodu języka C#.

Klasa PageModel bazowa zawiera właściwość słownika ViewData , która może służyć do przekazywania danych do widoku. Obiekty są dodawane do słownika ViewData przy użyciu wzorca wartości klucza. W poprzednim przykładzie Title właściwość jest dodawana do słownika ViewData .

Właściwość Title jest używana w Pages/Shared/_Layout.cshtml pliku . Poniższy znacznik przedstawia kilka pierwszych wierszy _Layout.cshtml pliku.

<!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" />

Wiersz @*Markup removed for brevity.*@ jest komentarzem Razor . W przeciwieństwie do komentarzy <!-- -->Razor HTML komentarze nie są wysyłane do klienta. Aby uzyskać więcej informacji, zobacz Dokumentację internetową usługi MDN: Wprowadzenie do języka HTML .

Aktualizowanie układu

  1. <title> Zmień element w pliku, Pages/Shared/_Layout.cshtml aby wyświetlić film, a nie RazorPagesPanel.

    <!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. Znajdź następujący element zakotwiczenia w Pages/Shared/_Layout.cshtml pliku.

    <a class="navbar-brand" asp-area="" asp-page="/Index">RazorPagesMovie</a>
    
  3. Zastąp poprzedni element następującym znacznikiem:

    <a class="navbar-brand" asp-page="/Movies/Index">RpMovie</a>
    

    Poprzedni element kotwicy jest pomocnikem tagów. W tym przypadku jest to pomocnik tagu kotwicy. Atrybut asp-page="/Movies/Index" i wartość Pomocnika tagów /Movies/IndexRazor tworzą link do strony. Wartość atrybutu asp-area jest pusta, więc obszar nie jest używany w linku. Aby uzyskać więcej informacji, zobacz Obszary .

  4. Zapisz zmiany i przetestuj aplikację, wybierając link RpFilm . Jeśli masz jakiekolwiek problemy, zobacz plik _Layout.cshtml w usłudze GitHub.

  5. Przetestuj Homełącza , RpFilm, Create, Edit i Delete. Każda strona ustawia tytuł, który można wyświetlić na karcie przeglądarki. Podczas tworzenia zakładek tytuł jest używany dla zakładki.

Uwaga

W polu może nie być możliwe wprowadzenie przecinków dziesiętnych Price . Aby obsługiwać walidację jQuery dla ustawień regionalnych innych niż angielski, które używają przecinka (",") dla punktu dziesiętnego i formatów dat innych niż angielskie stany USA, należy wykonać kroki w celu globalizacji aplikacji. Zobacz ten problem z usługą GitHub 4076 , aby uzyskać instrukcje dotyczące dodawania przecinka dziesiętnego.

Właściwość Layout jest ustawiana w Pages/_ViewStart.cshtml pliku:

@{
    Layout = "_Layout";
}

Powyższy znacznik ustawia plik układu na Pages/Shared/_Layout.cshtml dla wszystkich Razor plików w folderze Pages . Aby uzyskać więcej informacji, zobacz Układ .

Model tworzenia strony

Pages/Movies/Create.cshtml.cs Sprawdź model strony:

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");
        }
    }
}

Metoda OnGet inicjuje dowolny stan wymagany dla strony. Strona Tworzenie nie ma żadnego stanu do zainicjowania, dlatego Page jest zwracana. W dalszej części samouczka zostanie wyświetlony przykład inicjowania OnGet stanu. Metoda Page tworzy PageResult obiekt renderujący Create.cshtml stronę.

Właściwość Movie używa atrybutu [BindProperty], aby wyrazić zgodę na powiązanie modelu. Gdy formularz Tworzenie publikuje wartości formularza, środowisko uruchomieniowe ASP.NET Core wiąże opublikowane wartości z modelem Movie .

Metoda OnPostAsync jest uruchamiana, gdy strona publikuje dane formularza:

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

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

    return RedirectToPage("./Index");
}

Jeśli występują jakiekolwiek błędy modelu, formularz jest odtwarzany ponownie wraz z dowolnymi opublikowanymi danymi formularza. Większość błędów modelu można przechwycić po stronie klienta przed opublikowaniem formularza. Przykładem błędu modelu jest opublikowanie wartości pola daty, którego nie można przekonwertować na datę. Walidacja po stronie klienta i walidacja modelu zostały omówione w dalszej części tego samouczka.

Jeśli nie ma żadnych błędów modelu:

  • Dane są zapisywane.
  • Przeglądarka jest przekierowywana do strony Indeks.

Strona tworzenia Razor

Pages/Movies/Create.cshtmlRazor Sprawdź plik strony:

@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");}
}

Program Visual Studio wyświetla następujące tagi w charakterystycznej czcionki pogrubionej używanej dla pomocników tagów:

  • <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>

Widok vs17 strony Create.cshtml

Element <form method="post"> jest pomocnikiem tagu formularza. Pomocnik tagu formularza automatycznie zawiera token antyforgery.

Aparat tworzenia szkieletów tworzy Razor znaczniki dla każdego pola w modelu, z wyjątkiem identyfikatora, podobnego do następującego:

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

Pomocnicy tagów walidacji (<div asp-validation-summary i <span asp-validation-for) wyświetlają błędy walidacji. Walidacja zostanie szczegółowo omówiona w dalszej części tej serii.

Pomocnik tagów etykiet (<label asp-for="Movie.Title" class="control-label"></label>) generuje etykietę podpis i [for] atrybut właściwościTitle.

Pomocnik tagów wejściowych (<input asp-for="Movie.Title" class="form-control">) używa atrybutów DataAnnotations i tworzy atrybuty HTML wymagane do weryfikacji jQuery po stronie klienta.

Aby uzyskać więcej informacji na temat pomocników tagów, takich jak <form method="post">, zobacz Pomocnicy tagów w ASP.NET Core.

Następne kroki

Strony Tworzenie, Usuwanie, Szczegóły i Edytowanie

Pages/Movies/Index.cshtml.cs Sprawdź model strony:

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 Strony pochodzą z elementu PageModel. Zgodnie z konwencją klasa pochodna PageModel nosi nazwę PageNameModel. Na przykład strona Indeks ma nazwę IndexModel.

Konstruktor używa iniekcji zależności, aby dodać element RazorPagesMovieContext do strony:

public class IndexModel : PageModel
{
    private readonly RazorPagesMovie.Data.RazorPagesMovieContext _context;

    public IndexModel(RazorPagesMovie.Data.RazorPagesMovieContext context)
    {
        _context = context;
    }

Zobacz Kod asynchroniczny, aby uzyskać więcej informacji na temat programowania asynchronicznego w programie Entity Framework.

Po wysłaniu żądania dla strony OnGetAsync metoda zwraca listę filmów do strony Razor . Razor Na stronie lub OnGet jest wywoływana w OnGetAsync celu zainicjowania stanu strony. W tym przypadku OnGetAsync pobiera listę filmów i wyświetla je.

Gdy OnGet zwraca void lub OnGetAsync zwraca Taskwartość , nie jest używana żadna instrukcja return. Na przykład sprawdź Privacy stronę:

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()
        {
        }
    }
}

Gdy zwracany typ to IActionResult lub Task<IActionResult>, należy podać instrukcję return. Na przykład Pages/Movies/Create.cshtml.csOnPostAsync metoda:

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");
}

Sprawdź stronę Pages/Movies/Index.cshtmlRazor :

@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 może przejść z kodu HTML do języka C# lub do Razorznaczników specyficznych. Gdy po Razor symbolu @ następuje zastrzeżone słowo kluczowe, przechodzi do znaczników specyficznych dla języka C#. W przeciwnym razie przechodzi do Razorjęzyka C#.

Dyrektywa @page

Dyrektywa @pageRazor sprawia, że plik jest akcją MVC, co oznacza, że może obsługiwać żądania. Dyrektywa @page musi być pierwszą dyrektywą Razor na stronie. @page i @model to przykłady przejścia na Razorznaczniki specyficzne dla języka . Zobacz Razor składnię , aby uzyskać więcej informacji.

Dyrektywa @model

@page
@model RazorPagesMovie.Pages.Movies.IndexModel

Dyrektywa @model określa typ modelu przekazanego Razor do strony. W poprzednim przykładzie wiersz sprawia, @model że klasa pochodna PageModel jest dostępna dla strony Razor . Model jest używany w pomocnikach @Html.DisplayNameFor HTML i @Html.DisplayForna stronie.

Sprawdź wyrażenie lambda używane w następującym pomocniku HTML:

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

Pomocnik DisplayNameFor HTML sprawdza Title właściwość przywoływane w wyrażeniu lambda, aby określić nazwę wyświetlaną. Wyrażenie lambda jest sprawdzane, a nie oceniane. Oznacza to, że nie ma naruszenia dostępu, gdy modelwartość , model.Movielub model.Movie[0] jest pusta null . Gdy wyrażenie lambda jest obliczane, na przykład przy @Html.DisplayFor(modelItem => item.Title)użyciu metody , wartości właściwości modelu są oceniane.

Strona układu

Wybierz łącza Razormenu PagesFilmy, Homei Privacy. Każda strona zawiera ten sam układ menu. Układ menu jest implementowany w Pages/Shared/_Layout.cshtml pliku.

Otwórz plik i sprawdź go Pages/Shared/_Layout.cshtml .

Szablony układów umożliwiają układ kontenera HTML:

  • Określone w jednym miejscu.
  • Zastosowane na wielu stronach w witrynie.

@RenderBody() Znajdź wiersz. RenderBody to symbol zastępczy, w którym są wyświetlane wszystkie widoki specyficzne dla strony, opakowane na stronie układu. Na przykład wybierz Privacy link, a Pages/Privacy.cshtml widok jest renderowany wewnątrz RenderBody metody .

ViewData i układ

Rozważ następujące znaczniki z Pages/Movies/Index.cshtml pliku:

@page
@model RazorPagesMovie.Pages.Movies.IndexModel

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

Powyższy wyróżniony znacznik jest przykładem Razor przejścia do języka C#. Znaki { i } otaczają blok kodu języka C#.

Klasa PageModel bazowa zawiera właściwość słownika ViewData , która może służyć do przekazywania danych do widoku. Obiekty są dodawane do słownika ViewData przy użyciu wzorca wartości klucza. W poprzednim przykładzie Title właściwość jest dodawana do słownika ViewData .

Właściwość Title jest używana w Pages/Shared/_Layout.cshtml pliku . Poniższy znacznik przedstawia kilka pierwszych wierszy _Layout.cshtml pliku.

<!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" />

Wiersz @*Markup removed for brevity.*@ jest komentarzem Razor . W przeciwieństwie do komentarzy <!-- -->Razor HTML komentarze nie są wysyłane do klienta. Aby uzyskać więcej informacji, zobacz Dokumentację internetową usługi MDN: Wprowadzenie do języka HTML .

Aktualizowanie układu

  1. <title> Zmień element w pliku, Pages/Shared/_Layout.cshtml aby wyświetlić film, a nie RazorPagesPanel.

    <!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. Znajdź następujący element zakotwiczenia w Pages/Shared/_Layout.cshtml pliku.

    <a class="navbar-brand" asp-area="" asp-page="/Index">RazorPagesMovie</a>
    
  3. Zastąp poprzedni element następującym znacznikiem:

    <a class="navbar-brand" asp-page="/Movies/Index">RpMovie</a>
    

    Poprzedni element kotwicy jest pomocnikem tagów. W tym przypadku jest to pomocnik tagu kotwicy. Atrybut asp-page="/Movies/Index" i wartość Pomocnika tagów /Movies/IndexRazor tworzą link do strony. Wartość atrybutu asp-area jest pusta, więc obszar nie jest używany w linku. Aby uzyskać więcej informacji, zobacz Obszary .

  4. Zapisz zmiany i przetestuj aplikację, wybierając link RpFilm . Jeśli masz jakiekolwiek problemy, zobacz plik _Layout.cshtml w usłudze GitHub.

  5. Przetestuj Homełącza , RpFilm, Create, Edit i Delete. Każda strona ustawia tytuł, który można wyświetlić na karcie przeglądarki. Podczas tworzenia zakładek tytuł jest używany dla zakładki.

Uwaga

W polu może nie być możliwe wprowadzenie przecinków dziesiętnych Price . Aby obsługiwać walidację jQuery dla ustawień regionalnych innych niż angielski, które używają przecinka (",") dla punktu dziesiętnego i formatów dat innych niż angielskie stany USA, należy wykonać kroki w celu globalizacji aplikacji. Zobacz ten problem z usługą GitHub 4076 , aby uzyskać instrukcje dotyczące dodawania przecinka dziesiętnego.

Właściwość Layout jest ustawiana w Pages/_ViewStart.cshtml pliku:

@{
    Layout = "_Layout";
}

Powyższy znacznik ustawia plik układu na Pages/Shared/_Layout.cshtml dla wszystkich Razor plików w folderze Pages . Aby uzyskać więcej informacji, zobacz Układ .

Model tworzenia strony

Pages/Movies/Create.cshtml.cs Sprawdź model strony:

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");
        }
    }
}

Metoda OnGet inicjuje dowolny stan wymagany dla strony. Strona Tworzenie nie ma żadnego stanu do zainicjowania, dlatego Page jest zwracana. W dalszej części samouczka zostanie wyświetlony przykład inicjowania OnGet stanu. Metoda Page tworzy PageResult obiekt renderujący Create.cshtml stronę.

Właściwość Movie używa atrybutu [BindProperty], aby wyrazić zgodę na powiązanie modelu. Gdy formularz Tworzenie publikuje wartości formularza, środowisko uruchomieniowe ASP.NET Core wiąże opublikowane wartości z modelem Movie .

Metoda OnPostAsync jest uruchamiana, gdy strona publikuje dane formularza:

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");
}

Jeśli występują jakiekolwiek błędy modelu, formularz jest odtwarzany ponownie wraz z dowolnymi opublikowanymi danymi formularza. Większość błędów modelu można przechwycić po stronie klienta przed opublikowaniem formularza. Przykładem błędu modelu jest opublikowanie wartości pola daty, którego nie można przekonwertować na datę. Walidacja po stronie klienta i walidacja modelu zostały omówione w dalszej części tego samouczka.

Jeśli nie ma żadnych błędów modelu:

  • Dane są zapisywane.
  • Przeglądarka jest przekierowywana do strony Indeks.

Strona tworzenia Razor

Pages/Movies/Create.cshtmlRazor Sprawdź plik strony:

@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");}
}

Program Visual Studio wyświetla następujące tagi w charakterystycznej czcionki pogrubionej używanej dla pomocników tagów:

  • <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>

Widok vs17 strony Create.cshtml

Element <form method="post"> jest pomocnikiem tagu formularza. Pomocnik tagu formularza automatycznie zawiera token antyforgery.

Aparat tworzenia szkieletów tworzy Razor znaczniki dla każdego pola w modelu, z wyjątkiem identyfikatora, podobnego do następującego:

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

Pomocnicy tagów walidacji (<div asp-validation-summary i <span asp-validation-for) wyświetlają błędy walidacji. Walidacja zostanie szczegółowo omówiona w dalszej części tej serii.

Pomocnik tagów etykiet (<label asp-for="Movie.Title" class="control-label"></label>) generuje etykietę podpis i [for] atrybut właściwościTitle.

Pomocnik tagów wejściowych (<input asp-for="Movie.Title" class="form-control">) używa atrybutów DataAnnotations i tworzy atrybuty HTML wymagane do weryfikacji jQuery po stronie klienta.

Aby uzyskać więcej informacji na temat pomocników tagów, takich jak <form method="post">, zobacz Pomocnicy tagów w ASP.NET Core.

Następne kroki

Strony Tworzenie, Usuwanie, Szczegóły i Edytowanie

Pages/Movies/Index.cshtml.cs Sprawdź model strony:

// 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 Strony pochodzą z elementu PageModel. Zgodnie z konwencją klasa pochodna PageModelnosi nazwę <PageName>Model. Konstruktor używa iniekcji zależności, aby dodać element RazorPagesMovieContext do strony:

public class IndexModel : PageModel
{
    private readonly RazorPagesMovie.Data.RazorPagesMovieContext _context;

    public IndexModel(RazorPagesMovie.Data.RazorPagesMovieContext context)
    {
        _context = context;
    }

Zobacz Kod asynchroniczny, aby uzyskać więcej informacji na temat programowania asynchronicznego w programie Entity Framework.

Po wysłaniu żądania dla strony OnGetAsync metoda zwraca listę filmów do strony Razor . Razor Na stronie lub OnGet jest wywoływana w OnGetAsync celu zainicjowania stanu strony. W tym przypadku OnGetAsync pobiera listę filmów i wyświetla je.

Gdy OnGet zwraca void lub OnGetAsync zwraca Taskwartość , nie jest używana żadna instrukcja return. Na przykład Privacy strona:

public class PrivacyModel : PageModel
{
    private readonly ILogger<PrivacyModel> _logger;

    public PrivacyModel(ILogger<PrivacyModel> logger)
    {
        _logger = logger;
    }

    public void OnGet()
    {
    }
}

Gdy zwracany typ to IActionResult lub Task<IActionResult>, należy podać instrukcję return. Na przykład Pages/Movies/Create.cshtml.csOnPostAsync metoda:

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

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

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

Sprawdź stronę Pages/Movies/Index.cshtmlRazor :

@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 może przejść z kodu HTML do języka C# lub do Razorznaczników specyficznych. Gdy po Razor symbolu @ następuje zastrzeżone słowo kluczowe, przechodzi do znaczników specyficznych dla języka C#. W przeciwnym razie przechodzi do Razorjęzyka C#.

Dyrektywa @page

Dyrektywa @pageRazor sprawia, że plik jest akcją MVC, co oznacza, że może obsługiwać żądania. Dyrektywa @page musi być pierwszą dyrektywą Razor na stronie. @page i @model to przykłady przejścia na Razorznaczniki specyficzne dla języka . Zobacz Razor składnię , aby uzyskać więcej informacji.

Dyrektywa @model

@page
@model RazorPagesMovie.Pages.Movies.IndexModel

Dyrektywa @model określa typ modelu przekazanego Razor do strony. W poprzednim przykładzie wiersz sprawia, że @model klasa pochodna PageModeljest dostępna dla Razor strony. Model jest używany w pomocnikach @Html.DisplayNameFor HTML i @Html.DisplayForna stronie.

Sprawdź wyrażenie lambda używane w następującym pomocniku HTML:

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

Pomocnik DisplayNameFor HTML sprawdza Title właściwość przywoływane w wyrażeniu lambda, aby określić nazwę wyświetlaną. Wyrażenie lambda jest sprawdzane, a nie oceniane. Oznacza to, że nie ma naruszenia dostępu, gdy modelwartość , model.Movielub model.Movie[0] jest pusta null . Gdy wyrażenie lambda jest obliczane, na przykład przy @Html.DisplayFor(modelItem => item.Title)użyciu metody , wartości właściwości modelu są oceniane.

Strona układu

Wybierz łącza Razormenu PagesFilmy, Homei Privacy. Każda strona zawiera ten sam układ menu. Układ menu jest implementowany w Pages/Shared/_Layout.cshtml pliku.

Otwórz plik i sprawdź go Pages/Shared/_Layout.cshtml .

Szablony układów umożliwiają układ kontenera HTML:

  • Określone w jednym miejscu.
  • Zastosowane na wielu stronach w witrynie.

@RenderBody() Znajdź wiersz. RenderBody to symbol zastępczy, w którym są wyświetlane wszystkie widoki specyficzne dla strony, opakowane na stronie układu. Na przykład wybierz Privacy link, a Pages/Privacy.cshtml widok jest renderowany wewnątrz RenderBody metody .

ViewData i układ

Rozważ następujące znaczniki z Pages/Movies/Index.cshtml pliku:

@page
@model RazorPagesMovie.Pages.Movies.IndexModel

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

Powyższy wyróżniony znacznik jest przykładem Razor przejścia do języka C#. Znaki { i } otaczają blok kodu języka C#.

Klasa PageModel bazowa zawiera właściwość słownika ViewData , która może służyć do przekazywania danych do widoku. Obiekty są dodawane do słownika ViewData przy użyciu wzorca wartości klucza. W poprzednim przykładzie Title właściwość jest dodawana do słownika ViewData .

Właściwość Title jest używana w Pages/Shared/_Layout.cshtml pliku . Poniższy znacznik przedstawia kilka pierwszych wierszy _Layout.cshtml pliku.

<!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.*@

Wiersz @*Markup removed for brevity.*@ jest komentarzem Razor . W przeciwieństwie do komentarzy <!-- -->Razor HTML komentarze nie są wysyłane do klienta. Aby uzyskać więcej informacji, zobacz Dokumentację internetową usługi MDN: Wprowadzenie do języka HTML .

Aktualizowanie układu

  1. <title> Zmień element w pliku, Pages/Shared/_Layout.cshtml aby wyświetlić film, a nie RazorPagesPanel.

    <!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. Znajdź następujący element zakotwiczenia w Pages/Shared/_Layout.cshtml pliku.

    <a class="navbar-brand" asp-area="" asp-page="/Index">RazorPagesMovie</a>
    
  3. Zastąp poprzedni element następującym znacznikiem:

    <a class="navbar-brand" asp-page="/Movies/Index">RpMovie</a>
    

    Poprzedni element kotwicy jest pomocnikem tagów. W tym przypadku jest to pomocnik tagu kotwicy. Atrybut asp-page="/Movies/Index" i wartość Pomocnika tagów /Movies/IndexRazor tworzą link do strony. Wartość atrybutu asp-area jest pusta, więc obszar nie jest używany w linku. Aby uzyskać więcej informacji, zobacz Obszary .

  4. Zapisz zmiany i przetestuj aplikację, wybierając link RpFilm . Jeśli masz jakiekolwiek problemy, zobacz plik _Layout.cshtml w usłudze GitHub.

  5. Przetestuj Homełącza , RpFilm, Create, Edit i Delete. Każda strona ustawia tytuł, który można wyświetlić na karcie przeglądarki. Podczas tworzenia zakładek tytuł jest używany dla zakładki.

Uwaga

W polu może nie być możliwe wprowadzenie przecinków dziesiętnych Price . Aby obsługiwać walidację jQuery dla ustawień regionalnych innych niż angielski, które używają przecinka (",") dla punktu dziesiętnego i formatów dat innych niż angielskie stany USA, należy wykonać kroki w celu globalizacji aplikacji. Zobacz ten problem z usługą GitHub 4076 , aby uzyskać instrukcje dotyczące dodawania przecinka dziesiętnego.

Właściwość Layout jest ustawiana w Pages/_ViewStart.cshtml pliku:

@{
    Layout = "_Layout";
}

Powyższy znacznik ustawia plik układu na Pages/Shared/_Layout.cshtml dla wszystkich Razor plików w folderze Pages . Aby uzyskać więcej informacji, zobacz Układ .

Model tworzenia strony

Pages/Movies/Create.cshtml.cs Sprawdź model strony:

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");
        }
    }
}

Metoda OnGet inicjuje dowolny stan wymagany dla strony. Strona Tworzenie nie ma żadnego stanu do zainicjowania, dlatego Page jest zwracana. W dalszej części samouczka zostanie wyświetlony przykład inicjowania OnGet stanu. Metoda Page tworzy PageResult obiekt renderujący Create.cshtml stronę.

Właściwość Movie używa atrybutu [BindProperty], aby wyrazić zgodę na powiązanie modelu. Gdy formularz Tworzenie publikuje wartości formularza, środowisko uruchomieniowe ASP.NET Core wiąże opublikowane wartości z modelem Movie .

Metoda OnPostAsync jest uruchamiana, gdy strona publikuje dane formularza:

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

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

    return RedirectToPage("./Index");
}

Jeśli występują jakiekolwiek błędy modelu, formularz jest odtwarzany ponownie wraz z dowolnymi opublikowanymi danymi formularza. Większość błędów modelu można przechwycić po stronie klienta przed opublikowaniem formularza. Przykładem błędu modelu jest opublikowanie wartości pola daty, którego nie można przekonwertować na datę. Walidacja po stronie klienta i walidacja modelu zostały omówione w dalszej części tego samouczka.

Jeśli nie ma żadnych błędów modelu:

  • Dane są zapisywane.
  • Przeglądarka jest przekierowywana do strony Indeks.

Strona tworzenia Razor

Pages/Movies/Create.cshtmlRazor Sprawdź plik strony:

@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");}
}

Program Visual Studio wyświetla następujące tagi w charakterystycznej czcionki pogrubionej używanej dla pomocników tagów:

  • <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>

Widok vs17 strony Create.cshtml

Element <form method="post"> jest pomocnikiem tagu formularza. Pomocnik tagu formularza automatycznie zawiera token antyforgery.

Aparat tworzenia szkieletów tworzy Razor znaczniki dla każdego pola w modelu, z wyjątkiem identyfikatora, podobnego do następującego:

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

Pomocnicy tagów walidacji (<div asp-validation-summary i <span asp-validation-for) wyświetlają błędy walidacji. Walidacja zostanie szczegółowo omówiona w dalszej części tej serii.

Pomocnik tagów etykiet (<label asp-for="Movie.Title" class="control-label"></label>) generuje etykietę podpis i [for] atrybut właściwościTitle.

Pomocnik tagów wejściowych (<input asp-for="Movie.Title" class="form-control">) używa atrybutów DataAnnotations i tworzy atrybuty HTML wymagane do weryfikacji jQuery po stronie klienta.

Aby uzyskać więcej informacji na temat pomocników tagów, takich jak <form method="post">, zobacz Pomocnicy tagów w ASP.NET Core.

Następne kroki