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 9 de cet article.
Avertissement
Cette version d’ASP.NET Core n’est plus prise en charge. Pour plus d’informations, consultez la stratégie de support .NET et .NET Core. Pour la version actuelle, consultez la version .NET 9 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 9 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 System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.EntityFrameworkCore;
using RazorPagesMovie.Data;
using RazorPagesMovie.Models;
using Microsoft.AspNetCore.Mvc.Rendering;
namespace RazorPagesMovie.Pages.Movies
{
public class IndexModel : PageModel
{
private readonly RazorPagesMovie.Data.RazorPagesMovieContext _context;
public IndexModel(RazorPagesMovie.Data.RazorPagesMovieContext context)
{
_context = context;
}
public IList<Movie> Movie { get;set; } = default!;
public async Task OnGetAsync()
{
Movie = await _context.Movie.ToListAsync();
}
}
}
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.DisplayNameFor
et les @Html.DisplayFor
helpers HTML sur 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 du 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.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
Changez l’élément
<title>
dans le fichierPages/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>
Recherchez l’élément anchor suivant dans le fichier
Pages/Shared/_Layout.cshtml
.<a class="navbar-brand" asp-area="" asp-page="/Index">RazorPagesMovie</a>
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’attributasp-area
est vide : la zone n’est donc pas utilisée dans le lien. Pour plus d’informations, consultez Zones.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.
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 System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.AspNetCore.Mvc.Rendering;
using RazorPagesMovie.Data;
using RazorPagesMovie.Models;
namespace RazorPagesMovie.Pages.Movies
{
public class CreateModel : PageModel
{
private readonly RazorPagesMovie.Data.RazorPagesMovieContext _context;
public CreateModel(RazorPagesMovie.Data.RazorPagesMovieContext context)
{
_context = context;
}
public IActionResult OnGet()
{
return Page();
}
[BindProperty]
public Movie Movie { get; set; } = default!;
// To protect from overposting attacks, see https://aka.ms/RazorPagesCRUD
public async Task<IActionResult> OnPostAsync()
{
if (!ModelState.IsValid)
{
return Page();
}
_context.Movie.Add(Movie);
await _context.SaveChangesAsync();
return RedirectToPage("./Index");
}
}
}
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>
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.DisplayNameFor
et les @Html.DisplayFor
helpers HTML sur 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 du 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
Changez l’élément
<title>
dans le fichierPages/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>
Recherchez l’élément anchor suivant dans le fichier
Pages/Shared/_Layout.cshtml
.<a class="navbar-brand" asp-area="" asp-page="/Index">RazorPagesMovie</a>
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’attributasp-area
est vide : la zone n’est donc pas utilisée dans le lien. Pour plus d’informations, consultez Zones.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.
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>
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.DisplayNameFor
et les @Html.DisplayFor
helpers HTML sur 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 du 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
Changez l’élément
<title>
dans le fichierPages/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>
Recherchez l’élément anchor suivant dans le fichier
Pages/Shared/_Layout.cshtml
.<a class="navbar-brand" asp-area="" asp-page="/Index">RazorPagesMovie</a>
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’attributasp-area
est vide : la zone n’est donc pas utilisée dans le lien. Pour plus d’informations, consultez Zones.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.
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>
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.cs
OnPostAsync
:
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.DisplayNameFor
et les @Html.DisplayFor
helpers HTML sur 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 du 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
Changez l’élément
<title>
dans le fichierPages/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>
Recherchez l’élément anchor suivant dans le fichier
Pages/Shared/_Layout.cshtml
.<a class="navbar-brand" asp-area="" asp-page="/Index">RazorPagesMovie</a>
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’attributasp-area
est vide : la zone n’est donc pas utilisée dans le lien. Pour plus d’informations, consultez Zones.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.
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>
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.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.DisplayNameFor
et les @Html.DisplayFor
helpers HTML sur 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 du 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
Changez l’élément
<title>
dans le fichierPages/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>
Recherchez l’élément anchor suivant dans le fichier
Pages/Shared/_Layout.cshtml
.<a class="navbar-brand" asp-area="" asp-page="/Index">RazorPagesMovie</a>
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’attributasp-area
est vide : la zone n’est donc pas utilisée dans le lien. Pour plus d’informations, consultez Zones.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.
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>
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.