Présentation Razor des pages dans ASP.net Core

De Rick Anderson et Ryan Nowak

Razor Les pages peuvent rendre le codage des scénarios orientés page plus facile et plus productif que l’utilisation de contrôleurs et de vues.

Si vous cherchez un didacticiel qui utilise l’approche Model-View-Controller, consultez Bien démarrer avec ASP.NET Core MVC.

Ce document fournit une introduction aux Razor pages. Il ne s’agit pas d’un didacticiel pas à pas. Si vous trouvez certaines des sections trop avancées, consultez prise en main des Razor pages. Pour une vue d’ensemble d’ASP.NET Core, consultez Introduction à ASP.NET Core.

Prérequis

Créer un Razor projet pages

Pour obtenir des instructions détaillées sur la création d’un projet de pages, consultez prise en main des Razor pages Razor .

Razor Pages

Razor Les pages sont activées dans Startup. cs:

public class Startup
{
    public Startup(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public IConfiguration Configuration { get; }

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddRazorPages();
    }

    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }
        else
        {
            app.UseExceptionHandler("/Error");
            app.UseHsts();
        }

        app.UseHttpsRedirection();
        app.UseStaticFiles();

        app.UseRouting();

        app.UseAuthorization();

        app.UseEndpoints(endpoints =>
        {
            endpoints.MapRazorPages();
        });
    }
}

Considérez une page de base :

@page

<h1>Hello, world!</h1>
<h2>The time on the server is @DateTime.Now</h2>

Le code précédent ressemble beaucoup à un Razor fichier de vue utilisé dans une application ASP.net core avec des contrôleurs et des vues. Ce qui le rend différent est la @page directive. @page fait du fichier une action MVC, ce qui signifie qu’il gère les demandes directement, sans passer par un contrôleur. @page doit être la première Razor directive sur une page. @page affecte le comportement d’autres Razor constructions. Razor Les noms de fichiers de pages ont un suffixe . cshtml .

Une page similaire, utilisant une classe PageModel, est illustrée dans les deux fichiers suivants. Le fichier Pages/Index2.cshtml :

@page
@using RazorPagesIntro.Pages
@model Index2Model

<h2>Separate page model</h2>
<p>
    @Model.Message
</p>

Le modèle de page Pages/Index2.cshtml.cs :

using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.Extensions.Logging;
using System;

namespace RazorPagesIntro.Pages
{
    public class Index2Model : PageModel
    {
        public string Message { get; private set; } = "PageModel in C#";

        public void OnGet()
        {
            Message += $" Server time is { DateTime.Now }";
        }
    }
}

Par Convention, le PageModel fichier de classe a le même nom que le Razor fichier d’échange avec . cs ajouté. Par exemple, la Razor page précédente est pages/index2. cshtml. Le fichier contenant la classe PageModel se nomme Pages/Index2.cshtml.cs.

Les associations des chemins d’URL aux pages sont déterminées par l’emplacement de la page dans le système de fichiers. Le tableau suivant indique un Razor chemin d’accès à la page et l’URL correspondante :

Nom et chemin de fichier URL correspondante
/Pages/Index.cshtml / ou /Index
/Pages/Contact.cshtml /Contact
/Pages/Store/Contact.cshtml /Store/Contact
/Pages/Store/Index.cshtml /Store ou /Store/Index

Remarques :

  • Le runtime recherche les Razor fichiers de pages dans le dossier pages par défaut.
  • Index est la page par défaut quand une URL n’inclut pas de page.

Écrire un formulaire de base

Razor Les pages sont conçues pour rendre les modèles courants utilisés avec les navigateurs Web faciles à implémenter lors de la création d’une application. La liaison de modèle, les tag helperset les applications auxiliaires HTML fonctionnent tout simplement avec les propriétés définies dans une classe de Razor page. Considérez une page qui implémente un formulaire « Nous contacter » de base pour le modèle Contact :

Pour les exemples de ce document, le DbContext est initialisé dans le fichier Startup.cs.

La base de données en mémoire requiert le Microsoft.EntityFrameworkCore.InMemory package NuGet.

public void ConfigureServices(IServiceCollection services)
{
    services.AddDbContext<CustomerDbContext>(options =>
                      options.UseInMemoryDatabase("name"));
    services.AddRazorPages();
}

Le modèle de données :

using System.ComponentModel.DataAnnotations;

namespace RazorPagesContacts.Models
{
    public class Customer
    {
        public int Id { get; set; }

        [Required, StringLength(10)]
        public string Name { get; set; }
    }
}

Le contexte de la base de données :

using Microsoft.EntityFrameworkCore;
using RazorPagesContacts.Models;

namespace RazorPagesContacts.Data
{
    public class CustomerDbContext : DbContext
    {
        public CustomerDbContext(DbContextOptions options)
            : base(options)
        {
        }

        public DbSet<Customer> Customers { get; set; }
    }
}

Le fichier vue Pages/Create.cshtml :

@page
@model RazorPagesContacts.Pages.Customers.CreateModel
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers

<p>Enter a customer name:</p>

<form method="post">
    Name:
    <input asp-for="Customer.Name" />
    <input type="submit" />
</form>

Le modèle de page Pages/Create.cshtml.cs :

using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using RazorPagesContacts.Data;
using RazorPagesContacts.Models;
using System.Threading.Tasks;

namespace RazorPagesContacts.Pages.Customers
{
    public class CreateModel : PageModel
    {
        private readonly CustomerDbContext _context;

        public CreateModel(CustomerDbContext context)
        {
            _context = context;
        }

        public IActionResult OnGet()
        {
            return Page();
        }

        [BindProperty]
        public Customer Customer { get; set; }

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

            _context.Customers.Add(Customer);
            await _context.SaveChangesAsync();

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

Par convention, la classe PageModel se nomme <PageName>Model et se trouve dans le même espace de noms que la page.

La classe PageModel permet de séparer la logique d’une page de sa présentation. Elle définit des gestionnaires de page pour les demandes envoyées à la page et les données utilisées pour l’afficher. Cette séparation permet :

La page a une méthode de gestionnaireOnPostAsync, qui s’exécute sur les requêtes POST (quand un utilisateur poste le formulaire). Les méthodes de gestionnaire pour tout verbe HTTP peuvent être ajoutées. Les gestionnaires les plus courants sont :

  • OnGet pour initialiser l’état nécessaire pour la page. Dans le code précédent, la OnGet méthode affiche la page CreateModel. cshtml Razor .
  • OnPost pour gérer les envois de formulaire.

Le suffixe de nommage Async est facultatif, mais souvent utilisé par convention pour les fonctions asynchrones. Le code précédent est normal pour les Razor pages.

Si vous êtes familiarisé avec les applications ASP.NET à l’aide de contrôleurs et de vues :

  • Le OnPostAsync Code de l’exemple précédent ressemble au code de contrôleur classique.
  • La plupart des primitives MVC, telles que la liaison de modèle, la validationet les résultats d’action, fonctionnent de la même manière avec les contrôleurs et les Razor pages.

La méthode OnPostAsync précédente :

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

    _context.Customers.Add(Customer);
    await _context.SaveChangesAsync();

    return RedirectToPage("./Index");
}

Le flux de base de OnPostAsync :

Vérifiez s’il y a des erreurs de validation.

  • S’il n’y a aucune erreur, enregistrez les données et redirigez.
  • S’il y a des erreurs, réaffichez la page avec des messages de validation. Dans de nombreux cas, les erreurs de validation seraient détectées sur le client et jamais envoyées au serveur.

Le fichier vue Pages/Create.cshtml :

@page
@model RazorPagesContacts.Pages.Customers.CreateModel
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers

<p>Enter a customer name:</p>

<form method="post">
    Name:
    <input asp-for="Customer.Name" />
    <input type="submit" />
</form>

Le rendu HTML à partir de pages/Create. cshtml:

<p>Enter a customer name:</p>

<form method="post">
    Name:
    <input type="text" data-val="true"
           data-val-length="The field Name must be a string with a maximum length of 10."
           data-val-length-max="10" data-val-required="The Name field is required."
           id="Customer_Name" maxlength="10" name="Customer.Name" value="" />
    <input type="submit" />
    <input name="__RequestVerificationToken" type="hidden"
           value="<Antiforgery token here>" />
</form>

Dans le code précédent, la publication du formulaire :

  • Avec des données valides :

    • La OnPostAsync méthode de gestionnaire appelle la RedirectToPage méthode d’assistance. RedirectToPage retourne une instance de RedirectToPageResult. RedirectToPage:

      • Est un résultat d’action.
      • Est semblable à RedirectToAction ou RedirectToRoute (utilisé dans les contrôleurs et les vues).
      • Est personnalisé pour les pages. Dans l’exemple précédent, il redirige vers la page Index racine (/Index). RedirectToPage est détaillé dans la section génération d’URL pour les pages .
  • Avec les erreurs de validation qui sont transmises au serveur :

    • La OnPostAsync méthode de gestionnaire appelle la Page méthode d’assistance. Page retourne une instance de PageResult. Le retour de Page est similaire à la façon dont les actions dans les contrôleurs retournent View. PageResult est le type de retour par défaut pour une méthode de gestionnaire. Une méthode de gestionnaire qui retourne void restitue la page.
    • Dans l’exemple précédent, la publication du formulaire sans valeur entraîne le renvoi de la valeur false à ModelState. IsValid . Dans cet exemple, aucune erreur de validation n’est affichée sur le client. La gestion des erreurs de validation est traitée plus loin dans ce document.
    public async Task<IActionResult> OnPostAsync()
    {
        if (!ModelState.IsValid)
        {
            return Page();
        }
    
        _context.Customers.Add(Customer);
        await _context.SaveChangesAsync();
    
        return RedirectToPage("./Index");
    }
    
  • Avec les erreurs de validation détectées par la validation côté client :

    • Les données ne sont pas publiées sur le serveur.
    • La validation côté client est expliquée plus loin dans ce document.

La Customer propriété utilise l' [BindProperty] attribut pour s’abonner à la liaison de modèle :

public class CreateModel : PageModel
{
    private readonly CustomerDbContext _context;

    public CreateModel(CustomerDbContext context)
    {
        _context = context;
    }

    public IActionResult OnGet()
    {
        return Page();
    }

    [BindProperty]
    public Customer Customer { get; set; }

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

        _context.Customers.Add(Customer);
        await _context.SaveChangesAsync();

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

[BindProperty] ne doit pas être utilisé sur les modèles contenant des propriétés qui ne doivent pas être modifiées par le client. Pour plus d’informations, consultez survalidation.

Razor Les pages, par défaut, lient les propriétés uniquement avec des non- GET verbes. La liaison aux propriétés évite d’avoir à écrire du code pour convertir des données HTTP en type de modèle. Elle réduit la quantité de code en utilisant la même propriété pour afficher les champs de formulaire (<input asp-for="Customer.Name">) et accepter l’entrée.

Avertissement

Pour des raisons de sécurité, vous devez choisir de lier les données de requête GET aux propriétés du modèle de page. Vérifiez l’entrée utilisateur avant de la mapper à des propriétés. L’utilisation GET de la liaison est utile lors de l’adressage de scénarios qui reposent sur une chaîne de requête ou des valeurs de route.

Pour lier une propriété à des GET demandes, affectez [BindProperty] à la propriété de l’attribut la valeur SupportsGet true :

[BindProperty(SupportsGet = true)]

Pour plus d’informations, consultez ASP.net Core de la communauté réunions : lier sur obtenir une discussion (YouTube).

Examen du fichier de vue pages/Create. cshtml :

@page
@model RazorPagesContacts.Pages.Customers.CreateModel
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers

<p>Enter a customer name:</p>

<form method="post">
    Name:
    <input asp-for="Customer.Name" />
    <input type="submit" />
</form>
  • Dans le code précédent, le tag Helper d’entrée <input asp-for="Customer.Name" /> lie l’élément HTML <input> à l' Customer.Name expression de modèle.
  • @addTagHelper rend les tag helpers disponibles.

La page d’accueil

Index. cshtml est la page d’hébergement :

@page
@model RazorPagesContacts.Pages.Customers.IndexModel
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers

<h1>Contacts home page</h1>
<form method="post">
    <table class="table">
        <thead>
            <tr>
                <th>ID</th>
                <th>Name</th>
                <th></th>
            </tr>
        </thead>
        <tbody>
            @foreach (var contact in Model.Customer)
            {
                <tr>
                    <td> @contact.Id  </td>
                    <td>@contact.Name</td>
                    <td>
                        <a asp-page="./Edit" asp-route-id="@contact.Id">Edit</a> |
                        <button type="submit" asp-page-handler="delete"
                                asp-route-id="@contact.Id">delete
                        </button>
                    </td>
                </tr>
            }
        </tbody>
    </table>
    <a asp-page="Create">Create New</a>
</form>

La classe PageModel associée (Index.cshtml.cs) :

public class IndexModel : PageModel
{
    private readonly CustomerDbContext _context;

    public IndexModel(CustomerDbContext context)
    {
        _context = context;
    }

    public IList<Customer> Customer { get; set; }

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

    public async Task<IActionResult> OnPostDeleteAsync(int id)
    {
        var contact = await _context.Customers.FindAsync(id);

        if (contact != null)
        {
            _context.Customers.Remove(contact);
            await _context.SaveChangesAsync();
        }

        return RedirectToPage();
    }
}

Le fichier index. cshtml contient le balisage suivant :

<td>

Le <a /a> tag Helper ancre a utilisé l' asp-route-{value} attribut pour générer un lien vers la page de modification. Le lien contient des données d’itinéraire avec l’ID de contact. Par exemple : https://localhost:5001/Edit/1. Les tag helpers permettent au code côté serveur de participer à la création et au rendu des éléments HTML dans les Razor fichiers.

Le fichier index. cshtml contient un balisage pour créer un bouton Supprimer pour chaque contact client :

<a asp-page="./Edit" asp-route-id="@contact.Id">Edit</a> |
<button type="submit" asp-page-handler="delete"

HTML rendu :

<button type="submit" formaction="/Customers?id=1&amp;handler=delete">delete</button>

Lorsque le bouton supprimer est rendu en HTML, son formaction comprend des paramètres pour :

  • ID du contact client, spécifié par l' asp-route-id attribut.
  • handler, Spécifié par l' asp-page-handler attribut.

Quand le bouton est sélectionné, une demande POST de forumaire est envoyée au serveur. Par convention, le nom de la méthode de gestionnaire est sélectionné en fonction de la valeur du paramètre handler conformément au schéma OnPost[handler]Async.

Étant donné que le handler est delete dans cet exemple, la méthode de gestionnaire OnPostDeleteAsync est utilisée pour traiter la demande POST. Si asp-page-handler est défini sur une autre valeur, comme remove, une méthode de gestionnaire avec le nom OnPostRemoveAsync est sélectionnée.

public async Task<IActionResult> OnPostDeleteAsync(int id)
{
    var contact = await _context.Customers.FindAsync(id);

    if (contact != null)
    {
        _context.Customers.Remove(contact);
        await _context.SaveChangesAsync();
    }

    return RedirectToPage();
}

La méthode OnPostDeleteAsync :

  • Obtient le id de la chaîne de requête.
  • Interroge la base de données pour le contact client avec FindAsync.
  • Si le contact client est trouvé, il est supprimé et la base de données est mise à jour.
  • Appelle RedirectToPage pour rediriger vers la page Index racine (/Index).

Le fichier Edit. cshtml

@page "{id:int}"
@model RazorPagesContacts.Pages.Customers.EditModel
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers


<h1>Edit Customer - @Model.Customer.Id</h1>
<form method="post">
    <div asp-validation-summary="All"></div>
    <input asp-for="Customer.Id" type="hidden" />
    <div>
        <label asp-for="Customer.Name"></label>
        <div>
            <input asp-for="Customer.Name" />
            <span asp-validation-for="Customer.Name"></span>
        </div>
    </div>

    <div>
        <button type="submit">Save</button>
    </div>
</form>

La première ligne contient la directive @page "{id:int}". La contrainte de routage "{id:int}" indique à la page qu’elle doit accepter les requêtes qui contiennent des données d’itinéraire int. Si une requête à la page ne contient de données d’itinéraire qui peuvent être converties en int, le runtime retourne une erreur HTTP 404 (introuvable). Pour que l’ID soit facultatif, ajoutez ? à la contrainte d’itinéraire :

@page "{id:int?}"

Le fichier Edit. cshtml. cs :

public class EditModel : PageModel
{
    private readonly CustomerDbContext _context;

    public EditModel(CustomerDbContext context)
    {
        _context = context;
    }

    [BindProperty]
    public Customer Customer { get; set; }

    public async Task<IActionResult> OnGetAsync(int id)
    {
        Customer = await _context.Customers.FindAsync(id);

        if (Customer == null)
        {
            return RedirectToPage("./Index");
        }

        return Page();
    }

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

        _context.Attach(Customer).State = EntityState.Modified;

        try
        {
            await _context.SaveChangesAsync();
        }
        catch (DbUpdateConcurrencyException)
        {
            throw new Exception($"Customer {Customer.Id} not found!");
        }

        return RedirectToPage("./Index");
    }

}

Validation

Règles de validation :

  • Sont spécifiés de façon déclarative dans la classe de modèle.
  • Sont appliquées partout dans l’application.

L' System.ComponentModel.DataAnnotations espace de noms fournit un jeu d’attributs de validation intégrés qui sont appliqués de façon déclarative à une classe ou une propriété. DataAnnotations contient également des attributs de mise en forme tels [DataType] que l’aide à la mise en forme et ne fournissent aucune validation.

Prenons le Customer modèle :

using System.ComponentModel.DataAnnotations;

namespace RazorPagesContacts.Models
{
    public class Customer
    {
        public int Id { get; set; }

        [Required, StringLength(10)]
        public string Name { get; set; }
    }
}

À l’aide du fichier de vue Create. cshtml suivant :

@page
@model RazorPagesContacts.Pages.Customers.CreateModel
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers

<p>Validation: customer name:</p>

<form method="post">
    <div asp-validation-summary="ModelOnly"></div>
    <span asp-validation-for="Customer.Name"></span>
    Name:
    <input asp-for="Customer.Name" />
    <input type="submit" />
</form>

<script src="~/lib/jquery/dist/jquery.js"></script>
<script src="~/lib/jquery-validation/dist/jquery.validate.js"></script>
<script src="~/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.js"></script>

Le code précédent :

  • Comprend des scripts de validation jQuery et jQuery.

  • Utilise le <div /> et les <span /> aide pour les balises pour activer :

    • Validation côté client.
    • Rendu des erreurs de validation.
  • Génère le code HTML suivant :

    <p>Enter a customer name:</p>
    
    <form method="post">
        Name:
        <input type="text" data-val="true"
               data-val-length="The field Name must be a string with a maximum length of 10."
               data-val-length-max="10" data-val-required="The Name field is required."
               id="Customer_Name" maxlength="10" name="Customer.Name" value="" />
        <input type="submit" />
        <input name="__RequestVerificationToken" type="hidden"
               value="<Antiforgery token here>" />
    </form>
    
    <script src="/lib/jquery/dist/jquery.js"></script>
    <script src="/lib/jquery-validation/dist/jquery.validate.js"></script>
    <script src="/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.js"></script>
    

La publication de la valeur créer un formulaire sans nom affiche le message d’erreur « le champ nom est obligatoire. » sur le formulaire. Si JavaScript est activé sur le client, le navigateur affiche l’erreur sans la publier sur le serveur.

L' [StringLength(10)] attribut génère data-val-length-max="10" sur le rendu HTML. data-val-length-max empêche les navigateurs d’entrer une valeur supérieure à la longueur maximale spécifiée. Si un outil tel que Fiddler est utilisé pour modifier et relire la publication :

  • Avec le nom plus long que 10.
  • Le message d’erreur « le nom du champ doit être une chaîne d’une longueur maximale de 10 ». » est renvoyé.

Prenons le Movie modèle suivant :

using System;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;

namespace RazorPagesMovie.Models
{
    public class Movie
    {
        public int ID { get; set; }

        [StringLength(60, MinimumLength = 3)]
        [Required]
        public string Title { get; set; }

        [Display(Name = "Release Date")]
        [DataType(DataType.Date)]
        public DateTime ReleaseDate { get; set; }

        [Range(1, 100)]
        [DataType(DataType.Currency)]
        [Column(TypeName = "decimal(18, 2)")]
        public decimal Price { get; set; }

        [RegularExpression(@"^[A-Z]+[a-zA-Z\s]*$")]
        [Required]
        [StringLength(30)]
        public string Genre { get; set; }

        [RegularExpression(@"^[A-Z]+[a-zA-Z0-9""'\s-]*$")]
        [StringLength(5)]
        [Required]
        public string Rating { get; set; }
    }

Les attributs de validation spécifient le comportement à appliquer sur les propriétés de modèle auxquelles ils sont appliqués :

  • Les Required MinimumLength attributs et indiquent qu’une propriété doit avoir une valeur, mais rien n’empêche un utilisateur d’entrer un espace blanc pour satisfaire cette validation.

  • L’attribut RegularExpression sert à limiter les caractères pouvant être entrés. Dans le code précédent, « Genre » :

    • Doit utiliser seulement des lettres.
    • La première lettre doit être une majuscule. Les espaces, les chiffres et les caractères spéciaux ne sont pas autorisés.
  • L’expression RegularExpression « Rating » :

    • Nécessite que le premier caractère soit une lettre majuscule.
    • Autorise les caractères spéciaux et les nombres dans les espaces suivants. « PG-13 » est valide pour une évaluation, mais échoue pour un « Genre ».
  • L’attribut Range limite une valeur à une plage spécifiée.

  • L' StringLength attribut définit la longueur maximale d’une propriété de type chaîne et, éventuellement, sa longueur minimale.

  • Les types valeur (tels que decimal, int, float et DateTime) sont obligatoires par nature et n’ont pas besoin de l’attribut [Required].

La page créer du modèle affiche des Movie Erreurs avec des valeurs non valides :

Formulaire de vue Movie avec plusieurs erreurs de validation jQuery côté client

Pour plus d'informations, consultez les pages suivantes :

Gérer les requêtes HEAD avec un gestionnaire OnGet de secours

HEAD les requêtes permettent de récupérer les en-têtes pour une ressource spécifique. Contrairement aux requêtes GET, les requêtes HEAD ne retournent pas un corps de réponse.

En règle générale, un gestionnaire OnHead est créé et appelé pour les requêtes HEAD :

public void OnHead()
{
    HttpContext.Response.Headers.Add("Head Test", "Handled by OnHead!");
}

Razor Les pages reviennent à appeler le OnGet Gestionnaire si aucun OnHead gestionnaire n’est défini.

XSRF/CSRF et Razor pages

Razor Les pages sont protégées par la validation anti- contrefaçon. Le FormTagHelper injecte des jetons anti-contrefaçon dans des éléments de formulaire HTML.

Utilisation de dispositions, de partiels, de modèles et d’aide pour les balises avec des Razor pages

Les pages fonctionnent avec toutes les fonctionnalités du Razor moteur d’affichage. Les mises en page, les partiels, les modèles, les tag helpers, _ViewStart. cshtml et _ViewImports. cshtml fonctionnent de la même façon que pour les Razor vues conventionnelles.

Nous allons nettoyer un peu cette page en tirant parti de certaines de ces fonctionnalités.

Ajoutez une page de disposition à Pages/Shared/_Layout.cshtml :

<!DOCTYPE html>
<html>
<head>
    <title>RP Sample</title>
    <link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.css" />
</head>
<body>
    <a asp-page="/Index">Home</a>
    <a asp-page="/Customers/Create">Create</a>
    <a asp-page="/Customers/Index">Customers</a> <br />

    @RenderBody()
    <script src="~/lib/jquery/dist/jquery.js"></script>
    <script src="~/lib/jquery-validation/dist/jquery.validate.js"></script>
    <script src="~/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.js"></script>
</body>
</html>

La disposition:

  • Contrôle la disposition de chaque page (à moins que la page ne refuse la disposition).
  • Importe des structures HTML telles que JavaScript et les feuilles de style.
  • Le contenu de la Razor page est rendu où @RenderBody() est appelé.

Pour plus d’informations, consultez page disposition.

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

@{
    Layout = "_Layout";
}

La disposition est dans le dossier Pages/Shared. Les pages recherchent d’autres vues (dispositions, modèles, partiels) hiérarchiquement, en commençant dans le même dossier que la page active. Une mise en page dans le dossier pages/Shared peut être utilisée à partir de n’importe quelle Razor page sous le dossier pages .

Le fichier de disposition doit être placé dans le dossier Pages/Shared.

Nous vous recommandons de ne pas placer le fichier de disposition dans le dossier Views/Shared. Views/Shared est un modèle de vues MVC. Razor Les pages sont conçues pour s’appuyer sur la hiérarchie des dossiers, et non sur les conventions de chemin.

L’affichage de la recherche à partir d’une Razor page comprend le dossier pages . Les mises en page, les modèles et les partiels utilisés avec les contrôleurs MVC et les Razor vues conventionnelles fonctionnent simplement.

Ajoutez un fichier Pages/_ViewImports.cshtml :

@namespace RazorPagesContacts.Pages
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers

@namespace est expliqué plus loin dans le didacticiel. La directive @addTagHelper permet de bénéficier des Tag Helpers intégrés dans toutes les pages du dossier Pages.

La @namespace directive est définie sur une page :

@page
@namespace RazorPagesIntro.Pages.Customers

@model NameSpaceModel

<h2>Name space</h2>
<p>
    @Model.Message
</p>

La @namespace directive définit l’espace de noms de la page. La directive @model n’a pas besoin d’inclure l’espace de noms.

Quand la directive @namespace est contenue dans _ViewImports.cshtml, l’espace de noms spécifié fournit le préfixe de l’espace de noms généré dans la Page qui importe la directive @namespace. Le reste de l’espace de noms généré (la partie suffixe) est le chemin relatif séparé par un point entre le dossier contenant _ViewImports.cshtml et le dossier contenant la page.

Par exemple, la classe PageModelPages/Customers/Edit.cshtml.cs définit explicitement l’espace de noms :

namespace RazorPagesContacts.Pages
{
    public class EditModel : PageModel
    {
        private readonly AppDbContext _db;

        public EditModel(AppDbContext db)
        {
            _db = db;
        }

        // Code removed for brevity.

Le fichier Pages/_ViewImports.cshtml définit l’espace de noms suivant :

@namespace RazorPagesContacts.Pages
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers

L’espace de noms généré pour la page pages/Customers/Edit. cshtml Razor est le même que la PageModel classe.

@namespacefonctionne également avec les Razor vues conventionnelles.

Examinez le fichier de vue pages/Create. cshtml :

@page
@model RazorPagesContacts.Pages.Customers.CreateModel
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers

<p>Validation: customer name:</p>

<form method="post">
    <div asp-validation-summary="ModelOnly"></div>
    <span asp-validation-for="Customer.Name"></span>
    Name:
    <input asp-for="Customer.Name" />
    <input type="submit" />
</form>

<script src="~/lib/jquery/dist/jquery.js"></script>
<script src="~/lib/jquery-validation/dist/jquery.validate.js"></script>
<script src="~/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.js"></script>

Le fichier de vue pages/Create. cshtml mis à jour avec _ViewImports. cshtml et le fichier de disposition précédent :

@page
@model CreateModel

<p>Enter a customer name:</p>

<form method="post">
    Name:
    <input asp-for="Customer.Name" />
    <input type="submit" />
</form>

Dans le code précédent, le _ViewImports. cshtml a importé l’espace de noms et les tag helpers. Le fichier de disposition a importé les fichiers JavaScript.

Le Razor projet de démarrage pages contient les pages/_ValidationScriptsPartial. cshtml, qui raccorde la validation côté client.

Pour plus d'informations sur les affichages partiels, consultez Vues partielles dans ASP.NET Core.

Génération d’URL pour les pages

La page Create, illustrée précédemment, utilise RedirectToPage :

public class CreateModel : PageModel
{
    private readonly CustomerDbContext _context;

    public CreateModel(CustomerDbContext context)
    {
        _context = context;
    }

    public IActionResult OnGet()
    {
        return Page();
    }

    [BindProperty]
    public Customer Customer { get; set; }

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

        _context.Customers.Add(Customer);
        await _context.SaveChangesAsync();

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

L’application a la structure de fichiers/dossiers suivante :

  • /Pages

    • Index.cshtml

    • Privacy. cshtml

    • /Customers

      • Create.cshtml
      • Edit.cshtml
      • Index.cshtml

Les pages pages/Customers/Create. cshtml et pages/Customers/Edit. cshtml redirigent vers pages/Customers/index. cshtml après réussite. La chaîne ./Index est un nom de page relatif utilisé pour accéder à la page précédente. Elle est utilisée pour générer des URL dans la page pages/Customers/index. cshtml . Par exemple :

  • Url.Page("./Index", ...)
  • <a asp-page="./Index">Customers Index Page</a>
  • RedirectToPage("./Index")

Le nom de page absolu /Index est utilisé pour générer des URL dans la page pages/index. cshtml . Par exemple :

  • Url.Page("/Index", ...)
  • <a asp-page="/Index">Home Index Page</a>
  • RedirectToPage("/Index")

Le nom de la page est le chemin de la page à partir du dossier racine /Pages avec un / devant (par exemple, /Index). Les exemples de génération d’URL précédents offrent des options améliorées et des fonctionnalités fonctionnelles par rapport au codage en dur d’une URL. La génération d’URL utilise le routage et peut générer et encoder des paramètres en fonction de la façon dont l’itinéraire est défini dans le chemin de destination.

La génération d’URL pour les pages prend en charge les noms relatifs. Le tableau suivant indique quelle page d’index est sélectionnée à l’aide RedirectToPage de différents paramètres dans pages/Customers/Create. cshtml.

RedirectToPage(x) Page
RedirectToPage("/Index") Pages/Index
RedirectToPage("./Index"); Pages/Customers/Index
RedirectToPage("../Index") Pages/Index
RedirectToPage("Index") Pages/Customers/Index

RedirectToPage("Index"), RedirectToPage("./Index") et RedirectToPage("../Index") sont des noms relatifs. Le paramètre RedirectToPage est combiné avec le chemin de la page active pour calculer le nom de la page de destination.

La liaison de nom relatif est utile lors de la création de sites avec une structure complexe. Lorsque des noms relatifs sont utilisés pour établir une liaison entre les pages d’un dossier :

  • Le changement de nom d’un dossier n’interrompt pas les liens relatifs.
  • Les liens ne sont pas rompus, car ils n’incluent pas le nom du dossier.

Pour rediriger vers une page située dans une autre Zone, spécifiez la zone :

RedirectToPage("/Index", new { area = "Services" });

Pour plus d’informations, consultez Zones dans ASP.NET Core et Razor Conventions de routage et d’application des pages dans ASP.NET Core.

Attribut ViewData

Les données peuvent être passées à une page avec ViewDataAttribute . Les valeurs des propriétés avec l' [ViewData] attribut sont stockées et chargées à partir de ViewDataDictionary .

Dans l’exemple suivant, le AboutModel applique l' [ViewData] attribut à la Title propriété :

public class AboutModel : PageModel
{
    [ViewData]
    public string Title { get; } = "About";

    public void OnGet()
    {
    }
}

Dans la page À propos de, accédez à la propriété Title en tant que propriété de modèle :

<h1>@Model.Title</h1>

Dans la disposition, le titre est lu à partir du dictionnaire ViewData :

<!DOCTYPE html>
<html lang="en">
<head>
    <title>@ViewData["Title"] - WebApplication</title>
    ...

TempData

ASP.NET Core expose TempData . Cette propriété stocke les données jusqu’à ce qu’elles soient lues. Vous pouvez utiliser les méthodes Keep et Peek pour examiner les données sans suppression. TempData est utile pour la redirection, quand des données sont nécessaires pour plusieurs requêtes.

Le code suivant définit la valeur de Message à l’aide de TempData :

public class CreateDotModel : PageModel
{
    private readonly AppDbContext _db;

    public CreateDotModel(AppDbContext db)
    {
        _db = db;
    }

    [TempData]
    public string Message { get; set; }

    [BindProperty]
    public Customer Customer { get; set; }

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

        _db.Customers.Add(Customer);
        await _db.SaveChangesAsync();
        Message = $"Customer {Customer.Name} added";
        return RedirectToPage("./Index");
    }
}

Le balisage suivant dans le fichier Pages/Customers/Index.cshtml affiche la valeur de Message à l’aide de TempData.

<h3>Msg: @Model.Message</h3>

Le modèle de page Pages/Customers/Index.cshtml.cs applique l’attribut [TempData] à la propriété Message.

[TempData]
public string Message { get; set; }

Pour plus d’informations, consultez TempData.

Plusieurs gestionnaires par page

La page suivante génère un balisage pour deux gestionnaires en utilisant le Tag Helper asp-page-handler :

@page
@model CreateFATHModel

<html>
<body>
    <p>
        Enter your name.
    </p>
    <div asp-validation-summary="All"></div>
    <form method="POST">
        <div>Name: <input asp-for="Customer.Name" /></div>
        <input type="submit" asp-page-handler="JoinList" value="Join" />
        <input type="submit" asp-page-handler="JoinListUC" value="JOIN UC" />
    </form>
</body>
</html>

Le formulaire dans l’exemple précédent contient deux boutons d’envoi, chacun utilisant FormActionTagHelper pour envoyer à une URL différente. L’attribut asp-page-handler est un complément de asp-page. asp-page-handler génère des URL qui envoient à chacune des méthodes de gestionnaire définies par une page. asp-page n’est pas spécifié, car l’exemple établit une liaison à la page active.

Le modèle de page :

using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using RazorPagesContacts.Data;

namespace RazorPagesContacts.Pages.Customers
{
    public class CreateFATHModel : PageModel
    {
        private readonly AppDbContext _db;

        public CreateFATHModel(AppDbContext db)
        {
            _db = db;
        }

        [BindProperty]
        public Customer Customer { get; set; }

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

            _db.Customers.Add(Customer);
            await _db.SaveChangesAsync();
            return RedirectToPage("/Index");
        }

        public async Task<IActionResult> OnPostJoinListUCAsync()
        {
            if (!ModelState.IsValid)
            {
                return Page();
            }
            Customer.Name = Customer.Name?.ToUpperInvariant();
            return await OnPostJoinListAsync();
        }
    }
}

Le code précédent utilise des méthodes de gestionnaire nommées. Pour créer des méthodes de gestionnaire nommées, il faut prendre le texte dans le nom après On<HTTP Verb> et avant Async (le cas échéant). Dans l’exemple précédent, les méthodes de page sont OnPost JoinList Async et OnPost JoinListUC Async. Avec OnPost et Async supprimés, les noms des gestionnaires sont JoinList et JoinListUC.

<input type="submit" asp-page-handler="JoinList" value="Join" />
<input type="submit" asp-page-handler="JoinListUC" value="JOIN UC" />

Avec le code précédent, le chemin d’URL qui envoie à OnPostJoinListAsync est https://localhost:5001/Customers/CreateFATH?handler=JoinList. Le chemin d’URL qui envoie à OnPostJoinListUCAsync est https://localhost:5001/Customers/CreateFATH?handler=JoinListUC.

Itinéraires personnalisés

Utilisez la directive @page pour :

  • Spécifier une route personnalisée vers une page. Par exemple, la route vers la page À propos peut être définie sur /Some/Other/Path avec @page "/Some/Other/Path".
  • Ajouter des segments à la route par défaut d’une page. Par exemple, un segment « item » peut être ajouté à la route par défaut d’une page avec @page "item".
  • Ajouter des paramètres à la route par défaut d’une page. Par exemple, un paramètre d’ID, id, peut être nécessaire pour une page avec @page "{id}".

Un chemin relatif racine désigné par un tilde (~) au début du chemin est pris en charge. Par exemple, @page "~/Some/Other/Path" est identique à @page "/Some/Other/Path".

Si vous n’aimez pas la chaîne ?handler=JoinList de requête dans l’URL, modifiez l’itinéraire pour placer le nom du gestionnaire dans la partie chemin d’accès de l’URL. L’itinéraire peut être personnalisé en ajoutant un modèle de routage entre guillemets doubles après la @page directive.

@page "{handler?}"
@model CreateRouteModel

<html>
<body>
    <p>
        Enter your name.
    </p>
    <div asp-validation-summary="All"></div>
    <form method="POST">
        <div>Name: <input asp-for="Customer.Name" /></div>
        <input type="submit" asp-page-handler="JoinList" value="Join" />
        <input type="submit" asp-page-handler="JoinListUC" value="JOIN UC" />
    </form>
</body>
</html>

Avec le code précédent, le chemin d’URL qui envoie à OnPostJoinListAsync est https://localhost:5001/Customers/CreateFATH/JoinList. Le chemin d’URL qui envoie à OnPostJoinListUCAsync est https://localhost:5001/Customers/CreateFATH/JoinListUC.

Le ? suivant handler signifie que le paramètre d’itinéraire est facultatif.

Configuration et paramètres avancés

La configuration et les paramètres des sections suivantes ne sont pas requis par la plupart des applications.

Pour configurer des options avancées, utilisez la surcharge qui est configurée AddRazorPages RazorPagesOptions :

public void ConfigureServices(IServiceCollection services)
{            
    services.AddRazorPages(options =>
    {
        options.RootDirectory = "/MyPages";
        options.Conventions.AuthorizeFolder("/MyPages/Admin");
    });
}

Utilisez RazorPagesOptions pour définir le répertoire racine pour les pages ou ajouter des conventions de modèle d’application pour les pages. Pour plus d’informations sur les conventions, consultez Razor conventions d’autorisation des pages.

Pour précompiler des vues, consultez Razor afficher la compilation.

Spécifier que Razor les pages se trouvent à la racine du contenu

Par défaut, Razor les pages sont enracinées dans le répertoire /pages Ajouter WithRazorPagesAtContentRoot pour spécifier que vos Razor pages se trouvent à la racine du contenu ( ContentRootPath ) de l’application :

public void ConfigureServices(IServiceCollection services)
{            
    services.AddRazorPages(options =>
        {
            options.Conventions.AuthorizeFolder("/MyPages/Admin");
        })
        .WithRazorPagesAtContentRoot();
}

Spécifier que Razor les pages se trouvent dans un répertoire racine personnalisé

Ajouter WithRazorPagesRoot pour spécifier que Razor les pages se trouvent dans un répertoire racine personnalisé dans l’application (fournissez un chemin d’accès relatif) :

public void ConfigureServices(IServiceCollection services)
{            
    services.AddRazorPages(options =>
        {
            options.Conventions.AuthorizeFolder("/MyPages/Admin");
        })
        .WithRazorPagesRoot("/path/to/razor/pages");
}

Ressources supplémentaires

Avertissement

Si vous utilisez Visual Studio 2017, consultez le problème no 3124 dotnet/sdk pour plus d’informations sur les versions du Kit SDK .NET Core qui ne fonctionnent pas avec Visual Studio.

Créer un Razor projet pages

Pour obtenir des instructions détaillées sur la création d’un projet de pages, consultez prise en main des Razor pages Razor .

Razor Pages

Razor Les pages sont activées dans Startup. cs:

public class Startup
{
    public void ConfigureServices(IServiceCollection services)
    {
        // Includes support for Razor Pages and controllers.
        services.AddMvc();
    }

    public void Configure(IApplicationBuilder app)
    {
        app.UseMvc();
    }
}

Considérez une page de base :

@page

<h1>Hello, world!</h1>
<h2>The time on the server is @DateTime.Now</h2>

Le code précédent ressemble beaucoup à un Razor fichier de vue utilisé dans une application ASP.net core avec des contrôleurs et des vues. Ce qui le rend différent est la directive @page. @page fait du fichier une action MVC, ce qui signifie qu’il gère les demandes directement, sans passer par un contrôleur. @page doit être la première Razor directive sur une page. @page affecte le comportement d’autres Razor constructions.

Une page similaire, utilisant une classe PageModel, est illustrée dans les deux fichiers suivants. Le fichier Pages/Index2.cshtml :

@page
@using RazorPagesIntro.Pages
@model IndexModel2

<h2>Separate page model</h2>
<p>
    @Model.Message
</p>

Le modèle de page Pages/Index2.cshtml.cs :

using Microsoft.AspNetCore.Mvc.RazorPages;
using System;

namespace RazorPagesIntro.Pages
{
    public class IndexModel2 : PageModel
    {
        public string Message { get; private set; } = "PageModel in C#";

        public void OnGet()
        {
            Message += $" Server time is { DateTime.Now }";
        }
    }
}

Par Convention, le PageModel fichier de classe a le même nom que le Razor fichier d’échange avec . cs ajouté. Par exemple, la Razor page précédente est pages/index2. cshtml. Le fichier contenant la classe PageModel se nomme Pages/Index2.cshtml.cs.

Les associations des chemins d’URL aux pages sont déterminées par l’emplacement de la page dans le système de fichiers. Le tableau suivant indique un Razor chemin d’accès à la page et l’URL correspondante :

Nom et chemin de fichier URL correspondante
/Pages/Index.cshtml / ou /Index
/Pages/Contact.cshtml /Contact
/Pages/Store/Contact.cshtml /Store/Contact
/Pages/Store/Index.cshtml /Store ou /Store/Index

Remarques :

  • Le runtime recherche les Razor fichiers de pages dans le dossier pages par défaut.
  • Index est la page par défaut quand une URL n’inclut pas de page.

Écrire un formulaire de base

Razor Les pages sont conçues pour rendre les modèles courants utilisés avec les navigateurs Web faciles à implémenter lors de la création d’une application. La liaison de modèle, les tag helperset les applications auxiliaires HTML fonctionnent tout simplement avec les propriétés définies dans une classe de Razor page. Considérez une page qui implémente un formulaire « Nous contacter » de base pour le modèle Contact :

Pour les exemples de ce document, le DbContext est initialisé dans le fichier Startup.cs.

using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using RazorPagesContacts.Data;

namespace RazorPagesContacts
{
    public class Startup
    {
        public IHostingEnvironment HostingEnvironment { get; }

        public void ConfigureServices(IServiceCollection services)
        {
            services.AddDbContext<AppDbContext>(options =>
                              options.UseInMemoryDatabase("name"));
            services.AddMvc();
        }

        public void Configure(IApplicationBuilder app)
        {
            app.UseMvc();
        }
    }
}

Le modèle de données :

using System.ComponentModel.DataAnnotations;

namespace RazorPagesContacts.Data
{
    public class Customer
    {
        public int Id { get; set; }

        [Required, StringLength(100)]
        public string Name { get; set; }
    }
}

Le contexte de la base de données :

using Microsoft.EntityFrameworkCore;

namespace RazorPagesContacts.Data
{
    public class AppDbContext : DbContext
    {
        public AppDbContext(DbContextOptions options)
            : base(options)
        {
        }

        public DbSet<Customer> Customers { get; set; }
    }
}

Le fichier vue Pages/Create.cshtml :

@page
@model RazorPagesContacts.Pages.CreateModel
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers

<html>
<body>
    <p>
        Enter your name.
    </p>
    <div asp-validation-summary="All"></div>
    <form method="POST">
        <div>Name: <input asp-for="Customer.Name" /></div>
        <input type="submit" />
    </form>
</body>
</html>

Le modèle de page Pages/Create.cshtml.cs :

using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using RazorPagesContacts.Data;

namespace RazorPagesContacts.Pages
{
    public class CreateModel : PageModel
    {
        private readonly AppDbContext _db;

        public CreateModel(AppDbContext db)
        {
            _db = db;
        }

        [BindProperty]
        public Customer Customer { get; set; }

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

            _db.Customers.Add(Customer);
            await _db.SaveChangesAsync();
            return RedirectToPage("/Index");
        }
    }
}

Par convention, la classe PageModel se nomme <PageName>Model et se trouve dans le même espace de noms que la page.

La classe PageModel permet de séparer la logique d’une page de sa présentation. Elle définit des gestionnaires de page pour les demandes envoyées à la page et les données utilisées pour l’afficher. Cette séparation permet :

La page a une méthode de gestionnaireOnPostAsync, qui s’exécute sur les requêtes POST (quand un utilisateur poste le formulaire). Vous pouvez ajouter des méthodes de gestionnaire pour n’importe quel verbe HTTP. Les gestionnaires les plus courants sont :

  • OnGet pour initialiser l’état nécessaire pour la page. Exemple OnGet.
  • OnPost pour gérer les envois de formulaire.

Le suffixe de nommage Async est facultatif, mais souvent utilisé par convention pour les fonctions asynchrones. Le code précédent est normal pour les Razor pages.

Si vous êtes familiarisé avec les applications ASP.NET à l’aide de contrôleurs et de vues :

  • Le OnPostAsync Code de l’exemple précédent ressemble au code de contrôleur classique.
  • La plupart des primitives MVC, telles que la liaison de modèle, la validation, la validationet les résultats d’action, sont partagées.

La méthode OnPostAsync précédente :

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

    _db.Customers.Add(Customer);
    await _db.SaveChangesAsync();
    return RedirectToPage("/Index");
}

Le flux de base de OnPostAsync :

Vérifiez s’il y a des erreurs de validation.

  • S’il n’y a aucune erreur, enregistrez les données et redirigez.
  • S’il y a des erreurs, réaffichez la page avec des messages de validation. La validation côté client est identique à celle des applications ASP.NET Core MVC traditionnelles. Dans de nombreux cas, les erreurs de validation seraient détectées sur le client et jamais envoyées au serveur.

Quand les données sont entrées correctement, la méthode de gestionnaire OnPostAsync appelle la méthode d’assistance RedirectToPage pour retourner une instance de RedirectToPageResult. RedirectToPage est un nouveau résultat d’action, semblable à RedirectToAction ou RedirectToRoute, mais personnalisé pour les pages. Dans l’exemple précédent, il redirige vers la page Index racine (/Index). RedirectToPage est détaillé dans la section génération d’URL pour les pages .

Quand le formulaire envoyé comporte des erreurs de validation (qui sont passées au serveur), la méthode de gestionnaire OnPostAsync appelle la méthode d’assistance Page. Page retourne une instance de PageResult. Le retour de Page est similaire à la façon dont les actions dans les contrôleurs retournent View. PageResult est le type de retour par défaut pour une méthode de gestionnaire. Une méthode de gestionnaire qui retourne void restitue la page.

La propriété Customer utilise l’attribut [BindProperty] pour accepter la liaison de modèle.

public class CreateModel : PageModel
{
    private readonly AppDbContext _db;

    public CreateModel(AppDbContext db)
    {
        _db = db;
    }

    [BindProperty]
    public Customer Customer { get; set; }

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

        _db.Customers.Add(Customer);
        await _db.SaveChangesAsync();
        return RedirectToPage("/Index");
    }
}

Razor Les pages, par défaut, lient les propriétés uniquement avec des non- GET verbes. La liaison à des propriétés peut réduire la quantité de code à écrire. Elle réduit la quantité de code en utilisant la même propriété pour afficher les champs de formulaire (<input asp-for="Customer.Name">) et accepter l’entrée.

Avertissement

Pour des raisons de sécurité, vous devez choisir de lier les données de requête GET aux propriétés du modèle de page. Vérifiez l’entrée utilisateur avant de la mapper à des propriétés. L’utilisation GET de la liaison est utile lors de l’adressage de scénarios qui reposent sur une chaîne de requête ou des valeurs de route.

Pour lier une propriété à des GET demandes, affectez [BindProperty] à la propriété de l’attribut la valeur SupportsGet true :

[BindProperty(SupportsGet = true)]

Pour plus d’informations, consultez ASP.net Core de la communauté réunions : lier sur obtenir une discussion (YouTube).

La page d’accueil (Index.cshtml) :

@page
@model RazorPagesContacts.Pages.IndexModel
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers

<h1>Contacts</h1>
<form method="post">
    <table class="table">
        <thead>
            <tr>
                <th>ID</th>
                <th>Name</th>
            </tr>
        </thead>
        <tbody>
            @foreach (var contact in Model.Customers)
            {
                <tr>
                    <td>@contact.Id</td>
                    <td>@contact.Name</td>
                    <td>
                        <a asp-page="./Edit" asp-route-id="@contact.Id">edit</a>
                        <button type="submit" asp-page-handler="delete" 
                                asp-route-id="@contact.Id">delete</button>
                    </td>
                </tr>
            }
        </tbody>
    </table>

    <a asp-page="./Create">Create</a>
</form>

La classe PageModel associée (Index.cshtml.cs) :

using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using RazorPagesContacts.Data;
using System.Collections.Generic;
using Microsoft.EntityFrameworkCore;

namespace RazorPagesContacts.Pages
{
    public class IndexModel : PageModel
    {
        private readonly AppDbContext _db;

        public IndexModel(AppDbContext db)
        {
            _db = db;
        }

        public IList<Customer> Customers { get; private set; }

        public async Task OnGetAsync()
        {
            Customers = await _db.Customers.AsNoTracking().ToListAsync();
        }

        public async Task<IActionResult> OnPostDeleteAsync(int id)
        {
            var contact = await _db.Customers.FindAsync(id);

            if (contact != null)
            {
                _db.Customers.Remove(contact);
                await _db.SaveChangesAsync();
            }

            return RedirectToPage();
        }
    }
}

Le fichier Index.cshtml contient le balisage suivant pour créer un lien d’édition pour chaque contact :

<a asp-page="./Edit" asp-route-id="@contact.Id">edit</a>

Le <a asp-page="./Edit" asp-route-id="@contact.Id">Edit</a> tag Helper ancre a utilisé l' asp-route-{value} attribut pour générer un lien vers la page de modification. Le lien contient des données d’itinéraire avec l’ID de contact. Par exemple : https://localhost:5001/Edit/1. Les tag helpers permettent au code côté serveur de participer à la création et au rendu des éléments HTML dans les Razor fichiers. Les Tag Helpers sont activés par @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers

Le fichier Pages/Edit.cshtml :

@page "{id:int}"
@model RazorPagesContacts.Pages.EditModel
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers

@{
    ViewData["Title"] = "Edit Customer";
}

<h1>Edit Customer - @Model.Customer.Id</h1>
<form method="post">
    <div asp-validation-summary="All"></div>
    <input asp-for="Customer.Id" type="hidden" />
    <div>
        <label asp-for="Customer.Name"></label>
        <div>
            <input asp-for="Customer.Name" />
            <span asp-validation-for="Customer.Name" ></span>
        </div>
    </div>
 
    <div>
        <button type="submit">Save</button>
    </div>
</form>

La première ligne contient la directive @page "{id:int}". La contrainte de routage "{id:int}" indique à la page qu’elle doit accepter les requêtes qui contiennent des données d’itinéraire int. Si une requête à la page ne contient de données d’itinéraire qui peuvent être converties en int, le runtime retourne une erreur HTTP 404 (introuvable). Pour que l’ID soit facultatif, ajoutez ? à la contrainte d’itinéraire :

@page "{id:int?}"

Le fichier Pages/Edit.cshtml.cs :

using System;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.EntityFrameworkCore;
using RazorPagesContacts.Data;

namespace RazorPagesContacts.Pages
{
    public class EditModel : PageModel
    {
        private readonly AppDbContext _db;

        public EditModel(AppDbContext db)
        {
            _db = db;
        }

        [BindProperty]
        public Customer Customer { get; set; }

        public async Task<IActionResult> OnGetAsync(int id)
        {
            Customer = await _db.Customers.FindAsync(id);

            if (Customer == null)
            {
                return RedirectToPage("/Index");
            }

            return Page();
        }

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

            _db.Attach(Customer).State = EntityState.Modified;

            try
            {
                await _db.SaveChangesAsync();
            }
            catch (DbUpdateConcurrencyException)
            {
                throw new Exception($"Customer {Customer.Id} not found!");
            }

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

Le fichier Index.cshtml contient également le balisage pour créer un bouton Supprimer pour chaque contact client :

<button type="submit" asp-page-handler="delete" 
        asp-route-id="@contact.Id">delete</button>

Lorsque le bouton Supprimer est rendu en HTML, son formaction comprend des paramètres pour :

  • L’ID du contact client spécifié par l’attribut asp-route-id.
  • Le handler spécifié par l’attribut asp-page-handler.

Voici un exemple de bouton Supprimer rendu avec un ID de contact client de 1:

<button type="submit" formaction="/?id=1&amp;handler=delete">delete</button>

Quand le bouton est sélectionné, une demande POST de forumaire est envoyée au serveur. Par convention, le nom de la méthode de gestionnaire est sélectionné en fonction de la valeur du paramètre handler conformément au schéma OnPost[handler]Async.

Étant donné que le handler est delete dans cet exemple, la méthode de gestionnaire OnPostDeleteAsync est utilisée pour traiter la demande POST. Si asp-page-handler est défini sur une autre valeur, comme remove, une méthode de gestionnaire avec le nom OnPostRemoveAsync est sélectionnée. Le code suivant illustre le OnPostDeleteAsync Gestionnaire :

public async Task<IActionResult> OnPostDeleteAsync(int id)
{
    var contact = await _db.Customers.FindAsync(id);

    if (contact != null)
    {
        _db.Customers.Remove(contact);
        await _db.SaveChangesAsync();
    }

    return RedirectToPage();
}

La méthode OnPostDeleteAsync :

  • Accepte l’id de la chaîne de requête. Si la directive de la page index. cshtml contenait la contrainte "{id:int?}" de routage, id provient des données d’itinéraire. Les données d’itinéraire pour id sont spécifiées dans l’URI, par exemple https://localhost:5001/Customers/2 .
  • Interroge la base de données pour le contact client avec FindAsync.
  • Si le contact client est trouvé, il est supprimé de la liste des contacts client. La base de données est mise à jour.
  • Appelle RedirectToPage pour rediriger vers la page Index racine (/Index).

Marquer les propriétés de page comme Required

Les propriétés d’un PageModel peuvent être marquées avec l’attribut Required :

using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using System.ComponentModel.DataAnnotations;

namespace RazorPagesMovie.Pages.Movies
{
    public class CreateModel : PageModel
    {
        public IActionResult OnGet()
        {
            return Page();
        }

        [BindProperty]
        [Required(ErrorMessage = "Color is required")]
        public string Color { get; set; }

        public IActionResult OnPostAsync()
        {
            if (!ModelState.IsValid)
            {
                return Page();
            }

            // Process color.

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

Pour plus d’informations, consultez Validation de modèle.

Gérer les requêtes HEAD avec un gestionnaire OnGet de secours

Les requêtes HEAD vous permettent de récupérer les en-têtes pour une ressource spécifique. Contrairement aux requêtes GET, les requêtes HEAD ne retournent pas un corps de réponse.

En règle générale, un gestionnaire OnHead est créé et appelé pour les requêtes HEAD :

public void OnHead()
{
    HttpContext.Response.Headers.Add("HandledBy", "Handled by OnHead!");
}

Dans ASP.NET Core 2,1 ou version ultérieure, Razor les pages reviennent à appeler le OnGet Gestionnaire si aucun OnHead gestionnaire n’est défini. Ce comportement est activé par l’appel à SetCompatibilityVersion dans Startup.ConfigureServices :

services.AddMvc()
    .SetCompatibilityVersion(CompatibilityVersion.Version_2_1);

Les modèles par défaut génèrent l'appel SetCompatibilityVersion dans ASP.NET Core 2.1 et 2.2. SetCompatibilityVersion affecte efficacement Razor à l’option pages la AllowMappingHeadRequestsToGetHandler valeur true .

Au lieu d’adhérer à tous les comportements avec SetCompatibilityVersion, vous pouvez adhérer explicitement à des comportements spécifiques. Le code suivant adhère à l’autorisation de mappage des requêtes HEAD au gestionnaire OnGet :

services.AddMvc()
    .AddRazorPagesOptions(options =>
    {
        options.AllowMappingHeadRequestsToGetHandler = true;
    });

XSRF/CSRF et Razor pages

Vous n’avez aucun code à écrire pour la validation anti-contrefaçon. La génération et la validation des jetons anti-contrefaçon sont automatiquement incluses dans les Razor pages.

Utilisation de dispositions, de partiels, de modèles et d’aide pour les balises avec des Razor pages

Les pages fonctionnent avec toutes les fonctionnalités du Razor moteur d’affichage. Les mises en page, les partiels, les modèles, les tag helpers, _ViewStart. cshtml, _ViewImports. cshtml fonctionnent de la même façon que pour les Razor vues conventionnelles.

Nous allons nettoyer un peu cette page en tirant parti de certaines de ces fonctionnalités.

Ajoutez une page de disposition à Pages/Shared/_Layout.cshtml :

<!DOCTYPE html>
<html>
<head> 
    <title>Razor Pages Sample</title>      
</head>
<body>    
   <a asp-page="/Index">Home</a>
    @RenderBody()  
    <a asp-page="/Customers/Create">Create</a> <br />
</body>
</html>

La disposition:

  • Contrôle la disposition de chaque page (à moins que la page ne refuse la disposition).
  • Importe des structures HTML telles que JavaScript et les feuilles de style.

Pour plus d’informations, consultez Page de disposition.

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

@{
    Layout = "_Layout";
}

La disposition est dans le dossier Pages/Shared. Les pages recherchent d’autres vues (dispositions, modèles, partiels) hiérarchiquement, en commençant dans le même dossier que la page active. Une mise en page dans le dossier pages/Shared peut être utilisée à partir de n’importe quelle Razor page sous le dossier pages .

Le fichier de disposition doit être placé dans le dossier Pages/Shared.

Nous vous recommandons de ne pas placer le fichier de disposition dans le dossier Views/Shared. Views/Shared est un modèle de vues MVC. Razor Les pages sont conçues pour s’appuyer sur la hiérarchie des dossiers, et non sur les conventions de chemin.

L’affichage de la recherche à partir d’une Razor page comprend le dossier pages . Les mises en page, les modèles et les partiels que vous utilisez avec les contrôleurs MVC et les Razor vues conventionnelles fonctionnent simplement.

Ajoutez un fichier Pages/_ViewImports.cshtml :

@namespace RazorPagesContacts.Pages
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers

@namespace est expliqué plus loin dans le didacticiel. La directive @addTagHelper permet de bénéficier des Tag Helpers intégrés dans toutes les pages du dossier Pages.

Quand la directive @namespace est utilisée explicitement sur une page :

@page
@namespace RazorPagesIntro.Pages.Customers

@model NameSpaceModel

<h2>Name space</h2>
<p>
    @Model.Message
</p>

La directive définit l’espace de noms pour la page. La directive @model n’a pas besoin d’inclure l’espace de noms.

Quand la directive @namespace est contenue dans _ViewImports.cshtml, l’espace de noms spécifié fournit le préfixe de l’espace de noms généré dans la Page qui importe la directive @namespace. Le reste de l’espace de noms généré (la partie suffixe) est le chemin relatif séparé par un point entre le dossier contenant _ViewImports.cshtml et le dossier contenant la page.

Par exemple, la classe PageModelPages/Customers/Edit.cshtml.cs définit explicitement l’espace de noms :

namespace RazorPagesContacts.Pages
{
    public class EditModel : PageModel
    {
        private readonly AppDbContext _db;

        public EditModel(AppDbContext db)
        {
            _db = db;
        }

        // Code removed for brevity.

Le fichier Pages/_ViewImports.cshtml définit l’espace de noms suivant :

@namespace RazorPagesContacts.Pages
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers

L’espace de noms généré pour la page pages/Customers/Edit. cshtml Razor est le même que la PageModel classe.

@namespacefonctionne également avec les Razor vues conventionnelles.

Le fichier de vue Pages/Create.cshtml d’origine :

@page
@model RazorPagesContacts.Pages.CreateModel
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers

<html>
<body>
    <p>
        Enter your name.
    </p>
    <div asp-validation-summary="All"></div>
    <form method="POST">
        <div>Name: <input asp-for="Customer.Name" /></div>
        <input type="submit" />
    </form>
</body>
</html>

Le fichier vue Pages/Create.cshtml mis à jour :

@page
@model CreateModel

<html>
<body>
    <p>
        Enter your name.
    </p>
    <div asp-validation-summary="All"></div>
    <form method="POST">
        <div>Name: <input asp-for="Customer.Name" /></div>
        <input type="submit" />
    </form>
</body>
</html>

Le Razor projet de démarrage pages contient les pages/_ValidationScriptsPartial. cshtml, qui raccorde la validation côté client.

Pour plus d'informations sur les affichages partiels, consultez Vues partielles dans ASP.NET Core.

Génération d’URL pour les pages

La page Create, illustrée précédemment, utilise RedirectToPage :

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

    _db.Customers.Add(Customer);
    await _db.SaveChangesAsync();
    return RedirectToPage("/Index");
}

L’application a la structure de fichiers/dossiers suivante :

  • /Pages

    • Index.cshtml

    • /Customers

      • Create.cshtml
      • Edit.cshtml
      • Index.cshtml

Une fois l’opération réussie, les pages Pages/Customers/Create.cshtml et Pages/Customers/Edit.cshtml redirigent vers Pages/Index.cshtml. La chaîne /Index fait partie de l’URI pour accéder à la page précédente. La chaîne /Index peut être utilisée pour générer l’URI de la page Pages/Index.cshtml. Par exemple :

  • Url.Page("/Index", ...)
  • <a asp-page="/Index">My Index Page</a>
  • RedirectToPage("/Index")

Le nom de la page est le chemin de la page à partir du dossier racine /Pages avec un / devant (par exemple, /Index). Les exemples de génération d’URL précédents offrent des options améliorées et des capacités fonctionnelles sur le codage en dur d’une URL. La génération d’URL utilise le routage et peut générer et encoder des paramètres en fonction de la façon dont l’itinéraire est défini dans le chemin de destination.

La génération d’URL pour les pages prend en charge les noms relatifs. Le tableau suivant montre la page Index sélectionnée avec différents paramètres RedirectToPage à partir de Pages/Customers/Create.cshtml :

RedirectToPage(x) Page
RedirectToPage("/Index") Pages/Index
RedirectToPage("./Index"); Pages/Customers/Index
RedirectToPage("../Index") Pages/Index
RedirectToPage("Index") Pages/Customers/Index

RedirectToPage("Index"), RedirectToPage("./Index") et RedirectToPage("../Index") sont des noms relatifs. Le paramètre RedirectToPage est combiné avec le chemin de la page active pour calculer le nom de la page de destination.

La liaison de nom relatif est utile lors de la création de sites avec une structure complexe. Si vous utilisez des noms relatifs pour établir une liaison entre les pages d’un dossier, vous pouvez renommer ce dossier. Tous les liens fonctionneront encore (car ils n’incluent pas le nom du dossier).

Pour rediriger vers une page située dans une autre Zone, spécifiez la zone :

RedirectToPage("/Index", new { area = "Services" });

Pour plus d’informations, consultez Zones dans ASP.NET Core.

Attribut ViewData

Les données peuvent être passées à une page avec ViewDataAttribute. Les propriétés sur les contrôleurs ou Razor les modèles de page avec l' [ViewData] attribut ont leurs valeurs stockées et chargées à partir du ViewDataDictionary.

Dans l’exemple suivant, le AboutModel contient une Title propriété marquée avec [ViewData] . La propriété Title a pour valeur le titre de la page À propos de :

public class AboutModel : PageModel
{
    [ViewData]
    public string Title { get; } = "About";

    public void OnGet()
    {
    }
}

Dans la page À propos de, accédez à la propriété Title en tant que propriété de modèle :

<h1>@Model.Title</h1>

Dans la disposition, le titre est lu à partir du dictionnaire ViewData :

<!DOCTYPE html>
<html lang="en">
<head>
    <title>@ViewData["Title"] - WebApplication</title>
    ...

TempData

ASP.NET Core expose la propriété TempData sur un contrôleur. Cette propriété stocke les données jusqu’à ce qu’elles soient lues. Vous pouvez utiliser les méthodes Keep et Peek pour examiner les données sans suppression. TempData est utile pour la redirection, quand des données sont nécessaires pour plusieurs requêtes.

Le code suivant définit la valeur de Message à l’aide de TempData :

public class CreateDotModel : PageModel
{
    private readonly AppDbContext _db;

    public CreateDotModel(AppDbContext db)
    {
        _db = db;
    }

    [TempData]
    public string Message { get; set; }

    [BindProperty]
    public Customer Customer { get; set; }

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

        _db.Customers.Add(Customer);
        await _db.SaveChangesAsync();
        Message = $"Customer {Customer.Name} added";
        return RedirectToPage("./Index");
    }
}

Le balisage suivant dans le fichier Pages/Customers/Index.cshtml affiche la valeur de Message à l’aide de TempData.

<h3>Msg: @Model.Message</h3>

Le modèle de page Pages/Customers/Index.cshtml.cs applique l’attribut [TempData] à la propriété Message.

[TempData]
public string Message { get; set; }

Pour plus d’informations, consultez TempData.

Plusieurs gestionnaires par page

La page suivante génère un balisage pour deux gestionnaires en utilisant le Tag Helper asp-page-handler :

@page
@model CreateFATHModel

<html>
<body>
    <p>
        Enter your name.
    </p>
    <div asp-validation-summary="All"></div>
    <form method="POST">
        <div>Name: <input asp-for="Customer.Name" /></div>
        <input type="submit" asp-page-handler="JoinList" value="Join" />
        <input type="submit" asp-page-handler="JoinListUC" value="JOIN UC" />
    </form>
</body>
</html>

Le formulaire dans l’exemple précédent contient deux boutons d’envoi, chacun utilisant FormActionTagHelper pour envoyer à une URL différente. L’attribut asp-page-handler est un complément de asp-page. asp-page-handler génère des URL qui envoient à chacune des méthodes de gestionnaire définies par une page. asp-page n’est pas spécifié, car l’exemple établit une liaison à la page active.

Le modèle de page :

using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using RazorPagesContacts.Data;

namespace RazorPagesContacts.Pages.Customers
{
    public class CreateFATHModel : PageModel
    {
        private readonly AppDbContext _db;

        public CreateFATHModel(AppDbContext db)
        {
            _db = db;
        }

        [BindProperty]
        public Customer Customer { get; set; }

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

            _db.Customers.Add(Customer);
            await _db.SaveChangesAsync();
            return RedirectToPage("/Index");
        }

        public async Task<IActionResult> OnPostJoinListUCAsync()
        {
            if (!ModelState.IsValid)
            {
                return Page();
            }
            Customer.Name = Customer.Name?.ToUpperInvariant();
            return await OnPostJoinListAsync();
        }
    }
}

Le code précédent utilise des méthodes de gestionnaire nommées. Pour créer des méthodes de gestionnaire nommées, il faut prendre le texte dans le nom après On<HTTP Verb> et avant Async (le cas échéant). Dans l’exemple précédent, les méthodes de page sont OnPost JoinList Async et OnPost JoinListUC Async. Avec OnPost et Async supprimés, les noms des gestionnaires sont JoinList et JoinListUC.

<input type="submit" asp-page-handler="JoinList" value="Join" />
<input type="submit" asp-page-handler="JoinListUC" value="JOIN UC" />

Avec le code précédent, le chemin d’URL qui envoie à OnPostJoinListAsync est https://localhost:5001/Customers/CreateFATH?handler=JoinList. Le chemin d’URL qui envoie à OnPostJoinListUCAsync est https://localhost:5001/Customers/CreateFATH?handler=JoinListUC.

Itinéraires personnalisés

Utilisez la directive @page pour :

  • Spécifier une route personnalisée vers une page. Par exemple, la route vers la page À propos peut être définie sur /Some/Other/Path avec @page "/Some/Other/Path".
  • Ajouter des segments à la route par défaut d’une page. Par exemple, un segment « item » peut être ajouté à la route par défaut d’une page avec @page "item".
  • Ajouter des paramètres à la route par défaut d’une page. Par exemple, un paramètre d’ID, id, peut être nécessaire pour une page avec @page "{id}".

Un chemin relatif racine désigné par un tilde (~) au début du chemin est pris en charge. Par exemple, @page "~/Some/Other/Path" est identique à @page "/Some/Other/Path".

Si vous n’aimez pas la chaîne ?handler=JoinList de requête dans l’URL, modifiez l’itinéraire pour placer le nom du gestionnaire dans la partie chemin d’accès de l’URL. L’itinéraire peut être personnalisé en ajoutant un modèle de routage entre guillemets doubles après la @page directive.

@page "{handler?}"
@model CreateRouteModel

<html>
<body>
    <p>
        Enter your name.
    </p>
    <div asp-validation-summary="All"></div>
    <form method="POST">
        <div>Name: <input asp-for="Customer.Name" /></div>
        <input type="submit" asp-page-handler="JoinList" value="Join" />
        <input type="submit" asp-page-handler="JoinListUC" value="JOIN UC" />
    </form>
</body>
</html>

Avec le code précédent, le chemin d’URL qui envoie à OnPostJoinListAsync est https://localhost:5001/Customers/CreateFATH/JoinList. Le chemin d’URL qui envoie à OnPostJoinListUCAsync est https://localhost:5001/Customers/CreateFATH/JoinListUC.

Le ? suivant handler signifie que le paramètre d’itinéraire est facultatif.

Configuration et paramètres

Pour configurer les options avancées, utilisez la méthode d’extension AddRazorPagesOptions sur le générateur MVC :

public void ConfigureServices(IServiceCollection services)
{
    services.AddMvc()
        .AddRazorPagesOptions(options =>
        {
            options.RootDirectory = "/MyPages";
            options.Conventions.AuthorizeFolder("/MyPages/Admin");
        });
}

Actuellement, vous pouvez utiliser RazorPagesOptions pour définir le répertoire racine pour les pages, ou ajouter des conventions de modèle d’application pour les pages. Nous permettrons à l’avenir une plus grande extensibilité en ce sens.

Pour précompiler des vues, consultez Razor afficher la compilation .

Téléchargez ou affichez des exemples de code.

Consultez prise en main des Razor pages, qui s’appuie sur cette introduction.

Spécifier que Razor les pages se trouvent à la racine du contenu

Par défaut, Razor les pages sont enracinées dans le répertoire /pages Ajoutez avec Razor PagesAtContentRoot à AddMvc pour spécifier que vos Razor pages se trouvent à la racine du contenu (ContentRootPath) de l’application :

services.AddMvc()
    .AddRazorPagesOptions(options =>
    {
        ...
    })
    .WithRazorPagesAtContentRoot();

Spécifier que Razor les pages se trouvent dans un répertoire racine personnalisé

Ajoutez avec Razor PagesRoot à AddMvc pour spécifier que vos Razor pages se trouvent dans un répertoire racine personnalisé dans l’application (fournissez un chemin d’accès relatif) :

services.AddMvc()
    .AddRazorPagesOptions(options =>
    {
        ...
    })
    .WithRazorPagesRoot("/path/to/razor/pages");

Ressources supplémentaires