Delen via


Razor Paginaarchitectuur en -concepten in ASP.NET Core

Door Rick Anderson, Dave Brock en Kirk Larkin

Note

Dit is niet de nieuwste versie van dit artikel. Zie de .NET 10-versie van dit artikel voor de huidige release.

Warning

Deze versie van ASP.NET Core wordt niet meer ondersteund. Zie het .NET- en .NET Core-ondersteuningsbeleid voor meer informatie. Zie de .NET 9-versie van dit artikel voor de huidige release.

Razor Pagina's kunnen het coderen van paginagerichte scenario's eenvoudiger en productiever maken dan het gebruik van controllers en weergaven.

Zie Aan de slag met ASP.NET Core MVC als u op zoek bent naar een zelfstudie die gebruikmaakt van de model-View-Controller-benadering.

In dit artikel worden de architectuur, concepten en patronen beschreven waarmee pagina's effectief zijn Razor voor het bouwen van webtoepassingen die gericht zijn op pagina's. Hierin wordt uitgelegd hoe Razor Pagina's werken, hun belangrijkste onderdelen en aanbevolen procedures voor implementatie. Zie Zelfstudie: Een Razor pagina-web-app maken met ASP.NET Core als u liever praktische instructies gebruikt voor stapsgewijze instructies. Zie de inleiding tot ASP.NET Core voor een overzicht van ASP.NET Core.

Prerequisites

Een Razor Pagina-project maken

Zie Aan de slag met Razor Pages voor gedetailleerde instructies over het maken van een Razor Pages-project.

Razor pagina's

Razor Pagina's zijn ingeschakeld in Program.cs:

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();

var app = builder.Build();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

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

app.UseRouting();

app.UseAuthorization();

app.MapRazorPages();

app.Run();

In de voorgaande code:

Overweeg een basispagina:

@page

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

De voorgaande code ziet er veel uit als een Razor weergavebestand dat wordt gebruikt in een ASP.NET Core-app met controllers en weergaven. Wat het anders maakt, is de @page richtlijn. @page maakt het bestand in een MVC-actie, wat betekent dat het aanvragen rechtstreeks verwerkt, zonder een controller te doorlopen. @page moet de eerste Razor instructie op een pagina zijn. @page beïnvloedt het gedrag van andere Razor constructies. Razor Bestandsnamen van pagina's hebben een .cshtml achtervoegsel.

Een vergelijkbare pagina, met behulp van een PageModel klasse, wordt weergegeven in de volgende twee bestanden. Het bestand Pages/Index2.cshtml:

@page
@using RazorPagesIntro.Pages
@model Index2Model

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

Het Pages/Index2.cshtml.cs paginamodel:

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

Volgens de conventie heeft het PageModel klassebestand dezelfde naam als het Razor paginabestand waaraan .cs is toegevoegd. Bijvoorbeeld, de vorige Razor pagina is Pages/Index2.cshtml. Het bestand dat de PageModel klasse bevat, is genaamd Pages/Index2.cshtml.cs.

De koppelingen van URL-paden naar pagina's worden bepaald door de locatie van de pagina in het bestandssysteem. In de volgende tabel ziet u een Razor paginapad en de overeenkomende URL:

Bestandsnaam en pad overeenkomende URL
/Pages/Index.cshtml / of /Index
/Pages/Contact.cshtml /Contact
/Pages/Store/Contact.cshtml /Store/Contact
/Pages/Store/Index.cshtml /Store of /Store/Index

Notes:

  • De runtime zoekt standaard naar Razor Pages-bestanden in de map Pagina's .
  • Index is de standaardpagina wanneer een URL geen pagina bevat.

Een basisformulier schrijven

Razor Pagina's zijn ontworpen om algemene patronen die worden gebruikt met webbrowsers eenvoudig te implementeren bij het bouwen van een app. Modelbinding, Tag Helpers en HTML-helpers werken met de eigenschappen die zijn gedefinieerd in een Razor paginaklasse. Denk aan een pagina die een eenvoudig formulier 'contact met ons' implementeert voor het Contact model:

Voor de voorbeelden in dit document wordt het DbContext geïnitialiseerd in het Program.cs-bestand .

Voor de in-geheugendatabase is het Microsoft.EntityFrameworkCore.InMemory NuGet-pakket vereist.

using Microsoft.EntityFrameworkCore;
using RazorPagesContacts.Data;
var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();

builder.Services.AddDbContext<CustomerDbContext>(options =>
    options.UseInMemoryDatabase("name"));

var app = builder.Build();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

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

app.UseRouting();

app.UseAuthorization();

app.MapRazorPages();

app.Run();

Het gegevensmodel:

using System.ComponentModel.DataAnnotations;

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

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

De db-context:

using Microsoft.EntityFrameworkCore;

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

        public DbSet<RazorPagesContacts.Models.Customer> Customer => Set<RazorPagesContacts.Models.Customer>();
    }
}

Het Pages/Customers/Create.cshtml weergavebestand:

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

Het Pages/Customers/Create.cshtml.cs paginamodel:

public class CreateModel : PageModel
{
    private readonly Data.CustomerDbContext _context;

    public CreateModel(Data.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();
        }

        if (Customer != null) _context.Customer.Add(Customer);
        await _context.SaveChangesAsync();

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

De klasse wordt standaard PageModel aangeroepen <PageName>Model en bevindt zich in dezelfde naamruimte als de pagina.

Met PageModel de klasse kunt u de logica van een pagina scheiden van de presentatie. Hiermee worden pagina-handlers gedefinieerd voor aanvragen die naar de pagina worden verzonden en de gegevens die worden gebruikt om de pagina weer te geven. Deze scheiding maakt het volgende mogelijk:

De pagina heeft een OnPostAsynchandlermethode, die wordt uitgevoerd op POST aanvragen (wanneer een gebruiker het formulier plaatst). Handlermethoden voor elk HTTP-werkwoord kunnen worden toegevoegd. De meest voorkomende handlers zijn:

  • OnGet om de status te initialiseren die nodig is voor de pagina. In de voorgaande code geeft de OnGet methode de Create.cshtmlRazor pagina weer.
  • OnPost voor het afhandelen van formulierinzendingen.

Het Async naamachtervoegsel is optioneel, maar wordt vaak gebruikt door conventies voor asynchrone functies. De voorgaande code is typisch voor Razor Pagina's.

Als u bekend bent met ASP.NET apps met behulp van controllers en weergaven:

  • De OnPostAsync code in het voorgaande voorbeeld lijkt op typische controllercode.
  • De meeste MVC-primitieven, zoals modelbinding, validatie en actieresultaten, werken hetzelfde met controllers en Razor pagina's.

De vorige OnPostAsync-methode:

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

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

    if (Customer != null) _context.Customer.Add(Customer);
    await _context.SaveChangesAsync();

    return RedirectToPage("./Index");
}

De basisstroom van OnPostAsync:

Controleer op validatiefouten.

  • Als er geen fouten zijn, slaat u de gegevens op en stuurt u deze om.
  • Als er fouten zijn, kunt u de pagina opnieuw weergeven met validatieberichten. In veel gevallen worden validatiefouten op de client gedetecteerd en nooit verzonden naar de server.

Het Pages/Customers/Create.cshtml weergavebestand:

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

De HTML die door Pages/Customers/Create.cshtml wordt weergegeven:

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

In de vorige code plaatst u het formulier:

  • Met geldige gegevens:

    • De OnPostAsync handlermethode roept de RedirectToPage helpermethode aan. RedirectToPage retourneert een exemplaar van RedirectToPageResult. RedirectToPage:

      • Is een actieresultaat.
      • Is vergelijkbaar met RedirectToAction of RedirectToRoute (gebruikt in controllers en weergaven).
      • Is aangepast voor pagina's. In het voorgaande voorbeeld wordt deze omgeleid naar de hoofdindexpagina (/Index). RedirectToPage wordt beschreven in de sectie Url-generatie voor pagina's .
  • Bij validatiefouten die worden doorgegeven aan de server:

    • De OnPostAsync handlermethode roept de Page helpermethode aan. Page retourneert een exemplaar van PageResult. Teruggeven van Page is vergelijkbaar met de manier waarop acties in controllers View teruggeven. PageResult is het standaard retourtype voor een handlermethode. Een handlermethode die void retourneert rendert de pagina.
    • In het voorgaande voorbeeld resulteert het indienen van het formulier zonder waarde in ModelState.IsValid die onwaar retourneert. In dit voorbeeld worden er geen validatiefouten weergegeven op de client. De afhandeling van validatiefouten wordt verderop in dit document behandeld.
    [BindProperty]
    public Customer? Customer { get; set; }
    
    public async Task<IActionResult> OnPostAsync()
    {
        if (!ModelState.IsValid)
        {
            return Page();
        }
    
        if (Customer != null) _context.Customer.Add(Customer);
        await _context.SaveChangesAsync();
    
        return RedirectToPage("./Index");
    }
    
  • Met validatiefouten gedetecteerd door validatie aan de clientzijde:

    • Gegevens worden niet op de server geplaatst.
    • Validatie aan de clientzijde wordt verderop in dit document uitgelegd.

De Customer eigenschap maakt gebruik van het [BindProperty] kenmerk om zich aan te melden voor modelbinding.

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

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

    if (Customer != null) _context.Customer.Add(Customer);
    await _context.SaveChangesAsync();

    return RedirectToPage("./Index");
}

[BindProperty] mag niet worden gebruikt voor modellen met eigenschappen die niet door de client mogen worden gewijzigd. Zie Overposting voor meer informatie.

Razor Standaard binden pagina's alleen eigenschappen aan elementen die geen werkwoord zijnGET. Binding met eigenschappen verwijdert de noodzaak om code te schrijven om HTTP-gegevens te converteren naar het modeltype. Binding vermindert de code door dezelfde eigenschap te gebruiken om formuliervelden weer te geven (<input asp-for="Customer.Name">) en de invoer te accepteren.

Warning

Om veiligheidsredenen moet u kiezen om GET gegevens te koppelen aan de eigenschappen van het paginamodel. Controleer gebruikersinvoer voordat u deze toe te wijst aan eigenschappen. Het kiezen voor GET binding is nuttig bij het aanpakken van scenario's die afhankelijk zijn van querystring- of routewaarden.

Als u een eigenschap op GET-aanvragen wilt binden, stelt u de [BindProperty]-eigenschap van het SupportsGet-kenmerk in op true.

[BindProperty(SupportsGet = true)]

Zie ASP.NET Core Community Standup: Bind on GET-discussie (YouTube) voor meer informatie.

Pages/Customers/Create.cshtml Het weergavebestand controleren:

@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>
  • In de voorgaande code koppelt de helper <input asp-for="Customer.Name" /> het HTML-element <input> aan de Customer.Name modelexpressie.
  • @addTagHelper Tag Helpers beschikbaar maken.

De startpagina

Index.cshtml is de startpagina:

@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>
        @if (Model.Customers != null)
        {
            foreach (var contact in Model.Customers)
            {
                <tr>
                    <td> @contact.Id </td>
                    <td>@contact.Name</td>
                    <td>
                        <!-- <snippet_Edit> -->
                        <a asp-page="./Edit" asp-route-id="@contact.Id">Edit</a> |
                        <!-- </snippet_Edit> -->
                        <!-- <snippet_Delete> -->
                        <button type="submit" asp-page-handler="delete" asp-route-id="@contact.Id">delete</button>
                        <!-- </snippet_Delete> -->
                    </td>
                </tr>
            }
        }
        </tbody>
    </table>
    <a asp-page="Create">Create New</a>
</form>

De bijbehorende PageModel klasse (Index.cshtml.cs):

public class IndexModel : PageModel
{
    private readonly Data.CustomerDbContext _context;
    public IndexModel(Data.CustomerDbContext context)
    {
        _context = context;
    }

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

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

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

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

        return RedirectToPage();
    }
}

Het Index.cshtml bestand bevat de volgende markeringen:

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

De <a /a>Anchor Tag Helper heeft het asp-route-{value} kenmerk gebruikt om een koppeling naar de pagina Bewerken te genereren. De koppeling bevat routegegevens met de contactpersoon-id. Bijvoorbeeld: https://localhost:5001/Edit/1. Tag Helpers zorgen ervoor dat code aan de serverzijde kan deelnemen aan het maken en weergeven van HTML-elementen in Razor bestanden.

Het Index.cshtml bestand bevat markeringen voor het maken van een verwijderknop voor elke klantcontactpersoon:

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

De weergegeven HTML:

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

Wanneer de knop Verwijderen wordt weergegeven in HTML, bevat de bijbehorende formaction parameters voor:

  • De contactpersoon-id van de klant, opgegeven door het asp-route-id kenmerk.
  • De handler, opgegeven door het asp-page-handler kenmerk.

Wanneer de knop is geselecteerd, wordt een formulieraanvraag POST verzonden naar de server. Standaard wordt de naam van de handlermethode geselecteerd op basis van de waarde van de handler parameter volgens het schema OnPost[handler]Async.

Omdat de handler handler in dit voorbeeld delete wordt OnPostDeleteAsync gebruikt om de POST aanvraag te verwerken. Als de asp-page-handler waarde is ingesteld op een andere waarde, zoals remove, wordt een handlermethode met de naam OnPostRemoveAsync geselecteerd.

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

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

    return RedirectToPage();
}

De methode OnPostDeleteAsync:

  • Haalt id op uit de queryreeks.
  • Vraagt de database op naar het klantcontact met FindAsync.
  • Als de klantcontactpersoon wordt gevonden, wordt deze verwijderd en wordt de database bijgewerkt.
  • Roep RedirectToPage aan om naar de hoofdindex (/Index) te leiden.

Het bestand Edit.cshtml

@page "{id:int}"
@model RazorPagesContacts.Pages.Customers.EditModel

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

<h1>Edit</h1>

<h4>Customer</h4>
<hr />
<div class="row">
    <div class="col-md-4">
        <form method="post">
            <div asp-validation-summary="ModelOnly" class="text-danger"></div>
            <input type="hidden" asp-for="Customer!.Id" />
            <div class="form-group">
                <label asp-for="Customer!.Name" class="control-label"></label>
                <input asp-for="Customer!.Name" class="form-control" />
                <span asp-validation-for="Customer!.Name" class="text-danger"></span>
            </div>
            <div class="form-group">
                <input type="submit" value="Save" class="btn btn-primary" />
            </div>
        </form>
    </div>
</div>

<div>
    <a asp-page="./Index">Back to List</a>
</div>

@section Scripts {
    @{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}

De eerste regel bevat de @page "{id:int}" richtlijn. De routeringsbeperking "{id:int}" geeft aan dat de pagina aanvragen accepteert voor de pagina die routegegevens bevat int . Als een aanvraag naar de pagina geen routegegevens bevat die kunnen worden geconverteerd naar een int, retourneert de runtime een HTTP 404-fout (niet gevonden). Als u de id optioneel wilt maken, voegt u deze toe aan ? de routebeperking:

@page "{id:int?}"

Het bestand Edit.cshtml.cs:

public class EditModel : PageModel
{
    private readonly RazorPagesContacts.Data.CustomerDbContext _context;

    public EditModel(RazorPagesContacts.Data.CustomerDbContext context)
    {
        _context = context;
    }

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

    public async Task<IActionResult> OnGetAsync(int? id)
    {
        if (id == null)
        {
            return NotFound();
        }

        Customer = await _context.Customer.FirstOrDefaultAsync(m => m.Id == id);
        
        if (Customer == null)
        {
            return NotFound();
        }
        return Page();
    }

    // To protect from overposting attacks, enable the specific properties you want to bind to.
    // For more details, see https://aka.ms/RazorPagesCRUD.
    public async Task<IActionResult> OnPostAsync()
    {
        if (!ModelState.IsValid)
        {
            return Page();
        }

        if (Customer != null)
        {
            _context.Attach(Customer).State = EntityState.Modified;

            try
            {
                await _context.SaveChangesAsync();
            }
            catch (DbUpdateConcurrencyException)
            {
                if (!CustomerExists(Customer.Id))
                {
                    return NotFound();
                }
                else
                {
                    throw;
                }
            }
        }

        return RedirectToPage("./Index");
    }

    private bool CustomerExists(int id)
    {
        return _context.Customer.Any(e => e.Id == id);
    }
}

Validation

Validatieregels:

  • Worden declaratief opgegeven in de modelklasse.
  • In de app worden ze overal afgedwongen.

De System.ComponentModel.DataAnnotations naamruimte biedt een set ingebouwde validatiekenmerken die declaratief worden toegepast op een klasse of eigenschap. DataAnnotations bevat ook opmaakkenmerken zoals [DataType] die helpen bij het opmaken en bieden geen validatie.

Houd rekening met het Customer model:

using System.ComponentModel.DataAnnotations;

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

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

Gebruik het volgende Create.cshtml weergavebestand:

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

De voorgaande code:

  • Bevat jQuery- en jQuery-validatiescripts.

  • Maakt gebruik van de <div /> en <span />taghelpers om het volgende in te schakelen:

    • Validatie aan de clientzijde.
    • Validatiefout weergeven.
  • Hiermee wordt de volgende HTML gegenereerd:

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

Als u het formulier maken zonder een naamwaarde plaatst, wordt het foutbericht 'Het veld Naam is vereist' weergegeven op het formulier. Als JavaScript is ingeschakeld op de client, geeft de browser de fout weer zonder op de server te plaatsen.

Het [StringLength(10)] kenmerk genereert data-val-length-max="10" op de weergegeven HTML. data-val-length-max voorkomt dat browsers meer dan de opgegeven maximale lengte invoeren. Als een hulpprogramma zoals Fiddler wordt gebruikt om het bericht te bewerken en opnieuw af te spelen:

  • Met een naam die langer is dan 10 tekens.
  • Het foutbericht 'Het veld Naam moet een tekenreeks met een maximale lengte van 10 zijn.' wordt geretourneerd.

Houd rekening met het volgende Movie model:

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

De validatiekenmerken geven gedrag op voor het afdwingen van de modeleigenschappen waarop ze worden toegepast:

  • De Required en MinimumLength kenmerken geven aan dat een eigenschap een waarde moet hebben, maar niets voorkomt dat een gebruiker witruimte invoert om aan deze validatie te voldoen.

  • Het kenmerk RegularExpression wordt gebruikt om te beperken welke tekens kunnen worden ingevoerd. In de voorgaande code, "Genre":

    • Mag alleen letters gebruiken.
    • De eerste letter moet een hoofdletter zijn. Witruimte, getallen en speciale tekens zijn niet toegestaan.
  • De RegularExpression "Beoordeling":

    • Vereist dat het eerste teken een hoofdletter is.
    • Hiermee worden speciale tekens en nummers toegestaan in achtereenvolgende spaties. "PG-13" is geldig voor een beoordeling, maar is niet geschikt voor een genre.
  • Het Range kenmerk beperkt een waarde tot binnen een opgegeven bereik.

  • Met StringLength het kenmerk wordt de maximale lengte van een tekenreekseigenschap ingesteld en optioneel de minimale lengte.

  • Waardetypen (zoals decimal, int, float, ) DateTimezijn inherent vereist en hebben het [Required] kenmerk niet nodig.

De aanmaakpagina voor het Movie model vertoont fouten met ongeldige waarden.

filmweergaveformulier met meerdere jQuery-validatiefouten aan de clientkant

Voor meer informatie, zie:

CSS-isolatie

Isoleer CSS-stijlen voor afzonderlijke pagina's, weergaven en onderdelen om het aantal te verminderen of te voorkomen:

  • Afhankelijkheden van globale stijlen die lastig kunnen worden onderhouden.
  • Stijlconflicten in geneste inhoud.

Als u een CSS-bereikbestand voor een pagina of weergave wilt toevoegen, plaatst u de CSS-stijlen in een secundair .cshtml.css bestand dat overeenkomt met de naam van het .cshtml bestand. In het volgende voorbeeld bevat een Index.cshtml.css bestand CSS-stijlen die alleen worden toegepast op de Index.cshtml pagina of weergave.

Pages/Index.cshtml.css (Razor Pagina's) of Views/Index.cshtml.css (MVC):

h1 {
    color: red;
}

CSS-isolatie vindt plaats tijdens de build. Het framework herschrijft CSS-selectors zodat deze overeenkomen met de opmaak die wordt weergegeven door de pagina's of weergaven van de app. De herschreven CSS-stijlen worden gebundeld en geproduceerd als een statische asset, {APP ASSEMBLY}.styles.css. De tijdelijke aanduiding {APP ASSEMBLY} is de assemblynaam van het project. Een koppeling naar de gebundelde CSS-stijlen wordt in de indeling van de app geplaatst.

Voeg in de <head> inhoud van de app Pages/Shared/_Layout.cshtml (Razor Pagina's) of Views/Shared/_Layout.cshtml (MVC) de koppeling naar de gebundelde CSS-stijlen toe of bevestig de aanwezigheid van deze.

<link rel="stylesheet" href="~/{APP ASSEMBLY}.styles.css" />

In het volgende voorbeeld is WebApp de assemblynaam van de app:

<link rel="stylesheet" href="WebApp.styles.css" />

De stijlen die zijn gedefinieerd in een CSS-bereikbestand, worden alleen toegepast op de weergegeven uitvoer van het overeenkomende bestand. In het voorgaande voorbeeld conflicteren eventuele h1 CSS-declaraties die elders in de app zijn gedefinieerd, niet met de kopstijl van de Indexapp. CSS-stijlregels voor cascadering en overerving blijven van kracht voor gescoped CSS-bestanden. Stijlen die bijvoorbeeld rechtstreeks worden toegepast op een <h1> element in het Index.cshtml bestand, overschrijven de stijlen van het CSS-bereik in Index.cshtml.css.

Note

Om isolatie van CSS-stijlen te garanderen wanneer bundeling plaatsvindt, wordt het importeren van CSS in Razor codeblokken niet ondersteund.

CSS-isolatie is alleen van toepassing op HTML-elementen. CSS-isolatie wordt niet ondersteund voor Tag Helpers.

In het gebundelde CSS-bestand wordt elke pagina, weergave of Razor component gekoppeld aan een scope-identificator in het formaat b-{STRING}, waarbij de {STRING} tijdelijke aanduiding een tekenreeks van tien tekens is die door het framework wordt gegenereerd. In het volgende voorbeeld ziet u de stijl voor het voorgaande <h1> element op de Index pagina van een Razor pagina-app:

/* /Pages/Index.cshtml.rz.scp.css */
h1[b-3xxtam6d07] {
    color: red;
}

Op de Index pagina waarop de CSS-stijl wordt toegepast op basis van het gebundelde bestand, wordt de scope-id toegevoegd als een HTML-kenmerk:

<h1 b-3xxtam6d07>

De id is uniek voor een app. Tijdens de build wordt een projectbundel gemaakt met de conventie {STATIC WEB ASSETS BASE PATH}/Project.lib.scp.css, waarbij de plaatsaanduiding {STATIC WEB ASSETS BASE PATH} het basispad voor statische webactiva is.

Als andere projecten worden gebruikt, zoals NuGet-pakketten of Razor klassebibliotheken, wordt het gebundelde bestand:

  • Verwijst naar de stijlen met css-importbewerkingen.
  • Wordt niet gepubliceerd als een statische webasset van de app die de stijlen gebruikt.

Ondersteuning voor CSS-preprocessor

CSS-preprocessors zijn handig voor het verbeteren van CSS-ontwikkeling door gebruik te maken van functies zoals variabelen, nesten, modules, mixins en overname. Hoewel CSS-isolatie geen systeemeigen ondersteuning biedt voor CSS-preprocessors, zoals Sass of Less, is het integreren van CSS-preprocessors naadloos zolang preprocessorcompilatie plaatsvindt voordat het framework de CSS-selectors herschrijft tijdens het buildproces. Met Visual Studio configureert u bijvoorbeeld bestaande preprocessorcompilatie als een before build-taak in de Visual Studio Task Runner Explorer.

Veel NuGet-pakketten van derden, zoals AspNetCore.SassCompiler, kunnen SASS-/SCSS-bestanden compileren aan het begin van het buildproces voordat CSS-isolatie plaatsvindt en er is geen aanvullende configuratie vereist.

CSS-isolatieconfiguratie

CSS-isolatie maakt configuratie mogelijk voor sommige geavanceerde scenario's, zoals wanneer er afhankelijkheden zijn van bestaande hulpprogramma's of werkstromen.

Indeling van bereik-ID aanpassen

In deze sectie is de {Pages|Views} tijdelijke aanduiding ofwel Pages voor Razor Pagina-apps ofwel Views voor MVC-apps.

Scope-identificaties gebruiken standaard de indeling b-{STRING}, waarbij de {STRING}-tijdelijke aanduiding een tekenreeks van tien tekens is die door het framework wordt gegenereerd. Als u de indeling van de scope-id wilt aanpassen, werkt u het projectbestand bij naar een gewenst patroon:

<ItemGroup>
  <None Update="{Pages|Views}/Index.cshtml.css" CssScope="custom-scope-identifier" />
</ItemGroup>

In het voorgaande voorbeeld verandert de gegenereerde CSS voor Index.cshtml.css de scope-identificatie van b-{STRING} naar custom-scope-identifier.

Gebruik scope-identificatoren om overerving te bereiken met gescopeerde CSS-bestanden. In het volgende voorbeeld van een projectbestand bevat een BaseView.cshtml.css bestand algemene stijlen in verschillende weergaven. Een DerivedView.cshtml.css bestand neemt deze stijlen over.

<ItemGroup>
  <None Update="{Pages|Views}/BaseView.cshtml.css" CssScope="custom-scope-identifier" />
  <None Update="{Pages|Views}/DerivedView.cshtml.css" CssScope="custom-scope-identifier" />
</ItemGroup>

Gebruik de wildcard (*) operator om scope-identificators te delen tussen meerdere bestanden:

<ItemGroup>
  <None Update="{Pages|Views}/*.cshtml.css" CssScope="custom-scope-identifier" />
</ItemGroup>

Basispad voor statische webassets wijzigen

Het CSS-bereikbestand wordt gegenereerd in de hoofdmap van de app. Gebruik de StaticWebAssetBasePath eigenschap in het projectbestand om het standaardpad te wijzigen. In het volgende voorbeeld wordt het scoped CSS-bestand en de rest van de assets van de app op het _content pad weergegeven:

<PropertyGroup>
  <StaticWebAssetBasePath>_content/$(PackageId)</StaticWebAssetBasePath>
</PropertyGroup>

Automatische bundeling uitschakelen

Als u zich wilt afmelden voor de wijze waarop framework scoped bestanden tijdens runtime publiceert en laadt, gebruikt u de DisableScopedCssBundling eigenschap. Wanneer u deze eigenschap gebruikt, zijn andere hulpprogramma's of processen verantwoordelijk voor het nemen van de geïsoleerde CSS-bestanden uit de obj map en het publiceren en laden ervan tijdens runtime:

<PropertyGroup>
  <DisableScopedCssBundling>true</DisableScopedCssBundling>
</PropertyGroup>

Razor ondersteuning voor klassebibliotheek (RCL)

Wanneer een Razor klassebibliotheek (RCL) geïsoleerde stijlen biedt, verwijst het kenmerk van <link> de href tag naar {STATIC WEB ASSET BASE PATH}/{PACKAGE ID}.bundle.scp.css, waar de tijdelijke aanduidingen zich bevinden:

  • {STATIC WEB ASSET BASE PATH}: het basispad van de statische webasset.
  • {PACKAGE ID}: de pakket-id van de bibliotheek. De pakket-id wordt standaard ingesteld op de assemblynaam van het project als de pakket-id niet is opgegeven in het projectbestand.

In het volgende voorbeeld:

  • Het basispad van de statische webasset is _content/ClassLib.
  • De assemblynaam van de klassenbibliotheek is ClassLib.

Pages/Shared/_Layout.cshtml (Razor Pagina's) of Views/Shared/_Layout.cshtml (MVC):

<link href="_content/ClassLib/ClassLib.bundle.scp.css" rel="stylesheet">

Zie de volgende artikelen voor meer informatie over RCL's:

Zie Blazor voor meer informatie over Blazor CSS-isolatie.

HEAD-aanvragen verwerken door een OnGet-handler als back-up te gebruiken

HEAD aanvragen maken het ophalen van de headers voor een specifieke resource mogelijk. In tegenstelling tot GET aanvragen retourneren HEAD aanvragen geen antwoordtekst.

Normaal gesproken wordt een OnHead handler gemaakt en aangeroepen voor HEAD aanvragen:

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

Razor Pagina's vallen terug op het aanroepen van de OnGet handler als er geen OnHead handler is gedefinieerd.

XSRF/CSRF en Razor Pagina's

Razor Pagina's worden beveiligd door Antiforgery-validatie. De FormTagHelper- voegt antiforgery-tokens toe aan HTML-formulierelementen.

Indelingen, gedeeltelijke elementen, sjablonen en Tag Helpers gebruiken met Razor Pagina's

Pagina's werken met alle mogelijkheden van de Razor weergave-engine. Indelingen, gedeeltelijke elementen, sjablonen, Tag Helpers _ViewStart.cshtmlen _ViewImports.cshtml werken op dezelfde manier als voor conventionele Razor weergaven.

Laten we deze pagina opsplitsen door gebruik te maken van een aantal van deze mogelijkheden.

Voeg een indelingspagina toe aan 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>

De indeling:

  • Hiermee bepaalt u de indeling van elke pagina (tenzij de pagina niet kiest voor indeling).
  • Hiermee importeert u HTML-structuren zoals JavaScript en opmaakmodellen.
  • De inhoud van de Razor pagina wordt weergegeven waar @RenderBody() wordt aangeroepen.

Zie de indelingspagina voor meer informatie.

De eigenschap Indeling is ingesteld in Pages/_ViewStart.cshtml:

@{
    Layout = "_Layout";
}

De indeling bevindt zich in de map Pagina's/Gedeeld . Pagina's zoeken naar andere weergaven (indelingen, sjablonen, gedeeltelijke elementen) hiërarchisch, beginnend in dezelfde map als de huidige pagina. Een indeling in de map Pagina's/Gedeeld kan worden gebruikt vanaf elke Razor pagina onder de map Pagina's .

Het indelingsbestand moet worden weergegeven in de map Pagina's/Gedeeld .

U wordt aangeraden het indelingsbestand niet in de map Weergaven/Gedeeld te plaatsen. Weergaven/Gedeeld is een MVC-weergavepatroon. Razor Pagina's behoren te steunen op mapstructuur, niet op padconventies.

De zoekfunctie van een Razor pagina bevat de map Pagina's . De indelingen, sjablonen en gedeeltelijke elementen die worden gebruikt met MVC-controllers en conventionele Razor weergaven werken gewoon.

Pages/_ViewImports.cshtml Een bestand toevoegen:

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

@namespace wordt later in de zelfstudie uitgelegd. De @addTagHelper richtlijn brengt de ingebouwde Tag Helpers naar alle pagina's in de map Pagina's .

De @namespace richtlijn die is ingesteld op een pagina:

@page
@namespace RazorPagesIntro.Pages.Customers

@model NameSpaceModel

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

De @namespace instructie stelt de naamruimte voor de pagina in. De @model instructie hoeft de naamruimte niet op te nemen.

Wanneer de @namespace instructie is opgenomen in _ViewImports.cshtml, levert de opgegeven naamruimte het voorvoegsel voor de gegenereerde naamruimte in de pagina die de @namespace instructie importeert. De rest van de gegenereerde naamruimte (het achtervoegselgedeelte) is het relatieve pad tussen de map met _ViewImports.cshtml en de map die de pagina bevat.

De PageModel klasse Pages/Customers/Edit.cshtml.cs stelt bijvoorbeeld expliciet de naamruimte in:

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

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

        // Code removed for brevity.

Het Pages/_ViewImports.cshtml bestand stelt de volgende naamruimte in:

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

De gegenereerde naamruimte voor de Pages/Customers/Edit.cshtmlRazor pagina is hetzelfde als de PageModel klasse.

@namespace werkt ook met conventionele Razor weergaven.

Bekijk het Pages/Customers/Create.cshtml weergavebestand:

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

Het bijgewerkte Pages/Customers/Create.cshtml weergavebestand met _ViewImports.cshtml en het voorgaande indelingsbestand:

@page
@model CreateModel

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

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

In de voorgaande code zijn de _ViewImports.cshtml naamruimte en Tag Helpers geïmporteerd. Het indelingsbestand heeft de JavaScript-bestanden geïmporteerd.

Het Razor startersproject Pages bevat het Pages/_ValidationScriptsPartial.cshtml, waarmee validatie aan de clientzijde wordt gekoppeld.

Zie Gedeeltelijke weergaven in ASP.NET Core voor meer informatie over gedeeltelijke weergaven.

URL-generatie voor pagina's

De Create pagina, die eerder wordt weergegeven, gebruikt RedirectToPage:

public class CreateModel : PageModel
{
    private readonly Data.CustomerDbContext _context;

    public CreateModel(Data.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();
        }

        if (Customer != null) _context.Customer.Add(Customer);
        await _context.SaveChangesAsync();

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

De app heeft de volgende bestands-/mapstructuur:

  • /Pages

    • Index.cshtml

    • Privacy.cshtml

    • /Customers

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

De Pages/Customers/Create.cshtml pagina's Pages/Customers/Edit.cshtml worden omgeleid naar Pages/Customers/Index.cshtml na succes. De tekenreeks ./Index is een relatieve paginanaam die wordt gebruikt voor toegang tot de voorgaande pagina. Deze wordt gebruikt om URL's naar de Pages/Customers/Index.cshtml pagina te genereren. Voorbeeld:

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

De absolute paginanaam /Index wordt gebruikt om URL's naar de Pages/Index.cshtml pagina te genereren. Voorbeeld:

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

De paginanaam is het pad naar de pagina vanuit de hoofddirectory /Pagina's, inclusief een voorloopteken / (bijvoorbeeld /Index). De voorgaande voorbeelden van het genereren van URL's bieden verbeterde opties en functionele mogelijkheden ten opzichte van het coderen van een URL. Het genereren van url's maakt gebruik van routering en kan parameters genereren en coderen op basis van hoe de route in het doelpad wordt gedefinieerd.

HET genereren van URL's voor pagina's ondersteunt relatieve namen. In de volgende tabel ziet u welke indexpagina is geselecteerd met behulp van verschillende RedirectToPage parameters in 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")en RedirectToPage("../Index") zijn relatieve namen. De RedirectToPage parameter wordt gecombineerd met het pad van de huidige pagina om de naam van de doelpagina te berekenen.

Relatieve naamkoppeling is handig bij het bouwen van sites met een complexe structuur. Wanneer relatieve namen worden gebruikt om een koppeling te maken tussen pagina's in een map:

  • Als u de naam van een map wijzigt, worden de relatieve koppelingen niet verbroken.
  • Koppelingen worden niet verbroken omdat ze de mapnaam niet bevatten.

Als u wilt omleiden naar een pagina in een ander gebied, geeft u het gebied op:

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

Zie Gebieden in ASP.NET Core en Razor Pagina's route en app-conventies in ASP.NET Core voor meer informatie.

ViewData-kenmerk

Gegevens kunnen worden doorgegeven aan een pagina met ViewDataAttribute. Eigenschappen met het [ViewData] kenmerk hebben hun waarden opgeslagen en geladen vanuit de ViewDataDictionary.

In het volgende voorbeeld AboutModel wordt het [ViewData] kenmerk toegepast op de Title eigenschap:

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

    public void OnGet()
    {
    }
}

Ga op de pagina Info naar de Title eigenschap als een modeleigenschap:

<h1>@Model.Title</h1>

In de indeling wordt de titel gelezen uit de ViewData-woordenlijst:

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

TempData

ASP.NET Core stelt de TempData bloot. Met deze eigenschap worden gegevens opgeslagen totdat deze worden gelezen. De Keep en Peek methoden kunnen worden gebruikt om de gegevens te onderzoeken zonder te verwijderen. TempData is handig voor omleiding, wanneer gegevens nodig zijn voor meer dan één aanvraag.

Met de volgende code wordt de waarde van Message ingesteld met behulp van 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");
    }
}

De volgende opmaakcode in het Pages/Customers/Index.cshtml-bestand geeft de waarde van Message weer met behulp van TempData.

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

Het Pages/Customers/Index.cshtml.cs paginamodel past het [TempData] kenmerk toe op de Message eigenschap.

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

Zie TempData voor meer informatie.

Meerdere handlers per pagina

Op de volgende pagina worden markeringen voor twee handlers gegenereerd met behulp van de asp-page-handler Tag Helper:

@page
@model CreateFATHModel

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

Het formulier in het vorige voorbeeld heeft twee verzendknoppen, die elk FormActionTagHelper gebruiken om naar een andere URL te verzenden. Het asp-page-handler kenmerk is een aanvulling op asp-page. asp-page-handler genereert URL's die worden verzonden naar elk van de handlermethoden die zijn gedefinieerd door een pagina. asp-page is niet opgegeven omdat het voorbeeld is gekoppeld aan de huidige pagina.

Het paginamodel:

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

In de voorgaande code worden benoemde handlermethoden gebruikt. Benoemde handlermethoden worden gemaakt door de tekst in de naam na On<HTTP Verb> en voor Async (indien aanwezig) te nemen. In het voorgaande voorbeeld zijn de paginamethoden OnPostJoinListAsync en OnPostJoinListUCAsync. Als OnPost en Async zijn verwijderd, zijn de handlernamen JoinList en JoinListUC.

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

Met behulp van de voorgaande code, is het URL-pad dat naar OnPostJoinListAsync zendt https://localhost:5001/Customers/CreateFATH?handler=JoinList. Het URL-pad dat naar OnPostJoinListUCAsync verzendt, is https://localhost:5001/Customers/CreateFATH?handler=JoinListUC.

Aangepaste routes

Gebruik de @page instructie om het volgende te doen:

  • Geef een aangepaste route naar een pagina op. De route naar de Over-pagina kan bijvoorbeeld worden ingesteld met /Some/Other/Path@page "/Some/Other/Path".
  • Segmenten toevoegen aan de standaardroute van een pagina. Een itemsegment kan bijvoorbeeld worden toegevoegd aan de standaardroute van een pagina met @page "item".
  • Parameters toevoegen aan de standaardroute van een pagina. Een id-parameter, idkan bijvoorbeeld vereist zijn voor een pagina met @page "{id}".

Een root-relatief pad dat aan het begin van het pad is aangewezen door een tilde (~) wordt ondersteund. @page "~/Some/Other/Path" is bijvoorbeeld hetzelfde als @page "/Some/Other/Path".

Als u niet tevreden bent over de querytekenreeks ?handler=JoinList in de URL, wijzigt u de route om de handlernaam in het padgedeelte van de URL te plaatsen. De route kan worden aangepast door een routesjabloon tussen dubbele aanhalingstekens na de @page instructie toe te voegen.

@page "{handler?}"
@model CreateRouteModel

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

Met behulp van de voorgaande code, is het URL-pad dat naar OnPostJoinListAsync zendt https://localhost:5001/Customers/CreateFATH/JoinList. Het URL-pad dat naar OnPostJoinListUCAsync verzendt, is https://localhost:5001/Customers/CreateFATH/JoinListUC.

Het ? volgende handler betekent dat de routeparameter optioneel is.

Samenvoeging van JavaScript-bestanden (JS)

Collocation van JavaScript-bestanden (JS) voor pagina's en weergaven is een handige manier om scripts in een app te organiseren.

JS Plaats bestanden met behulp van de volgende bestandsnaamextensieconventies:

  • Pagina's van de Razor Pagina-apps en weergaven van MVC-apps: .cshtml.js. Examples:
    • Pages/Index.cshtml.js voor de Index pagina van een Razor pagina-applicatie op Pages/Index.cshtml.
    • Views/Home/Index.cshtml.js voor de Index weergave van een MVC-app op Views/Home/Index.cshtml.

Collocated JS bestanden zijn openbaar toegankelijk met behulp van het pad naar het bestand in het project:

  • Pagina's en weergaven van een bestand met samengevoegde scripts in de app.

    {PATH}/{PAGE, VIEW, OR COMPONENT}.{EXTENSION}.js

    • De {PATH} tijdelijke aanduiding is het pad naar de pagina, weergave of onderdeel.
    • De {PAGE, VIEW, OR COMPONENT} tijdelijke aanduiding is de pagina, weergave of het onderdeel.
    • De {EXTENSION} tijdelijke aanduiding komt overeen met de bestandsextensie van de pagina, weergave of component, hetzij razor of cshtml.

    Razor Voorbeeld van pagina's:

    Een JS bestand voor de Index pagina is in de Pages map (Pages/Index.cshtml.js) naast de Index pagina (Pages/Index.cshtml) geplaatst. Op de Index pagina wordt naar het script verwezen op het pad in de Pages map:

    @section Scripts {
      <script src="~/Pages/Index.cshtml.js"></script>
    }
    

De standaardindeling Pages/Shared/_Layout.cshtml kan worden geconfigureerd voor het opnemen van collocated JS bestanden, waardoor elke pagina niet afzonderlijk hoeft te worden geconfigureerd:

<script asp-src-include="@(ViewContext.View.Path).js"></script>

De voorbeelddownload maakt gebruik van het voorgaande codefragment om collocated JS files in de standaardindeling op te nemen.

Wanneer de app wordt gepubliceerd, verplaatst het framework het script automatisch naar de webroot. In het voorgaande voorbeeld wordt het script verplaatst naar bin\Release\{TARGET FRAMEWORK MONIKER}\publish\wwwroot\Pages\Index.cshtml.js, waarbij de {TARGET FRAMEWORK MONIKER} tijdelijke aanduiding de Target Framework Moniker (TFM) is. Er is geen wijziging vereist voor de relatieve URL van het script op de Index pagina.

Wanneer de app wordt gepubliceerd, verplaatst het framework het script automatisch naar de webroot. In het voorgaande voorbeeld wordt het script verplaatst naar bin\Release\{TARGET FRAMEWORK MONIKER}\publish\wwwroot\Components\Pages\Index.razor.js, waarbij de {TARGET FRAMEWORK MONIKER} tijdelijke aanduiding de Target Framework Moniker (TFM) is. Er is geen wijziging vereist voor de relatieve URL van het script in het Index onderdeel.

  • Voor scripts die worden geleverd door een Razor klassebibliotheek (RCL):

    _content/{PACKAGE ID}/{PATH}/{PAGE, VIEW, OR COMPONENT}.{EXTENSION}.js

    • De tijdelijke aanduiding {PACKAGE ID} is de pakket-id van de RCL (of bibliotheeknaam voor een klassebibliotheek waarnaar wordt verwezen door de app).
    • De {PATH} tijdelijke aanduiding is het pad naar de pagina, weergave of onderdeel. Als een Razor component zich in de root van de RCL bevindt, wordt het padsegment niet opgenomen.
    • De {PAGE, VIEW, OR COMPONENT} tijdelijke aanduiding is de pagina, weergave of het onderdeel.
    • De {EXTENSION} tijdelijke aanduiding komt overeen met de extensie van pagina, weergave of onderdeel, of razorcshtml .

Geavanceerde configuratie en instellingen

De configuratie en instellingen in de volgende secties zijn niet vereist voor de meeste apps.

Als u geavanceerde opties wilt configureren, gebruikt u de AddRazorPages overbelasting die het volgende configureert RazorPagesOptions:

using Microsoft.EntityFrameworkCore;
using RazorPagesContacts.Data;
var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages(options =>
{
    options.RootDirectory = "/MyPages";
    options.Conventions.AuthorizeFolder("/MyPages/Admin");
});

builder.Services.AddDbContext<CustomerDbContext>(options =>
    options.UseInMemoryDatabase("name"));

var app = builder.Build();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

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

app.UseRouting();

app.UseAuthorization();

app.MapRazorPages();

app.Run();

Gebruik de RazorPagesOptions opdracht om de hoofdmap voor pagina's in te stellen of toepassingsmodelconventies toe te voegen voor pagina's. Zie Razor pagina's autorisatieconventies voor meer informatie over conventies.

Zie Razor compilatie weergeven om weergaven vooraf te compileren.

Opgeven dat Razor pagina's zich in de hoofdmap van de inhoud bevinden

Pagina's zijn standaard Razor geroot in de map /Pages . Voeg WithRazorPagesAtContentRoot toe om op te geven dat uw Razor pagina's zich in de hoofdmap van de inhoud (ContentRootPath) van de app bevinden:

using Microsoft.EntityFrameworkCore;
using RazorPagesContacts.Data;
var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages(options =>
{
    options.Conventions.AuthorizeFolder("/MyPages/Admin");
})
  .WithRazorPagesAtContentRoot();

builder.Services.AddDbContext<CustomerDbContext>(options =>
    options.UseInMemoryDatabase("name"));

var app = builder.Build();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

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

app.UseRouting();

app.UseAuthorization();

app.MapRazorPages();

app.Run();

Opgeven dat Razor Pagina's zich in een aangepaste hoofdmap bevinden

Toevoegen WithRazorPagesRoot om op te geven dat Razor Pagina's zich in een aangepaste hoofdmap in de app bevinden (geef een relatief pad op):

using Microsoft.EntityFrameworkCore;
using RazorPagesContacts.Data;
var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages(options =>
{
    options.Conventions.AuthorizeFolder("/MyPages/Admin");
})
  .WithRazorPagesRoot("/path/to/razor/pages");

builder.Services.AddDbContext<CustomerDbContext>(options =>
    options.UseInMemoryDatabase("name"));

var app = builder.Build();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

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

app.UseRouting();

app.UseAuthorization();

app.MapRazorPages();

app.Run();

Aanvullende bronnen

Een Razor Pagina-project maken

Zie Aan de slag met Razor Pages voor gedetailleerde instructies over het maken van een Razor Pages-project.

Razor pagina's

Razor Pagina's zijn ingeschakeld in 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();
        });
    }
}

Overweeg een basispagina:

@page

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

De voorgaande code ziet er veel uit als een Razor weergavebestand dat wordt gebruikt in een ASP.NET Core-app met controllers en weergaven. Wat het anders maakt, is de @page richtlijn. @page maakt het bestand in een MVC-actie, wat betekent dat het aanvragen rechtstreeks verwerkt, zonder een controller te doorlopen. @page moet de eerste Razor instructie op een pagina zijn. @page beïnvloedt het gedrag van andere Razor constructies. Razor Bestandsnamen van pagina's hebben een .cshtml achtervoegsel.

Een vergelijkbare pagina, met behulp van een PageModel klasse, wordt weergegeven in de volgende twee bestanden. Het bestand Pages/Index2.cshtml:

@page
@using RazorPagesIntro.Pages
@model Index2Model

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

Het Pages/Index2.cshtml.cs paginamodel:

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

Volgens de conventie heeft het PageModel klassebestand dezelfde naam als het Razor paginabestand waaraan .cs is toegevoegd. Bijvoorbeeld, de vorige Razor pagina is Pages/Index2.cshtml. Het bestand dat de PageModel klasse bevat, is genaamd Pages/Index2.cshtml.cs.

De koppelingen van URL-paden naar pagina's worden bepaald door de locatie van de pagina in het bestandssysteem. In de volgende tabel ziet u een Razor paginapad en de overeenkomende URL:

Bestandsnaam en pad overeenkomende URL
/Pages/Index.cshtml / of /Index
/Pages/Contact.cshtml /Contact
/Pages/Store/Contact.cshtml /Store/Contact
/Pages/Store/Index.cshtml /Store of /Store/Index

Notes:

  • De runtime zoekt standaard naar Razor Pages-bestanden in de map Pagina's .
  • Index is de standaardpagina wanneer een URL geen pagina bevat.

Een basisformulier schrijven

Razor Pagina's zijn ontworpen om algemene patronen die worden gebruikt met webbrowsers eenvoudig te implementeren bij het bouwen van een app. Modelbinding, Tag Helpers en HTML-helpers werken allemaal met de eigenschappen die zijn gedefinieerd in een Razor paginaklasse. Denk aan een pagina die een eenvoudig formulier 'contact met ons' implementeert voor het Contact model:

Voor de voorbeelden in dit document wordt het DbContext geïnitialiseerd in het Startup.cs-bestand .

Voor de in-geheugendatabase is het Microsoft.EntityFrameworkCore.InMemory NuGet-pakket vereist.

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

Het gegevensmodel:

using System.ComponentModel.DataAnnotations;

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

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

De db-context:

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

Het Pages/Create.cshtml weergavebestand:

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

Het Pages/Create.cshtml.cs paginamodel:

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

De klasse wordt standaard PageModel aangeroepen <PageName>Model en bevindt zich in dezelfde naamruimte als de pagina.

Met PageModel de klasse kunt u de logica van een pagina scheiden van de presentatie. Hiermee worden pagina-handlers gedefinieerd voor aanvragen die naar de pagina worden verzonden en de gegevens die worden gebruikt om de pagina weer te geven. Deze scheiding maakt het volgende mogelijk:

De pagina heeft een OnPostAsynchandlermethode, die wordt uitgevoerd op POST aanvragen (wanneer een gebruiker het formulier plaatst). Handlermethoden voor elk HTTP-werkwoord kunnen worden toegevoegd. De meest voorkomende handlers zijn:

  • OnGet om de status te initialiseren die nodig is voor de pagina. In de voorgaande code geeft de OnGet methode de CreateModel.cshtmlRazor pagina weer.
  • OnPost voor het afhandelen van formulierinzendingen.

Het Async naamachtervoegsel is optioneel, maar wordt vaak gebruikt door conventies voor asynchrone functies. De voorgaande code is typisch voor Razor Pagina's.

Als u bekend bent met ASP.NET apps met behulp van controllers en weergaven:

  • De OnPostAsync code in het voorgaande voorbeeld lijkt op typische controllercode.
  • De meeste MVC-primitieven, zoals modelbinding, validatie en actieresultaten, werken hetzelfde met controllers en Razor pagina's.

De vorige OnPostAsync-methode:

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

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

    return RedirectToPage("./Index");
}

De basisstroom van OnPostAsync:

Controleer op validatiefouten.

  • Als er geen fouten zijn, slaat u de gegevens op en stuurt u deze om.
  • Als er fouten zijn, kunt u de pagina opnieuw weergeven met validatieberichten. In veel gevallen worden validatiefouten op de client gedetecteerd en nooit verzonden naar de server.

Het Pages/Create.cshtml weergavebestand:

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

De HTML die door Pages/Create.cshtml wordt weergegeven:

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

In de vorige code plaatst u het formulier:

  • Met geldige gegevens:

    • De OnPostAsync handlermethode roept de RedirectToPage helpermethode aan. RedirectToPage retourneert een exemplaar van RedirectToPageResult. RedirectToPage:

      • Is een actieresultaat.
      • Is vergelijkbaar met RedirectToAction of RedirectToRoute (gebruikt in controllers en weergaven).
      • Is aangepast voor pagina's. In het voorgaande voorbeeld wordt deze omgeleid naar de hoofdindexpagina (/Index). RedirectToPage wordt beschreven in de sectie Url-generatie voor pagina's .
  • Bij validatiefouten die worden doorgegeven aan de server:

    • De OnPostAsync handlermethode roept de Page helpermethode aan. Page retourneert een exemplaar van PageResult. Teruggeven van Page is vergelijkbaar met de manier waarop acties in controllers View teruggeven. PageResult is het standaard retourtype voor een handlermethode. Een handlermethode die void retourneert rendert de pagina.
    • In het voorgaande voorbeeld resulteert het indienen van het formulier zonder waarde in ModelState.IsValid die onwaar retourneert. In dit voorbeeld worden er geen validatiefouten weergegeven op de client. De afhandeling van validatiefouten wordt verderop in dit document behandeld.
    public async Task<IActionResult> OnPostAsync()
    {
        if (!ModelState.IsValid)
        {
            return Page();
        }
    
        _context.Customers.Add(Customer);
        await _context.SaveChangesAsync();
    
        return RedirectToPage("./Index");
    }
    
  • Met validatiefouten gedetecteerd door validatie aan de clientzijde:

    • Gegevens worden niet op de server geplaatst.
    • Validatie aan de clientzijde wordt verderop in dit document uitgelegd.

De Customer eigenschap maakt gebruik van het [BindProperty] kenmerk om zich aan te melden voor modelbinding.

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] mag niet worden gebruikt voor modellen met eigenschappen die niet door de client mogen worden gewijzigd. Zie Overposting voor meer informatie.

Razor Standaard binden pagina's alleen eigenschappen aan elementen die geen werkwoord zijnGET. Binding met eigenschappen verwijdert de noodzaak om code te schrijven om HTTP-gegevens te converteren naar het modeltype. Binding vermindert de code door dezelfde eigenschap te gebruiken om formuliervelden weer te geven (<input asp-for="Customer.Name">) en de invoer te accepteren.

Warning

Om veiligheidsredenen moet u kiezen om GET gegevens te koppelen aan de eigenschappen van het paginamodel. Controleer gebruikersinvoer voordat u deze toe te wijst aan eigenschappen. Het kiezen voor GET binding is nuttig bij het aanpakken van scenario's die afhankelijk zijn van querystring- of routewaarden.

Als u een eigenschap op GET-aanvragen wilt binden, stelt u de [BindProperty]-eigenschap van het SupportsGet-kenmerk in op true.

[BindProperty(SupportsGet = true)]

Zie ASP.NET Core Community Standup: Bind on GET-discussie (YouTube) voor meer informatie.

Pages/Create.cshtml Het weergavebestand controleren:

@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>
  • In de voorgaande code koppelt de helper <input asp-for="Customer.Name" /> het HTML-element <input> aan de Customer.Name modelexpressie.
  • @addTagHelper Tag Helpers beschikbaar maken.

De startpagina

Index.cshtml is de startpagina:

@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>
                        <!-- <snippet_Edit> -->
                        <a asp-page="./Edit" asp-route-id="@contact.Id">Edit</a> |
                        <!-- </snippet_Edit> -->
                        <!-- <snippet_Delete> -->
                        <button type="submit" asp-page-handler="delete" asp-route-id="@contact.Id">delete</button>
                        <!-- </snippet_Delete> -->
                    </td>
                </tr>
            }
        </tbody>
    </table>
    <a asp-page="Create">Create New</a>
</form>

De bijbehorende PageModel klasse (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();
    }
}

Het Index.cshtml bestand bevat de volgende markeringen:

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

De <a /a>Anchor Tag Helper heeft het asp-route-{value} kenmerk gebruikt om een koppeling naar de pagina Bewerken te genereren. De koppeling bevat routegegevens met de contactpersoon-id. Bijvoorbeeld: https://localhost:5001/Edit/1. Tag Helpers zorgen ervoor dat code aan de serverzijde kan deelnemen aan het maken en weergeven van HTML-elementen in Razor bestanden.

Het Index.cshtml bestand bevat markeringen voor het maken van een verwijderknop voor elke klantcontactpersoon:

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

De weergegeven HTML:

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

Wanneer de knop Verwijderen wordt weergegeven in HTML, bevat de bijbehorende formaction parameters voor:

  • De contactpersoon-id van de klant, opgegeven door het asp-route-id kenmerk.
  • De handler, opgegeven door het asp-page-handler kenmerk.

Wanneer de knop is geselecteerd, wordt een formulieraanvraag POST verzonden naar de server. Standaard wordt de naam van de handlermethode geselecteerd op basis van de waarde van de handler parameter volgens het schema OnPost[handler]Async.

Omdat de handler handler in dit voorbeeld delete wordt OnPostDeleteAsync gebruikt om de POST aanvraag te verwerken. Als de asp-page-handler waarde is ingesteld op een andere waarde, zoals remove, wordt een handlermethode met de naam OnPostRemoveAsync geselecteerd.

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

De methode OnPostDeleteAsync:

  • Haalt id op uit de queryreeks.
  • Vraagt de database op naar het klantcontact met FindAsync.
  • Als de klantcontactpersoon wordt gevonden, wordt deze verwijderd en wordt de database bijgewerkt.
  • Roep RedirectToPage aan om naar de hoofdindex (/Index) te leiden.

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

De eerste regel bevat de @page "{id:int}" richtlijn. De routeringsbeperking "{id:int}" geeft aan dat de pagina aanvragen accepteert voor de pagina die routegegevens bevat int . Als een aanvraag naar de pagina geen routegegevens bevat die kunnen worden geconverteerd naar een int, retourneert de runtime een HTTP 404-fout (niet gevonden). Als u de id optioneel wilt maken, voegt u deze toe aan ? de routebeperking:

@page "{id:int?}"

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

Validatieregels:

  • Worden declaratief opgegeven in de modelklasse.
  • In de app worden ze overal afgedwongen.

De System.ComponentModel.DataAnnotations naamruimte biedt een set ingebouwde validatiekenmerken die declaratief worden toegepast op een klasse of eigenschap. DataAnnotations bevat ook opmaakkenmerken zoals [DataType] die helpen bij het opmaken en bieden geen validatie.

Houd rekening met het Customer model:

using System.ComponentModel.DataAnnotations;

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

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

Gebruik het volgende Create.cshtml weergavebestand:

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

De voorgaande code:

  • Bevat jQuery- en jQuery-validatiescripts.

  • Maakt gebruik van de <div /> en <span />taghelpers om het volgende in te schakelen:

    • Validatie aan de clientzijde.
    • Validatiefout weergeven.
  • Hiermee wordt de volgende HTML gegenereerd:

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

Als u het formulier maken zonder een naamwaarde plaatst, wordt het foutbericht 'Het veld Naam is vereist' weergegeven op het formulier. Als JavaScript is ingeschakeld op de client, geeft de browser de fout weer zonder op de server te plaatsen.

Het [StringLength(10)] kenmerk genereert data-val-length-max="10" op de weergegeven HTML. data-val-length-max voorkomt dat browsers meer dan de opgegeven maximale lengte invoeren. Als een hulpprogramma zoals Fiddler wordt gebruikt om het bericht te bewerken en opnieuw af te spelen:

  • Met een naam die langer is dan 10 tekens.
  • Het foutbericht 'Het veld Naam moet een tekenreeks met een maximale lengte van 10 zijn.' wordt geretourneerd.

Houd rekening met het volgende Movie model:

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

De validatiekenmerken geven gedrag op voor het afdwingen van de modeleigenschappen waarop ze worden toegepast:

  • De Required en MinimumLength kenmerken geven aan dat een eigenschap een waarde moet hebben, maar niets voorkomt dat een gebruiker witruimte invoert om aan deze validatie te voldoen.

  • Het kenmerk RegularExpression wordt gebruikt om te beperken welke tekens kunnen worden ingevoerd. In de voorgaande code, "Genre":

    • Mag alleen letters gebruiken.
    • De eerste letter moet een hoofdletter zijn. Witruimte, getallen en speciale tekens zijn niet toegestaan.
  • De RegularExpression "Beoordeling":

    • Vereist dat het eerste teken een hoofdletter is.
    • Hiermee worden speciale tekens en nummers toegestaan in achtereenvolgende spaties. "PG-13" is geldig voor een beoordeling, maar is niet geschikt voor een genre.
  • Het Range kenmerk beperkt een waarde tot binnen een opgegeven bereik.

  • Met StringLength het kenmerk wordt de maximale lengte van een tekenreekseigenschap ingesteld en optioneel de minimale lengte.

  • Waardetypen (zoals decimal, int, float, ) DateTimezijn inherent vereist en hebben het [Required] kenmerk niet nodig.

De aanmaakpagina voor het Movie model vertoont fouten met ongeldige waarden.

filmweergaveformulier met meerdere jQuery-validatiefouten aan de clientkant

Voor meer informatie, zie:

HEAD-aanvragen verwerken door een OnGet-handler als back-up te gebruiken

HEAD aanvragen maken het ophalen van de headers voor een specifieke resource mogelijk. In tegenstelling tot GET aanvragen retourneren HEAD aanvragen geen antwoordtekst.

Normaal gesproken wordt een OnHead handler gemaakt en aangeroepen voor HEAD aanvragen:

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

Razor Pagina's vallen terug op het aanroepen van de OnGet handler als er geen OnHead handler is gedefinieerd.

XSRF/CSRF en Razor Pagina's

Razor Pagina's worden beveiligd door Antiforgery-validatie. De FormTagHelper- voegt antiforgery-tokens toe aan HTML-formulierelementen.

Indelingen, gedeeltelijke elementen, sjablonen en Tag Helpers gebruiken met Razor Pagina's

Pagina's werken met alle mogelijkheden van de Razor weergave-engine. Indelingen, gedeeltelijke elementen, sjablonen, Tag Helpers _ViewStart.cshtmlen _ViewImports.cshtml werken op dezelfde manier als voor conventionele Razor weergaven.

Laten we deze pagina opsplitsen door gebruik te maken van een aantal van deze mogelijkheden.

Voeg een indelingspagina toe aan 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>

De indeling:

  • Hiermee bepaalt u de indeling van elke pagina (tenzij de pagina niet kiest voor indeling).
  • Hiermee importeert u HTML-structuren zoals JavaScript en opmaakmodellen.
  • De inhoud van de Razor pagina wordt weergegeven waar @RenderBody() wordt aangeroepen.

Zie de indelingspagina voor meer informatie.

De eigenschap Indeling is ingesteld in Pages/_ViewStart.cshtml:

@{
    Layout = "_Layout";
}

De indeling bevindt zich in de map Pagina's/Gedeeld . Pagina's zoeken naar andere weergaven (indelingen, sjablonen, gedeeltelijke elementen) hiërarchisch, beginnend in dezelfde map als de huidige pagina. Een indeling in de map Pagina's/Gedeeld kan worden gebruikt vanaf elke Razor pagina onder de map Pagina's .

Het indelingsbestand moet worden weergegeven in de map Pagina's/Gedeeld .

U wordt aangeraden het indelingsbestand niet in de map Weergaven/Gedeeld te plaatsen. Weergaven/Gedeeld is een MVC-weergavepatroon. Razor Pagina's behoren te steunen op mapstructuur, niet op padconventies.

De zoekfunctie van een Razor pagina bevat de map Pagina's . De indelingen, sjablonen en gedeeltelijke elementen die worden gebruikt met MVC-controllers en conventionele Razor weergaven werken gewoon.

Pages/_ViewImports.cshtml Een bestand toevoegen:

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

@namespace wordt later in de zelfstudie uitgelegd. De @addTagHelper richtlijn brengt de ingebouwde Tag Helpers naar alle pagina's in de map Pagina's .

De @namespace richtlijn die is ingesteld op een pagina:

@page
@namespace RazorPagesIntro.Pages.Customers

@model NameSpaceModel

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

De @namespace instructie stelt de naamruimte voor de pagina in. De @model instructie hoeft de naamruimte niet op te nemen.

Wanneer de @namespace instructie is opgenomen in _ViewImports.cshtml, levert de opgegeven naamruimte het voorvoegsel voor de gegenereerde naamruimte in de pagina die de @namespace instructie importeert. De rest van de gegenereerde naamruimte (het achtervoegselgedeelte) is het relatieve pad tussen de map met _ViewImports.cshtml en de map die de pagina bevat.

De PageModel klasse Pages/Customers/Edit.cshtml.cs stelt bijvoorbeeld expliciet de naamruimte in:

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

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

        // Code removed for brevity.

Het Pages/_ViewImports.cshtml bestand stelt de volgende naamruimte in:

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

De gegenereerde naamruimte voor de Pages/Customers/Edit.cshtmlRazor pagina is hetzelfde als de PageModel klasse.

@namespace werkt ook met conventionele Razor weergaven.

Bekijk het Pages/Create.cshtml weergavebestand:

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

Het bijgewerkte Pages/Create.cshtml weergavebestand met _ViewImports.cshtml en het voorgaande indelingsbestand:

@page
@model CreateModel

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

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

In de voorgaande code zijn de _ViewImports.cshtml naamruimte en Tag Helpers geïmporteerd. Het indelingsbestand heeft de JavaScript-bestanden geïmporteerd.

Het Razor startersproject Pages bevat het Pages/_ValidationScriptsPartial.cshtml, waarmee validatie aan de clientzijde wordt gekoppeld.

Zie Gedeeltelijke weergaven in ASP.NET Core voor meer informatie over gedeeltelijke weergaven.

URL-generatie voor pagina's

De Create pagina, die eerder wordt weergegeven, gebruikt 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");
    }
}

De app heeft de volgende bestands-/mapstructuur:

  • /Pages

    • Index.cshtml

    • Privacy.cshtml

    • /Customers

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

De Pages/Customers/Create.cshtml pagina's Pages/Customers/Edit.cshtml worden omgeleid naar Pages/Customers/Index.cshtml na succes. De tekenreeks ./Index is een relatieve paginanaam die wordt gebruikt voor toegang tot de voorgaande pagina. Deze wordt gebruikt om URL's naar de Pages/Customers/Index.cshtml pagina te genereren. Voorbeeld:

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

De absolute paginanaam /Index wordt gebruikt om URL's naar de Pages/Index.cshtml pagina te genereren. Voorbeeld:

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

De paginanaam is het pad naar de pagina vanuit de hoofddirectory /Pagina's, inclusief een voorloopteken / (bijvoorbeeld /Index). De voorgaande voorbeelden van het genereren van URL's bieden verbeterde opties en functionele mogelijkheden ten opzichte van het coderen van een URL. Het genereren van url's maakt gebruik van routering en kan parameters genereren en coderen op basis van hoe de route in het doelpad wordt gedefinieerd.

HET genereren van URL's voor pagina's ondersteunt relatieve namen. In de volgende tabel ziet u welke indexpagina is geselecteerd met behulp van verschillende RedirectToPage parameters in 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")en RedirectToPage("../Index") zijn relatieve namen. De RedirectToPage parameter wordt gecombineerd met het pad van de huidige pagina om de naam van de doelpagina te berekenen.

Relatieve naamkoppeling is handig bij het bouwen van sites met een complexe structuur. Wanneer relatieve namen worden gebruikt om een koppeling te maken tussen pagina's in een map:

  • Als u de naam van een map wijzigt, worden de relatieve koppelingen niet verbroken.
  • Koppelingen worden niet verbroken omdat ze de mapnaam niet bevatten.

Als u wilt omleiden naar een pagina in een ander gebied, geeft u het gebied op:

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

Zie Gebieden in ASP.NET Core en Razor Pagina's route en app-conventies in ASP.NET Core voor meer informatie.

ViewData-kenmerk

Gegevens kunnen worden doorgegeven aan een pagina met ViewDataAttribute. Eigenschappen met het [ViewData] kenmerk hebben hun waarden opgeslagen en geladen vanuit de ViewDataDictionary.

In het volgende voorbeeld AboutModel wordt het [ViewData] kenmerk toegepast op de Title eigenschap:

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

    public void OnGet()
    {
    }
}

Ga op de pagina Info naar de Title eigenschap als een modeleigenschap:

<h1>@Model.Title</h1>

In de indeling wordt de titel gelezen uit de ViewData-woordenlijst:

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

TempData

ASP.NET Core stelt de TempData bloot. Met deze eigenschap worden gegevens opgeslagen totdat deze worden gelezen. De Keep en Peek methoden kunnen worden gebruikt om de gegevens te onderzoeken zonder te verwijderen. TempData is handig voor omleiding, wanneer gegevens nodig zijn voor meer dan één aanvraag.

Met de volgende code wordt de waarde van Message ingesteld met behulp van 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");
    }
}

De volgende opmaakcode in het Pages/Customers/Index.cshtml-bestand geeft de waarde van Message weer met behulp van TempData.

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

Het Pages/Customers/Index.cshtml.cs paginamodel past het [TempData] kenmerk toe op de Message eigenschap.

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

Zie TempData voor meer informatie.

Meerdere handlers per pagina

Op de volgende pagina worden markeringen voor twee handlers gegenereerd met behulp van de asp-page-handler Tag Helper:

@page
@model CreateFATHModel

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

Het formulier in het vorige voorbeeld heeft twee verzendknoppen, die elk FormActionTagHelper gebruiken om naar een andere URL te verzenden. Het asp-page-handler kenmerk is een aanvulling op asp-page. asp-page-handler genereert URL's die worden verzonden naar elk van de handlermethoden die zijn gedefinieerd door een pagina. asp-page is niet opgegeven omdat het voorbeeld is gekoppeld aan de huidige pagina.

Het paginamodel:

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

In de voorgaande code worden benoemde handlermethoden gebruikt. Benoemde handlermethoden worden gemaakt door de tekst in de naam na On<HTTP Verb> en voor Async (indien aanwezig) te nemen. In het voorgaande voorbeeld zijn de paginamethoden OnPostJoinListAsync en OnPostJoinListUCAsync. Als OnPost en Async zijn verwijderd, zijn de handlernamen JoinList en JoinListUC.

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

Met behulp van de voorgaande code, is het URL-pad dat naar OnPostJoinListAsync zendt https://localhost:5001/Customers/CreateFATH?handler=JoinList. Het URL-pad dat naar OnPostJoinListUCAsync verzendt, is https://localhost:5001/Customers/CreateFATH?handler=JoinListUC.

Aangepaste routes

Gebruik de @page instructie om het volgende te doen:

  • Geef een aangepaste route naar een pagina op. De route naar de Over-pagina kan bijvoorbeeld worden ingesteld met /Some/Other/Path@page "/Some/Other/Path".
  • Segmenten toevoegen aan de standaardroute van een pagina. Een itemsegment kan bijvoorbeeld worden toegevoegd aan de standaardroute van een pagina met @page "item".
  • Parameters toevoegen aan de standaardroute van een pagina. Een id-parameter, idkan bijvoorbeeld vereist zijn voor een pagina met @page "{id}".

Een root-relatief pad dat aan het begin van het pad is aangewezen door een tilde (~) wordt ondersteund. @page "~/Some/Other/Path" is bijvoorbeeld hetzelfde als @page "/Some/Other/Path".

Als u niet tevreden bent over de querytekenreeks ?handler=JoinList in de URL, wijzigt u de route om de handlernaam in het padgedeelte van de URL te plaatsen. De route kan worden aangepast door een routesjabloon tussen dubbele aanhalingstekens na de @page instructie toe te voegen.

@page "{handler?}"
@model CreateRouteModel

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

Met behulp van de voorgaande code, is het URL-pad dat naar OnPostJoinListAsync zendt https://localhost:5001/Customers/CreateFATH/JoinList. Het URL-pad dat naar OnPostJoinListUCAsync verzendt, is https://localhost:5001/Customers/CreateFATH/JoinListUC.

Het ? volgende handler betekent dat de routeparameter optioneel is.

Geavanceerde configuratie en instellingen

De configuratie en instellingen in de volgende secties zijn niet vereist voor de meeste apps.

Als u geavanceerde opties wilt configureren, gebruikt u de AddRazorPages overbelasting die het volgende configureert RazorPagesOptions:

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

Gebruik de RazorPagesOptions opdracht om de hoofdmap voor pagina's in te stellen of toepassingsmodelconventies toe te voegen voor pagina's. Zie Razor pagina's autorisatieconventies voor meer informatie over conventies.

Zie Razor compilatie weergeven om weergaven vooraf te compileren.

Opgeven dat Razor pagina's zich in de hoofdmap van de inhoud bevinden

Pagina's zijn standaard Razor geroot in de map /Pages . Voeg WithRazorPagesAtContentRoot toe om op te geven dat uw Razor pagina's zich in de hoofdmap van de inhoud (ContentRootPath) van de app bevinden:

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

Opgeven dat Razor Pagina's zich in een aangepaste hoofdmap bevinden

Toevoegen WithRazorPagesRoot om op te geven dat Razor Pagina's zich in een aangepaste hoofdmap in de app bevinden (geef een relatief pad op):

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

Aanvullende bronnen