Partie 3, pages Razor obtenues par génération de modèles automatique dans ASP.NET Core

Remarque

Ceci n’est pas la dernière version de cet article. Pour la version actuelle, consultez la version .NET 8 de cet article.

Important

Ces informations portent sur la préversion du produit, qui est susceptible d’être en grande partie modifié avant sa commercialisation. Microsoft n’offre aucune garantie, expresse ou implicite, concernant les informations fournies ici.

Pour la version actuelle, consultez la version .NET 8 de cet article.

Par Rick Anderson

Ce tutoriel décrit les pages Razor créées par génération de modèles automatique dans le tutoriel précédent.

Pages Create, Delete, Details et Edit

Examinez le modèle de page Pages/Movies/Index.cshtml.cs :

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

Les pages Razor sont dérivées de PageModel. Par convention, la classe dérivée de PageModel s’appelle PageNameModel. Par exemple, la page Index est nommée IndexModel.

Le constructeur utilise l’injection de dépendances pour ajouter RazorPagesMovieContext à la page :

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

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

Consultez Code asynchrone pour plus d’informations sur la programmation asynchrone avec Entity Framework.

Quand une demande GET est effectuée pour la page, la méthode OnGetAsync retourne une liste de films à la page Razor. Dans une page Razor, OnGetAsync ou OnGet est appelée pour initialiser l’état de la page. Dans ce cas, OnGetAsync obtient une liste de films et les affiche.

Si OnGet retourne void ou que OnGetAsync retourne Task, aucune instruction return n’est utilisée. Par exemple, examinez la page Privacy :

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

Lorsque le type de retour est IActionResult ou Task<IActionResult>, une instruction de retour doit être spécifiée. Par exemple, la méthode Pages/Movies/Create.cshtml.cs OnPostAsync :

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

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

    return RedirectToPage("./Index");
}

Examinez la page RazorPages/Movies/Index.cshtml :

@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 peut passer du code HTML à du code C# ou au balisage spécifique à Razor. Quand un symbole @ est suivi d’un mot clé réservé Razor, il est converti en balisage spécifique à Razor. Sinon, il est converti en C#.

Directive @page

La directive Razor@page transforme le fichier en action MVC, ce qui lui permet de traiter des demandes. @page doit être la première directive Razor sur une page. @page et @model sont des exemples de transition vers un balisage spécifique à Razor. Consultez Syntaxe Razor pour plus d’informations.

Directive @model

@page
@model RazorPagesMovie.Pages.Movies.IndexModel

La directive @model spécifie le type du modèle passé à la page Razor. Dans l’exemple précédent, la ligne @model rend la classe dérivée de PageModel accessible à la page Razor. Le modèle est utilisé dans les HTML Helpers@Html.DisplayNameFor et @Html.DisplayFor de la page.

Examinez l’expression lambda utilisée dans le HTML Helper suivant :

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

Le HTML Helper DisplayNameFor inspecte la propriété Title référencée dans l’expression lambda pour déterminer le nom d’affichage. L’expression lambda est inspectée plutôt qu’évaluée. Cela signifie qu’il n’existe pas de violation d’accès quand model, model.Movie ou model.Movie[0] a la valeur null ou est vide. Quand l’expression lambda est évaluée, par exemple avec @Html.DisplayFor(modelItem => item.Title), les valeurs de propriété du modèle sont évaluées.

La page de disposition

Sélectionnez les liens de menu RazorPagesMovie, Home et Privacy. Chaque page affiche la même disposition de menu. La disposition du menu est implémentée dans le fichier Pages/Shared/_Layout.cshtml.

Ouvrez et examinez le fichier Pages/Shared/_Layout.cshtml.

Les modèles de Disposition permettent que la disposition du conteneur HTML soit :

  • spécifiée à un seul endroit ;
  • appliquée à plusieurs pages du site.

Recherchez la ligne @RenderBody(). RenderBody est un espace réservé dans lequel toutes les vues propres à la page s’affichent, encapsulées dans la page de disposition. Par exemple, sélectionnez le lien Privacy et la vue Pages/Privacy.cshtml est affichée à l’intérieur de la méthode RenderBody.

ViewData et disposition

Examinez le balisage suivant à partir du fichier Pages/Movies/Index.cshtml :

@page
@model RazorPagesMovie.Pages.Movies.IndexModel

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

Le balisage précédent en surbrillance est un exemple de conversion de Razor vers C#. Les caractères { et } délimitent un bloc de code C#.

La classe de base PageModel contient une propriété de dictionnaire ViewData qui peut être utilisée pour transmettre des données à une vue. Des objets sont ajoutés au dictionnaire ViewData à l’aide d’un modèle clé valeur. Dans l’exemple précédent, la propriété Title est ajoutée au dictionnaire ViewData.

La propriété Title est utilisée dans le fichier Pages/Shared/_Layout.cshtml. Le balisage suivant montre les premières lignes du fichier _Layout.cshtml.

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

Mettre à jour la disposition

  1. Changez l’élément <title> dans le fichier Pages/Shared/_Layout.cshtml pour afficher Movie au lieu de RazorPagesMovie.

    <!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. Recherchez l’élément anchor suivant dans le fichier Pages/Shared/_Layout.cshtml.

    <a class="navbar-brand" asp-area="" asp-page="/Index">RazorPagesMovie</a>
    
  3. Remplacez l’élément précédent par la balise suivante :

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

    L’élément anchor précédent est un Tag Helper. Dans le cas présent, il s’agit du Tag Helper d’ancre. L’attribut et la valeur du Tag Helper asp-page="/Movies/Index" créent un lien vers la page Razor/Movies/Index. La valeur de l’attribut asp-area est vide : la zone n’est donc pas utilisée dans le lien. Pour plus d’informations, consultez Zones.

  4. Enregistrez les modifications et testez l’application en sélectionnant le lien RpMovie. Consultez le fichier _Layout.cshtml dans GitHub si vous rencontrez des problèmes.

  5. Testez les liens Home, RpMovie, Create, Edit et Delete. Chaque page définit le titre, que vous pouvez voir dans l’onglet du navigateur. Quand vous définissez un signet pour une page, le titre est affecté au signet.

Notes

Vous ne pourrez peut-être pas entrer de virgules décimales dans le champ Price. Pour prendre en charge la validation jQuery pour les paramètres régionaux autres que l’anglais qui utilisent une virgule (« , ») comme point décimal, et des formats de date autres que l’anglais des États-Unis, vous devez prendre des mesures pour mondialiser l’application. Consultez cette page GitHub problème 4076 pour savoir comment ajouter une virgule décimale.

La propriété Layout est définie dans le fichier Pages/_ViewStart.cshtml :

@{
    Layout = "_Layout";
}

Le balisage précédent définit le fichier de disposition Pages/Shared/_Layout.cshtml pour tous les fichiers Razor du dossier Pages. Pour plus d’informations, consultez Disposition.

Le modèle de page Create

Examinez le modèle de page 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");
        }
    }
}

La méthode OnGet initialise l’état nécessaire pour la page. La page Create n’ayant aucun état à initialiser, Page est retourné. Plus loin dans le tutoriel, un exemple d’état d’initialisation OnGet est affiché. La méthode Page crée un objet PageResult qui affiche la page Create.cshtml.

La propriété Movie utilise l’attribut [BindProperty] pour adhérer à la liaison de modèles. Quand le formulaire Create publie les valeurs de formulaire, le runtime ASP.NET Core lie les valeurs publiées au modèle Movie.

La méthode OnPostAsync est exécutée quand la page publie les données de formulaire :

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

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

    return RedirectToPage("./Index");
}

S’il existe des erreurs liées au modèle, le formulaire est réaffiché, ainsi que toutes les données de formulaire publiées. La plupart des erreurs de modèle peuvent être interceptées côté client avant la publication du formulaire. Voici un exemple d’erreur de modèle : la publication pour le champ de date d’une valeur qui ne peut pas être convertie en date. La validation côté client et la validation du modèle sont présentées plus loin dans le tutoriel.

S’il n’y a pas d’erreurs de modèle :

  • Les données sont enregistrées.
  • Le navigateur est redirigé vers la page Index.

Page Razor Create

Examinez le fichier de page RazorPages/Movies/Create.cshtml :

@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 affiche la balise suivante dans une police différenciée en gras utilisée pour les Tag Helpers :

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

Vue VS17 de la page Create.cshtml

L’élément <form method="post"> est un Tag Helper de formulaire. Le Tag Helper de formulaire inclut automatiquement un jeton de protection contre les falsifications.

Le moteur de génération de modèles automatique crée le balisage Razor pour chaque champ du modèle, sauf l’ID, de la manière suivante :

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

Les Tag Helpers de validation (<div asp-validation-summary et <span asp-validation-for) affichent des erreurs de validation. La validation est traitée de manière plus détaillée plus loin dans cette série.

Le Tag Helper d’étiquette (<label asp-for="Movie.Title" class="control-label"></label>) génère la légende de l’étiquette et l’attribut [for] pour la propriété Title.

Le Tag Helper d’entrée (<input asp-for="Movie.Title" class="form-control">) utilise les attributs DataAnnotations et produit les attributs HTML nécessaires à la validation jQuery côté client.

Pour plus d’informations sur les Tag Helpers, comme <form method="post">, consultez Tag Helpers dans ASP.NET Core.

Étapes suivantes

Pages Create, Delete, Details et Edit

Examinez le modèle de page Pages/Movies/Index.cshtml.cs :

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

Les pages Razor sont dérivées de PageModel. Par convention, la classe dérivée de PageModel s’appelle PageNameModel. Par exemple, la page Index est nommée IndexModel.

Le constructeur utilise l’injection de dépendances pour ajouter RazorPagesMovieContext à la page :

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

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

Consultez Code asynchrone pour plus d’informations sur la programmation asynchrone avec Entity Framework.

Quand une demande GET est effectuée pour la page, la méthode OnGetAsync retourne une liste de films à la page Razor. Dans une page Razor, OnGetAsync ou OnGet est appelée pour initialiser l’état de la page. Dans ce cas, OnGetAsync obtient une liste de films et les affiche.

Si OnGet retourne void ou que OnGetAsync retourne Task, aucune instruction return n’est utilisée. Par exemple, examinez la page Privacy :

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

Lorsque le type de retour est IActionResult ou Task<IActionResult>, une instruction de retour doit être spécifiée. Par exemple, la méthode Pages/Movies/Create.cshtml.cs OnPostAsync :

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

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

    return RedirectToPage("./Index");
}

Examinez la page RazorPages/Movies/Index.cshtml :

@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 peut passer du code HTML à du code C# ou au balisage spécifique à Razor. Quand un symbole @ est suivi d’un mot clé réservé Razor, il est converti en balisage spécifique à Razor. Sinon, il est converti en C#.

Directive @page

La directive Razor@page transforme le fichier en action MVC, ce qui lui permet de traiter des demandes. @page doit être la première directive Razor sur une page. @page et @model sont des exemples de transition vers un balisage spécifique à Razor. Consultez Syntaxe Razor pour plus d’informations.

Directive @model

@page
@model RazorPagesMovie.Pages.Movies.IndexModel

La directive @model spécifie le type du modèle passé à la page Razor. Dans l’exemple précédent, la ligne @model rend la classe dérivée de PageModel accessible à la page Razor. Le modèle est utilisé dans les HTML Helpers@Html.DisplayNameFor et @Html.DisplayFor de la page.

Examinez l’expression lambda utilisée dans le HTML Helper suivant :

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

Le HTML Helper DisplayNameFor inspecte la propriété Title référencée dans l’expression lambda pour déterminer le nom d’affichage. L’expression lambda est inspectée plutôt qu’évaluée. Cela signifie qu’il n’existe pas de violation d’accès quand model, model.Movie ou model.Movie[0] a la valeur null ou est vide. Quand l’expression lambda est évaluée, par exemple avec @Html.DisplayFor(modelItem => item.Title), les valeurs de propriété du modèle sont évaluées.

La page de disposition

Sélectionnez les liens de menu RazorPagesMovie, Home et Privacy. Chaque page affiche la même disposition de menu. La disposition du menu est implémentée dans le fichier Pages/Shared/_Layout.cshtml.

Ouvrez et examinez le fichier Pages/Shared/_Layout.cshtml.

Les modèles de Disposition permettent que la disposition du conteneur HTML soit :

  • spécifiée à un seul endroit ;
  • appliquée à plusieurs pages du site.

Recherchez la ligne @RenderBody(). RenderBody est un espace réservé dans lequel toutes les vues propres à la page s’affichent, encapsulées dans la page de disposition. Par exemple, sélectionnez le lien Privacy et la vue Pages/Privacy.cshtml est affichée à l’intérieur de la méthode RenderBody.

ViewData et disposition

Examinez le balisage suivant à partir du fichier Pages/Movies/Index.cshtml :

@page
@model RazorPagesMovie.Pages.Movies.IndexModel

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

Le balisage précédent en surbrillance est un exemple de conversion de Razor vers C#. Les caractères { et } délimitent un bloc de code C#.

La classe de base PageModel contient une propriété de dictionnaire ViewData qui peut être utilisée pour transmettre des données à une vue. Des objets sont ajoutés au dictionnaire ViewData à l’aide d’un modèle clé valeur. Dans l’exemple précédent, la propriété Title est ajoutée au dictionnaire ViewData.

La propriété Title est utilisée dans le fichier Pages/Shared/_Layout.cshtml. Le balisage suivant montre les premières lignes du fichier _Layout.cshtml.

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

La ligne @*Markup removed for brevity.*@ est un commentaire Razor. Contrairement aux commentaires HTML <!-- -->, les commentaires Razor ne sont pas envoyés au client. Consultez Documents web MDN : Prise en main du code HTML pour plus d’informations.

Mettre à jour la disposition

  1. Changez l’élément <title> dans le fichier Pages/Shared/_Layout.cshtml pour afficher Movie au lieu de RazorPagesMovie.

    <!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. Recherchez l’élément anchor suivant dans le fichier Pages/Shared/_Layout.cshtml.

    <a class="navbar-brand" asp-area="" asp-page="/Index">RazorPagesMovie</a>
    
  3. Remplacez l’élément précédent par la balise suivante :

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

    L’élément anchor précédent est un Tag Helper. Dans le cas présent, il s’agit du Tag Helper d’ancre. L’attribut et la valeur du Tag Helper asp-page="/Movies/Index" créent un lien vers la page Razor/Movies/Index. La valeur de l’attribut asp-area est vide : la zone n’est donc pas utilisée dans le lien. Pour plus d’informations, consultez Zones.

  4. Enregistrez les modifications et testez l’application en sélectionnant le lien RpMovie. Consultez le fichier _Layout.cshtml dans GitHub si vous rencontrez des problèmes.

  5. Testez les liens Home, RpMovie, Create, Edit et Delete. Chaque page définit le titre, que vous pouvez voir dans l’onglet du navigateur. Quand vous définissez un signet pour une page, le titre est affecté au signet.

Notes

Vous ne pourrez peut-être pas entrer de virgules décimales dans le champ Price. Pour prendre en charge la validation jQuery pour les paramètres régionaux autres que l’anglais qui utilisent une virgule (« , ») comme point décimal, et des formats de date autres que l’anglais des États-Unis, vous devez prendre des mesures pour mondialiser l’application. Consultez cette page GitHub problème 4076 pour savoir comment ajouter une virgule décimale.

La propriété Layout est définie dans le fichier Pages/_ViewStart.cshtml :

@{
    Layout = "_Layout";
}

Le balisage précédent définit le fichier de disposition Pages/Shared/_Layout.cshtml pour tous les fichiers Razor du dossier Pages. Pour plus d’informations, consultez Disposition.

Le modèle de page Create

Examinez le modèle de page 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");
        }
    }
}

La méthode OnGet initialise l’état nécessaire pour la page. La page Create n’ayant aucun état à initialiser, Page est retourné. Plus loin dans le tutoriel, un exemple d’état d’initialisation OnGet est affiché. La méthode Page crée un objet PageResult qui affiche la page Create.cshtml.

La propriété Movie utilise l’attribut [BindProperty] pour adhérer à la liaison de modèles. Quand le formulaire Create publie les valeurs de formulaire, le runtime ASP.NET Core lie les valeurs publiées au modèle Movie.

La méthode OnPostAsync est exécutée quand la page publie les données de formulaire :

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

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

    return RedirectToPage("./Index");
}

S’il existe des erreurs liées au modèle, le formulaire est réaffiché, ainsi que toutes les données de formulaire publiées. La plupart des erreurs de modèle peuvent être interceptées côté client avant la publication du formulaire. Voici un exemple d’erreur de modèle : la publication pour le champ de date d’une valeur qui ne peut pas être convertie en date. La validation côté client et la validation du modèle sont présentées plus loin dans le tutoriel.

S’il n’y a pas d’erreurs de modèle :

  • Les données sont enregistrées.
  • Le navigateur est redirigé vers la page Index.

Page Razor Create

Examinez le fichier de page RazorPages/Movies/Create.cshtml :

@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 affiche la balise suivante dans une police différenciée en gras utilisée pour les Tag Helpers :

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

Vue VS17 de la page Create.cshtml

L’élément <form method="post"> est un Tag Helper de formulaire. Le Tag Helper de formulaire inclut automatiquement un jeton de protection contre les falsifications.

Le moteur de génération de modèles automatique crée le balisage Razor pour chaque champ du modèle, sauf l’ID, de la manière suivante :

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

Les Tag Helpers de validation (<div asp-validation-summary et <span asp-validation-for) affichent des erreurs de validation. La validation est traitée de manière plus détaillée plus loin dans cette série.

Le Tag Helper d’étiquette (<label asp-for="Movie.Title" class="control-label"></label>) génère la légende de l’étiquette et l’attribut [for] pour la propriété Title.

Le Tag Helper d’entrée (<input asp-for="Movie.Title" class="form-control">) utilise les attributs DataAnnotations et produit les attributs HTML nécessaires à la validation jQuery côté client.

Pour plus d’informations sur les Tag Helpers, comme <form method="post">, consultez Tag Helpers dans ASP.NET Core.

Étapes suivantes

Pages Create, Delete, Details et Edit

Examinez le modèle de page Pages/Movies/Index.cshtml.cs :

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

Les pages Razor sont dérivées de PageModel. Par convention, la classe dérivée de PageModel s’appelle PageNameModel. Par exemple, la page Index est nommée IndexModel.

Le constructeur utilise l’injection de dépendances pour ajouter RazorPagesMovieContext à la page :

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

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

Consultez Code asynchrone pour plus d’informations sur la programmation asynchrone avec Entity Framework.

Quand une demande est effectuée pour la page, la méthode OnGetAsync retourne une liste de films à la page Razor. Dans une page Razor, OnGetAsync ou OnGet est appelée pour initialiser l’état de la page. Dans ce cas, OnGetAsync obtient une liste de films et les affiche.

Si OnGet retourne void ou que OnGetAsync retourne Task, aucune instruction return n’est utilisée. Par exemple, examinez la page Privacy :

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

Lorsque le type de retour est IActionResult ou Task<IActionResult>, une instruction de retour doit être spécifiée. Par exemple, la méthode Pages/Movies/Create.cshtml.csOnPostAsync :

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

Examinez la page RazorPages/Movies/Index.cshtml :

@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 peut passer du code HTML à du code C# ou au balisage spécifique à Razor. Quand un symbole @ est suivi d’un mot clé réservé Razor, il est converti en balisage spécifique à Razor. Sinon, il est converti en C#.

Directive @page

La directive Razor@page transforme le fichier en action MVC, ce qui lui permet de traiter des demandes. @page doit être la première directive Razor sur une page. @page et @model sont des exemples de transition vers un balisage spécifique à Razor. Consultez Syntaxe Razor pour plus d’informations.

Directive @model

@page
@model RazorPagesMovie.Pages.Movies.IndexModel

La directive @model spécifie le type du modèle passé à la page Razor. Dans l’exemple précédent, la ligne @model rend la classe dérivée de PageModel accessible à la page Razor. Le modèle est utilisé dans les HTML Helpers@Html.DisplayNameFor et @Html.DisplayFor de la page.

Examinez l’expression lambda utilisée dans le HTML Helper suivant :

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

Le HTML Helper DisplayNameFor inspecte la propriété Title référencée dans l’expression lambda pour déterminer le nom d’affichage. L’expression lambda est inspectée plutôt qu’évaluée. Cela signifie qu’il n’existe pas de violation d’accès quand model, model.Movie ou model.Movie[0] a la valeur null ou est vide. Quand l’expression lambda est évaluée, par exemple avec @Html.DisplayFor(modelItem => item.Title), les valeurs de propriété du modèle sont évaluées.

La page de disposition

Sélectionnez les liens de menu RazorPagesMovie, Home et Privacy. Chaque page affiche la même disposition de menu. La disposition du menu est implémentée dans le fichier Pages/Shared/_Layout.cshtml.

Ouvrez et examinez le fichier Pages/Shared/_Layout.cshtml.

Les modèles de Disposition permettent que la disposition du conteneur HTML soit :

  • spécifiée à un seul endroit ;
  • appliquée à plusieurs pages du site.

Recherchez la ligne @RenderBody(). RenderBody est un espace réservé dans lequel toutes les vues propres à la page s’affichent, encapsulées dans la page de disposition. Par exemple, sélectionnez le lien Privacy et la vue Pages/Privacy.cshtml est affichée à l’intérieur de la méthode RenderBody.

ViewData et disposition

Examinez le balisage suivant à partir du fichier Pages/Movies/Index.cshtml :

@page
@model RazorPagesMovie.Pages.Movies.IndexModel

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

Le balisage précédent en surbrillance est un exemple de conversion de Razor vers C#. Les caractères { et } délimitent un bloc de code C#.

La classe de base PageModel contient une propriété de dictionnaire ViewData qui peut être utilisée pour transmettre des données à une vue. Des objets sont ajoutés au dictionnaire ViewData à l’aide d’un modèle clé valeur. Dans l’exemple précédent, la propriété Title est ajoutée au dictionnaire ViewData.

La propriété Title est utilisée dans le fichier Pages/Shared/_Layout.cshtml. Le balisage suivant montre les premières lignes du fichier _Layout.cshtml.

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

La ligne @*Markup removed for brevity.*@ est un commentaire Razor. Contrairement aux commentaires HTML <!-- -->, les commentaires Razor ne sont pas envoyés au client. Consultez Documents web MDN : Prise en main du code HTML pour plus d’informations.

Mettre à jour la disposition

  1. Changez l’élément <title> dans le fichier Pages/Shared/_Layout.cshtml pour afficher Movie au lieu de RazorPagesMovie.

    <!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. Recherchez l’élément anchor suivant dans le fichier Pages/Shared/_Layout.cshtml.

    <a class="navbar-brand" asp-area="" asp-page="/Index">RazorPagesMovie</a>
    
  3. Remplacez l’élément précédent par la balise suivante :

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

    L’élément anchor précédent est un Tag Helper. Dans le cas présent, il s’agit du Tag Helper d’ancre. L’attribut et la valeur du Tag Helper asp-page="/Movies/Index" créent un lien vers la page Razor/Movies/Index. La valeur de l’attribut asp-area est vide : la zone n’est donc pas utilisée dans le lien. Pour plus d’informations, consultez Zones.

  4. Enregistrez les modifications et testez l’application en sélectionnant le lien RpMovie. Consultez le fichier _Layout.cshtml dans GitHub si vous rencontrez des problèmes.

  5. Testez les liens Home, RpMovie, Create, Edit et Delete. Chaque page définit le titre, que vous pouvez voir dans l’onglet du navigateur. Quand vous définissez un signet pour une page, le titre est affecté au signet.

Notes

Vous ne pourrez peut-être pas entrer de virgules décimales dans le champ Price. Pour prendre en charge la validation jQuery pour les paramètres régionaux autres que l’anglais qui utilisent une virgule (« , ») comme point décimal, et des formats de date autres que l’anglais des États-Unis, vous devez prendre des mesures pour mondialiser l’application. Consultez cette page GitHub problème 4076 pour savoir comment ajouter une virgule décimale.

La propriété Layout est définie dans le fichier Pages/_ViewStart.cshtml :

@{
    Layout = "_Layout";
}

Le balisage précédent définit le fichier de disposition Pages/Shared/_Layout.cshtml pour tous les fichiers Razor du dossier Pages. Pour plus d’informations, consultez Disposition.

Le modèle de page Create

Examinez le modèle de page 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");
        }
    }
}

La méthode OnGet initialise l’état nécessaire pour la page. La page Create n’ayant aucun état à initialiser, Page est retourné. Plus loin dans le tutoriel, un exemple d’état d’initialisation OnGet est affiché. La méthode Page crée un objet PageResult qui affiche la page Create.cshtml.

La propriété Movie utilise l’attribut [BindProperty] pour adhérer à la liaison de modèles. Quand le formulaire Create publie les valeurs de formulaire, le runtime ASP.NET Core lie les valeurs publiées au modèle Movie.

La méthode OnPostAsync est exécutée quand la page publie les données de formulaire :

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

S’il existe des erreurs liées au modèle, le formulaire est réaffiché, ainsi que toutes les données de formulaire publiées. La plupart des erreurs de modèle peuvent être interceptées côté client avant la publication du formulaire. Voici un exemple d’erreur de modèle : la publication pour le champ de date d’une valeur qui ne peut pas être convertie en date. La validation côté client et la validation du modèle sont présentées plus loin dans le tutoriel.

S’il n’y a pas d’erreurs de modèle :

  • Les données sont enregistrées.
  • Le navigateur est redirigé vers la page Index.

Page Razor Create

Examinez le fichier de page RazorPages/Movies/Create.cshtml :

@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 affiche la balise suivante dans une police différenciée en gras utilisée pour les Tag Helpers :

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

Vue VS17 de la page Create.cshtml

L’élément <form method="post"> est un Tag Helper de formulaire. Le Tag Helper de formulaire inclut automatiquement un jeton de protection contre les falsifications.

Le moteur de génération de modèles automatique crée le balisage Razor pour chaque champ du modèle, sauf l’ID, de la manière suivante :

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

Les Tag Helpers de validation (<div asp-validation-summary et <span asp-validation-for) affichent des erreurs de validation. La validation est traitée de manière plus détaillée plus loin dans cette série.

Le Tag Helper d’étiquette (<label asp-for="Movie.Title" class="control-label"></label>) génère la légende de l’étiquette et l’attribut [for] pour la propriété Title.

Le Tag Helper d’entrée (<input asp-for="Movie.Title" class="form-control">) utilise les attributs DataAnnotations et produit les attributs HTML nécessaires à la validation jQuery côté client.

Pour plus d’informations sur les Tag Helpers, comme <form method="post">, consultez Tag Helpers dans ASP.NET Core.

Étapes suivantes

Pages Create, Delete, Details et Edit

Examinez le modèle de page Pages/Movies/Index.cshtml.cs :

// Unused usings removed.
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.EntityFrameworkCore;
using RazorPagesMovie.Models;
using System.Collections.Generic;
using System.Threading.Tasks;

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

        public IndexModel(RazorPagesMovie.Data.RazorPagesMovieContext context)
        {
            _context = context;
        }
        public IList<Movie> Movie { get;set; }

        public async Task OnGetAsync()
        {
            Movie = await _context.Movie.ToListAsync();
        }
    }
}

Les pages Razor sont dérivées de PageModel. Par convention, la classe dérivée de PageModel s’appelle <PageName>Model. Le constructeur utilise l’injection de dépendances pour ajouter RazorPagesMovieContext à la page :

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

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

Consultez Code asynchrone pour plus d’informations sur la programmation asynchrone avec Entity Framework.

Quand une demande est effectuée pour la page, la méthode OnGetAsync retourne une liste de films à la page Razor. Dans une page Razor, OnGetAsync ou OnGet est appelée pour initialiser l’état de la page. Dans ce cas, OnGetAsync obtient une liste de films et les affiche.

Si OnGet retourne void ou que OnGetAsync retourne Task, aucune instruction return n’est utilisée. Par exemple, la page Privacy :

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

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

    public void OnGet()
    {
    }
}

Lorsque le type de retour est IActionResult ou Task<IActionResult>, une instruction de retour doit être spécifiée. Par exemple, la méthode Pages/Movies/Create.cshtml.csOnPostAsync :

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

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

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

Examinez la page RazorPages/Movies/Index.cshtml :

@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 peut passer du code HTML à du code C# ou au balisage spécifique à Razor. Quand un symbole @ est suivi d’un mot clé réservé Razor, il est converti en balisage spécifique à Razor. Sinon, il est converti en C#.

Directive @page

La directive Razor@page transforme le fichier en action MVC, ce qui lui permet de traiter des demandes. @page doit être la première directive Razor sur une page. @page et @model sont des exemples de transition vers un balisage spécifique à Razor. Consultez Syntaxe Razor pour plus d’informations.

Directive @model

@page
@model RazorPagesMovie.Pages.Movies.IndexModel

La directive @model spécifie le type du modèle passé à la page Razor. Dans l’exemple précédent, la ligne @model rend la classe dérivée de PageModel accessible à la page Razor. Le modèle est utilisé dans les HTML Helpers@Html.DisplayNameFor et @Html.DisplayFor de la page.

Examinez l’expression lambda utilisée dans le HTML Helper suivant :

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

Le HTML Helper DisplayNameFor inspecte la propriété Title référencée dans l’expression lambda pour déterminer le nom d’affichage. L’expression lambda est inspectée plutôt qu’évaluée. Cela signifie qu’il n’existe pas de violation d’accès quand model, model.Movie ou model.Movie[0] a la valeur null ou est vide. Quand l’expression lambda est évaluée, par exemple avec @Html.DisplayFor(modelItem => item.Title), les valeurs de propriété du modèle sont évaluées.

La page de disposition

Sélectionnez les liens de menu RazorPagesMovie, Home et Privacy. Chaque page affiche la même disposition de menu. La disposition du menu est implémentée dans le fichier Pages/Shared/_Layout.cshtml.

Ouvrez et examinez le fichier Pages/Shared/_Layout.cshtml.

Les modèles de Disposition permettent que la disposition du conteneur HTML soit :

  • spécifiée à un seul endroit ;
  • appliquée à plusieurs pages du site.

Recherchez la ligne @RenderBody(). RenderBody est un espace réservé dans lequel toutes les vues propres à la page s’affichent, encapsulées dans la page de disposition. Par exemple, sélectionnez le lien Privacy et la vue Pages/Privacy.cshtml est affichée à l’intérieur de la méthode RenderBody.

ViewData et disposition

Examinez le balisage suivant à partir du fichier Pages/Movies/Index.cshtml :

@page
@model RazorPagesMovie.Pages.Movies.IndexModel

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

Le balisage précédent en surbrillance est un exemple de conversion de Razor vers C#. Les caractères { et } délimitent un bloc de code C#.

La classe de base PageModel contient une propriété de dictionnaire ViewData qui peut être utilisée pour transmettre des données à une vue. Des objets sont ajoutés au dictionnaire ViewData à l’aide d’un modèle clé valeur. Dans l’exemple précédent, la propriété Title est ajoutée au dictionnaire ViewData.

La propriété Title est utilisée dans le fichier Pages/Shared/_Layout.cshtml. Le balisage suivant montre les premières lignes du fichier _Layout.cshtml.

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

La ligne @*Markup removed for brevity.*@ est un commentaire Razor. Contrairement aux commentaires HTML <!-- -->, les commentaires Razor ne sont pas envoyés au client. Consultez Documents web MDN : Prise en main du code HTML pour plus d’informations.

Mettre à jour la disposition

  1. Changez l’élément <title> dans le fichier Pages/Shared/_Layout.cshtml pour afficher Movie au lieu de RazorPagesMovie.

    <!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. Recherchez l’élément anchor suivant dans le fichier Pages/Shared/_Layout.cshtml.

    <a class="navbar-brand" asp-area="" asp-page="/Index">RazorPagesMovie</a>
    
  3. Remplacez l’élément précédent par la balise suivante :

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

    L’élément anchor précédent est un Tag Helper. Dans le cas présent, il s’agit du Tag Helper d’ancre. L’attribut et la valeur du Tag Helper asp-page="/Movies/Index" créent un lien vers la page Razor/Movies/Index. La valeur de l’attribut asp-area est vide : la zone n’est donc pas utilisée dans le lien. Pour plus d’informations, consultez Zones.

  4. Enregistrez les modifications et testez l’application en sélectionnant le lien RpMovie. Consultez le fichier _Layout.cshtml dans GitHub si vous rencontrez des problèmes.

  5. Testez les liens Home, RpMovie, Create, Edit et Delete. Chaque page définit le titre, que vous pouvez voir dans l’onglet du navigateur. Quand vous définissez un signet pour une page, le titre est affecté au signet.

Notes

Vous ne pourrez peut-être pas entrer de virgules décimales dans le champ Price. Pour prendre en charge la validation jQuery pour les paramètres régionaux autres que l’anglais qui utilisent une virgule (« , ») comme point décimal, et des formats de date autres que l’anglais des États-Unis, vous devez prendre des mesures pour mondialiser l’application. Consultez cette page GitHub problème 4076 pour savoir comment ajouter une virgule décimale.

La propriété Layout est définie dans le fichier Pages/_ViewStart.cshtml :

@{
    Layout = "_Layout";
}

Le balisage précédent définit le fichier de disposition Pages/Shared/_Layout.cshtml pour tous les fichiers Razor du dossier Pages. Pour plus d’informations, consultez Disposition.

Le modèle de page Create

Examinez le modèle de page 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");
        }
    }
}

La méthode OnGet initialise l’état nécessaire pour la page. La page Create n’ayant aucun état à initialiser, Page est retourné. Plus loin dans le tutoriel, un exemple d’état d’initialisation OnGet est affiché. La méthode Page crée un objet PageResult qui affiche la page Create.cshtml.

La propriété Movie utilise l’attribut [BindProperty] pour adhérer à la liaison de modèles. Quand le formulaire Create publie les valeurs de formulaire, le runtime ASP.NET Core lie les valeurs publiées au modèle Movie.

La méthode OnPostAsync est exécutée quand la page publie les données de formulaire :

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

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

    return RedirectToPage("./Index");
}

S’il existe des erreurs liées au modèle, le formulaire est réaffiché, ainsi que toutes les données de formulaire publiées. La plupart des erreurs de modèle peuvent être interceptées côté client avant la publication du formulaire. Voici un exemple d’erreur de modèle : la publication pour le champ de date d’une valeur qui ne peut pas être convertie en date. La validation côté client et la validation du modèle sont présentées plus loin dans le tutoriel.

S’il n’y a pas d’erreurs de modèle :

  • Les données sont enregistrées.
  • Le navigateur est redirigé vers la page Index.

Page Razor Create

Examinez le fichier de page RazorPages/Movies/Create.cshtml :

@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 affiche la balise suivante dans une police différenciée en gras utilisée pour les Tag Helpers :

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

Vue VS17 de la page Create.cshtml

L’élément <form method="post"> est un Tag Helper de formulaire. Le Tag Helper de formulaire inclut automatiquement un jeton de protection contre les falsifications.

Le moteur de génération de modèles automatique crée le balisage Razor pour chaque champ du modèle, sauf l’ID, de la manière suivante :

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

Les Tag Helpers de validation (<div asp-validation-summary et <span asp-validation-for) affichent des erreurs de validation. La validation est traitée de manière plus détaillée plus loin dans cette série.

Le Tag Helper d’étiquette (<label asp-for="Movie.Title" class="control-label"></label>) génère la légende de l’étiquette et l’attribut [for] pour la propriété Title.

Le Tag Helper d’entrée (<input asp-for="Movie.Title" class="form-control">) utilise les attributs DataAnnotations et produit les attributs HTML nécessaires à la validation jQuery côté client.

Pour plus d’informations sur les Tag Helpers, comme <form method="post">, consultez Tag Helpers dans ASP.NET Core.

Étapes suivantes