Úvod do Razor stránek v ASP.NET Core

Autor: Rick Anderson, Dave Brock a Kirk Larkin

Razor Stránky můžou usnadnit a zvýšit produktivitu scénářů zaměřených na kódování stránek než používání kontrolerů a zobrazení.

Pokud hledáte kurz, který používá přístup Model-View-Controller, podívejte se na Začínáme s ASP.NET Core MVC.

Tento dokument obsahuje úvod do Razor stránek. Nejedná se o podrobný kurz. Pokud najdete některé oddíly příliš pokročilé, podívejte se na Začínáme se stránkamiRazor. Přehled ASP.NET Core najdete v tématu Úvod do ASP.NET Core.

Požadavky

Razor Vytvoření projektu Stránky

Podrobné pokyny k vytvoření Razor projektu Pages najdete v Začínáme se stránkamiRazor.

Razor Stránky

Razor Stránky jsou povoleny v 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();

V předchozím kódu:

Zvažte základní stránku:

@page

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

Předchozí kód vypadá hodně jako Razor soubor zobrazení používaný v aplikaci ASP.NET Core s kontrolery a zobrazeními. Čím se direktiva @page liší. @page vytvoří soubor do akce MVC, což znamená, že zpracovává požadavky přímo, aniž by procházel kontrolerem. @page musí být první Razor direktivou na stránce. @page ovlivňuje chování jiných Razor konstruktorů. Razor Názvy souborů stránek mají příponu .cshtml .

Podobná stránka, která používá PageModel třídu, je zobrazena v následujících dvou souborech. Soubor Pages/Index2.cshtml :

@page
@using RazorPagesIntro.Pages
@model Index2Model

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

Model Pages/Index2.cshtml.cs stránky:

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

Podle konvence PageModel má soubor třídy stejný název jako Razor stránkovací soubor s připojeným .cs . Například předchozí Razor stránka je Pages/Index2.cshtml. Soubor obsahující PageModel třídu má název Pages/Index2.cshtml.cs.

Přidružení cest URL na stránky jsou určena umístěním stránky v systému souborů. Následující tabulka ukazuje Razor cestu stránky a odpovídající adresu URL:

Název souboru a cesta odpovídající adresa URL
/Pages/Index.cshtml / nebo /Index
/Pages/Contact.cshtml /Contact
/Pages/Store/Contact.cshtml /Store/Contact
/Pages/Store/Index.cshtml /Store nebo /Store/Index

Poznámky:

  • Modul runtime ve výchozím nastavení hledá Razor soubory Pages ve složce Pages .
  • Index je výchozí stránka, pokud adresa URL neobsahuje stránku.

Zápis základního formuláře

Razor Stránky jsou navržené tak, aby se při vytváření aplikace snadno implementovaly běžné vzory používané ve webových prohlížečích. Vazby modelu, pomocné rutiny značek a pomocné rutiny HTML pracují s vlastnostmi definovanými ve Razor třídě Page. Zvažte stránku, která implementuje základní formulář Contact "kontaktujte nás":

Pro ukázky v tomto dokumentu DbContext se inicializuje v souboru Startup.cs .

Databáze v paměti vyžaduje Microsoft.EntityFrameworkCore.InMemory balíček NuGet.

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

Datový model:

using System.ComponentModel.DataAnnotations;

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

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

Kontext databáze:

using Microsoft.EntityFrameworkCore;

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

        public DbSet<RazorPagesContacts.Models.Customer> Customer { get; set; }
    }
}

Soubor Pages/Create.cshtml zobrazení:

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

Model Pages/Create.cshtml.cs stránky:

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

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

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

Podle konvence PageModel se třída volá <PageName>Model a je ve stejném oboru názvů jako stránka.

Třída PageModel umožňuje oddělení logiky stránky od prezentace. Definuje obslužné rutiny stránek pro požadavky odeslané na stránku a data použitá k vykreslení stránky. Toto oddělení umožňuje:

Stránka má metodu OnPostAsyncobslužné rutiny, která běží na POST požadavcích (když uživatel publikuje formulář). Metody obslužné rutiny pro jakékoli příkazy HTTP lze přidat. Nejběžnější obslužné rutiny jsou:

  • OnGet pro inicializaci stavu potřebného pro stránku. V předchozím kódu se OnGet v metodě zobrazí CreateModel.cshtmlRazor stránka.
  • OnPost pro zpracování odesílání formulářů.

Přípona názvu Async je volitelná, ale často se podle konvence používá pro asynchronní funkce. Předchozí kód je typický pro Razor Stránky.

Pokud znáte ASP.NET aplikace pomocí kontrolerů a zobrazení:

  • Kód OnPostAsync v předchozím příkladu vypadá podobně jako typický kód kontroleru.
  • Většina primitivních objektů MVC, jako jsou vazby modelu, ověření a výsledky akcí, fungují stejně s řadiči a Razor stránkami.

Předchozí OnPostAsync metoda:

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

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

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

    return RedirectToPage("./Index");
}

Základní tok OnPostAsync:

Zkontrolujte chyby ověření.

  • Pokud nedošlo k žádným chybám, uložte data a přesměrujte je.
  • Pokud dojde k chybám, zobrazte stránku znovu s ověřovacími zprávami. V mnoha případech by se v klientovi zjistily chyby ověřování a nikdy by se neodeslaly na server.

Soubor Pages/Create.cshtml zobrazení:

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

Vykreslený kód HTML z Pages/Create.cshtml:

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

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

V předchozím kódu publikujte formulář:

  • S platnými daty:

    • Metoda OnPostAsync obslužné rutiny volá pomocnou metodu RedirectToPage . RedirectToPage vrací instanci RedirectToPageResult. RedirectToPage:

      • Je výsledek akce.
      • Podobá se RedirectToAction nebo RedirectToRoute (používá se v kontrolérech a zobrazeních).
      • Je přizpůsobený pro stránky. V předchozí ukázce se přesměruje na kořenovou stránku indexu (/Index). RedirectToPage je podrobně popsáno v části Generování adres URL pro stránky .
  • Při ověřování chyb, které se předávají serveru:

    • Metoda OnPostAsync obslužné rutiny volá pomocnou metodu Page . Page vrací instanci PageResult. Page Vrácení se podobá tomu, jak se vrátí akce v řadičích View. PageResult je výchozí návratový typ pro metodu obslužné rutiny. Metoda obslužné rutiny, která vrátí void vykreslení stránky.
    • V předchozím příkladu publikování formuláře bez hodnoty způsobí , že ModelState.IsValid vrátí hodnotu false. V této ukázce se v klientovi nezobrazují žádné chyby ověření. Předání chyby ověření je popsané dále v tomto dokumentu.
    [BindProperty]
    public Customer Customer { get; set; }
    
    public async Task<IActionResult> OnPostAsync()
    {
        if (!ModelState.IsValid)
        {
            return Page();
        }
    
        _context.Customer.Add(Customer);
        await _context.SaveChangesAsync();
    
        return RedirectToPage("./Index");
    }
    
  • S chybami ověření zjištěnými ověřením na straně klienta:

    • Data se na server neodesílala.
    • Ověření na straně klienta je vysvětleno dále v tomto dokumentu.

Vlastnost Customer používá [BindProperty] atribut k vyjádření souhlasu s vazbou modelu:

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

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

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

[BindProperty]by se neměly používat u modelů obsahujících vlastnosti, které by klient neměl měnit. Další informace naleznete v tématu Overposting.

Razor Stránky ve výchozím nastavení sváže vlastnosti pouze s jinýmiGET příkazy. Vazba na vlastnosti odebere nutnost zápisu kódu pro převod dat HTTP na typ modelu. Vazba omezuje kód pomocí stejné vlastnosti k vykreslení polí formuláře (<input asp-for="Customer.Name">) a přijetí vstupu.

Upozornění

Z bezpečnostních důvodů se musíte přihlásit k vytvoření vazby GET dat požadavku na vlastnosti modelu stránky. Před mapováním na vlastnosti ověřte vstup uživatele. Při přidělování scénářů, které se spoléhají na řetězec dotazu nebo hodnoty směrování, je vhodné vyjádřit výslovný souhlas s GET vazbou.

Chcete-li vytvořit vazbu vlastnosti na GET požadavky, nastavte vlastnost atributu [BindProperty]SupportsGet na true:

[BindProperty(SupportsGet = true)]

Další informace najdete v tématu ASP.NET Core Community Standup: Bind on GET discussion (YouTube).

Pages/Create.cshtml Kontrola souboru zobrazení:

@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>
  • V předchozím kódu pomocné rutina<input asp-for="Customer.Name" /> vstupní značky vytvoří vazbu elementu HTML <input> na Customer.Name výraz modelu.
  • @addTagHelper zpřístupňuje pomocné rutiny značek.

Domovská stránka

Index.cshtml je domovská stránka:

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

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

Přidružená PageModel třída (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();
    }
}

Soubor Index.cshtml obsahuje následující revize:

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

Pomocný <a /a>pomocník značky ukotveníasp-route-{value} použil atribut k vygenerování odkazu na stránku Upravit. Odkaz obsahuje směrovací data s ID kontaktu. Například, https://localhost:5001/Edit/1. Pomocné rutiny značek umožňují, aby se podíleli na vytváření a vykreslování elementů HTML v Razor souborech.

Soubor Index.cshtml obsahuje kód pro vytvoření tlačítka pro odstranění pro každý kontakt zákazníka:

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

Vykreslený kód HTML:

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

Když se tlačítko pro odstranění vykreslí ve formátu HTML, jeho formaction obsahuje parametry pro:

  • ID kontaktu zákazníka zadané atributem asp-route-id .
  • Vlastnost handler, určená atributem asp-page-handler .

Po výběru tlačítka se na server odešle žádost o formulář POST . Podle konvence je název metody obslužné rutiny vybrán na základě hodnoty handler parametru podle schématu OnPost[handler]Async.

Vzhledem k tomu, že handler je delete v tomto příkladu OnPostDeleteAsync , metoda obslužné rutiny se používá ke zpracování POST požadavku. asp-page-handler Pokud je nastavena na jinou hodnotu, například remove, je vybrána metoda obslužné rutiny s názvemOnPostRemoveAsync.

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

Metoda OnPostDeleteAsync :

  • id Získá z řetězce dotazu.
  • Dotazuje databázi na kontakt zákazníka s FindAsync.
  • Pokud se najde kontakt zákazníka, odebere se a databáze se aktualizuje.
  • Volání RedirectToPage přesměrování na kořenovou stránku indexu (/Index).

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

První řádek obsahuje direktivu @page "{id:int}" . Omezení "{id:int}" směrování informuje stránku, aby přijímala požadavky na stránku, která obsahuje int směrovací data. Pokud požadavek na stránku neobsahuje směrovací data, která lze převést na , intvrátí modul runtime chybu HTTP 404 (nenalezena). Pokud chcete, aby ID bylo volitelné, připojte ? se k omezení trasy:

@page "{id:int?}"

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

}

Ověřování

Ověřovací pravidla:

  • Jsou deklarativní zadané ve třídě modelu.
  • Vynucují se všude v aplikaci.

Obor System.ComponentModel.DataAnnotations názvů poskytuje sadu předdefinovaných ověřovacích atributů, které se aplikují deklarativním způsobem na třídu nebo vlastnost. Objekty DataAnnotation také obsahují atributy formátování, jako [DataType] je například formátování, a neposkytuje žádné ověření.

Customer Zvažte model:

using System.ComponentModel.DataAnnotations;

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

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

Pomocí následujícího Create.cshtml souboru zobrazení:

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

Předchozí kód:

  • Obsahuje ověřovací skripty jQuery a jQuery.

  • Pomocí pomocných rutin a <span /> pomocných <div />rutin značek povolíte:

    • Ověření na straně klienta
    • Vykreslování chyby ověření
  • Vygeneruje následující kód HTML:

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

Publikování formuláře Vytvořit bez hodnoty názvu zobrazí chybovou zprávu "Pole Název je požadováno" ve formuláři. Pokud je v klientovi povolený JavaScript, zobrazí se v prohlížeči chyba bez publikování na server.

Atribut [StringLength(10)] vygeneruje data-val-length-max="10" vykreslený kód HTML. data-val-length-max zabraňuje prohlížečům zadávat více než maximální zadanou délku. Pokud se nástroj, jako je Fiddler , používá k úpravám a přehrání příspěvku:

  • S názvem delším než 10.
  • Vrátí se chybová zpráva "Název pole musí být řetězec s maximální délkou 10".

Zvažte následující 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; }
    }
}

Atributy ověření určují chování, které se má vynutit u vlastností modelu, na které se použijí:

  • MinimumLength Atributy Required označují, že vlastnost musí mít hodnotu, ale nic nebrání uživateli v zadávání prázdného místa, aby toto ověření splnil.

  • Atribut RegularExpression slouží k omezení toho, jaké znaky lze zadat. V předchozím kódu "Žánr":

    • Musí používat jenom písmena.
    • První písmeno musí být velké. Prázdné znaky, čísla a speciální znaky nejsou povolené.
  • " RegularExpression Hodnocení":

    • Vyžaduje, aby první znak byl velkým písmenem.
    • Umožňuje speciální znaky a čísla v dalších mezerách. "PG-13" je platný pro hodnocení, ale selže pro "Žánr".
  • Atribut Range omezuje hodnotu v konkrétním rozsahu.

  • Atribut StringLength nastaví maximální délku vlastnosti řetězce a volitelně její minimální délku.

  • Typy hodnot (například decimal, , intfloatDateTime) jsou ze své podstaty povinné a nepotřebují [Required] atribut.

Na stránce Vytvořit pro Movie model se zobrazují chyby s neplatnými hodnotami:

Movie view form with multiple jQuery client-side validation errors

Další informace naleznete v tématu:

Izolace šablon stylů CSS

Izolujte styly CSS na jednotlivé stránky, zobrazení a komponenty, abyste snížili nebo zabránili těmto stránkám:

  • Závislosti na globálních stylech, které můžou být náročné na údržbu.
  • Konflikty stylů v vnořeném obsahu

Pokud chcete přidat soubor CSS s vymezeným oborem pro stránku nebo zobrazení, umístěte styly CSS do doprovodného .cshtml.css souboru odpovídající názvu .cshtml souboru. V následujícím příkladu Index.cshtml.css soubor poskytuje styly CSS, které se použijí jenom na Index.cshtml stránku nebo zobrazení.

Pages/Index.cshtml.css (Razor Stránky) nebo Views/Index.cshtml.css (MVC):

h1 {
    color: red;
}

Izolace šablon stylů CSS probíhá v době sestavení. Architektura přepisuje selektory css tak, aby odpovídaly revizím vykresleným stránkami nebo zobrazeními aplikace. Přepsané styly CSS jsou seskupené a vytvářeny jako statický prostředek, {APP ASSEMBLY}.styles.css. Zástupný symbol {APP ASSEMBLY} je název sestavení projektu. Odkaz na seskupené styly CSS se umístí do rozložení aplikace.

<head> V obsahu aplikace Pages/Shared/_Layout.cshtml (RazorStránky) nebo Views/Shared/_Layout.cshtml MVC přidejte nebo potvrďte přítomnost odkazu na sbalené styly CSS:

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

V následujícím příkladu je WebAppnázev sestavení aplikace:

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

Styly definované v souboru CSS s vymezeným oborem se použijí pouze na vykreslený výstup odpovídajícího souboru. V předchozím příkladu nejsou všechny h1 deklarace CSS definované jinde v aplikaci v konfliktu se stylem nadpisu Index. Šablony stylů CSS a pravidla dědičnosti zůstávají v platnosti pro soubory CSS s vymezeným oborem. Styly použité například přímo u <h1> elementu Index.cshtml v souboru přepíší styly souboru CSS s vymezeným oborem v Index.cshtml.csssouboru .

Poznámka

Pokud chcete zaručit izolaci stylu CSS při sdružování, import šablon stylů CSS v Razor blocích kódu se nepodporuje.

Izolace šablon stylů CSS se vztahuje pouze na elementy HTML. Izolace šablon stylů CSS není podporována pro pomocné rutiny značek.

V souboru CSS v rámci sady je každá stránka, zobrazení nebo Razor komponenta přidružena k identifikátoru oboru ve formátu b-{STRING}, kde {STRING} zástupný symbol je desetimínný řetězec vygenerovaný architekturou. Následující příklad poskytuje styl pro předchozí <h1> prvek na Index stránce Razor aplikace Pages:

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

Na Index stránce, kde se styl CSS použije ze souboru se souborem s balíčkem, se identifikátor oboru připojí jako atribut HTML:

<h1 b-3xxtam6d07>

Identifikátor je jedinečný pro aplikaci. V době sestavení se vytvoří sada projektů s konvencí {STATIC WEB ASSETS BASE PATH}/Project.lib.scp.css, kde zástupný symbol {STATIC WEB ASSETS BASE PATH} představuje základní cestu statických webových prostředků.

Pokud se využívají jiné projekty, například balíčky NuGet nebo Razor knihovny tříd, soubor se váže:

  • Odkazuje na styly pomocí importů css.
  • Nepublikuje se jako statický webový prostředek aplikace, který využívá styly.

Podpora preprocesoru CSS

Preprocesory css jsou užitečné pro zlepšení vývoje css pomocí funkcí, jako jsou proměnné, vnořování, moduly, mixiny a dědičnost. I když izolace šablon stylů CSS nativně nepodporuje preprocesory šablon stylů CSS, jako jsou Sass nebo Less, integrace preprocesorů CSS je bezproblémová, pokud dojde k kompilaci preprocesoru před přepsáním selektorů CSS během procesu sestavení. Pomocí Visual Studio například nakonfigurujte existující kompilaci preprocesoru jako úlohu Před sestavením v průzkumníku Visual Studio Spouštěč úloh.

Řada balíčků NuGet třetích stran, jako Delegate.SassBuilderje například , může kompilovat soubory SASS/SCSS na začátku procesu sestavení před izolací CSS a nevyžaduje se žádná další konfigurace.

Konfigurace izolace šablon stylů CSS

Izolace šablon stylů CSS umožňuje konfiguraci pro některé pokročilé scénáře, například pokud existují závislosti na existujících nástrojích nebo pracovních postupech.

Přizpůsobení formátu identifikátoru oboru

V této části {Pages|Views} je Pages zástupný symbol pro Razor aplikace Pages nebo Views pro aplikace MVC.

Ve výchozím nastavení identifikátory oboru používají formát b-{STRING}, kde {STRING} zástupný symbol je řetězec desetimísek vygenerovaný architekturou. Pokud chcete přizpůsobit formát identifikátoru oboru, aktualizujte soubor projektu na požadovaný vzor:

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

V předchozím příkladu vygeneroval css pro Index.cshtml.css změny jeho identifikátor oboru z b-{STRING} na custom-scope-identifier.

Pomocí identifikátorů oboru dosáhnete dědičnosti s vymezenými soubory CSS. V následujícím příkladu BaseView.cshtml.css souboru projektu soubor obsahuje společné styly napříč zobrazeními. DerivedView.cshtml.css Soubor dědí tyto styly.

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

Pomocí operátoru se zástupným znakem (*) můžete sdílet identifikátory oboru mezi více soubory:

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

Změna základní cesty pro statické webové prostředky

V kořenovém adresáři aplikace se vygeneruje soubor CSS s vymezeným oborem. V souboru projektu použijte StaticWebAssetBasePath vlastnost ke změně výchozí cesty. Následující příklad umístí soubor CSS s vymezeným oborem a zbytek prostředků aplikace na _content cestu:

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

Zakázání automatického sdružování

Pokud chcete vyloučit, jak architektura publikuje a načítá soubory s vymezeným oborem za běhu, použijte DisableScopedCssBundling tuto vlastnost. Při použití této vlastnosti zodpovídají za převzetí izolovaných souborů CSS z obj adresáře a jejich publikování a jejich načítání za běhu další nástroje nebo procesy:

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

Razor Podpora knihovny tříd (RCL)

Razor Když knihovna tříd (RCL) poskytuje izolované styly, <link> atribut značky href odkazuje na {STATIC WEB ASSET BASE PATH}/{PACKAGE ID}.bundle.scp.css, kde jsou zástupné symboly:

  • {STATIC WEB ASSET BASE PATH}: Základní cesta statického webového prostředku.
  • {PACKAGE ID}: Identifikátor balíčku knihovny. Identifikátor balíčku ve výchozím nastavení odkazuje na název sestavení projektu, pokud není v souboru projektu zadaný identifikátor balíčku.

V následujícím příkladu:

  • Základní cesta statického webového prostředku je _content/ClassLib.
  • Název sestavení knihovny tříd je ClassLib.

Pages/Shared/_Layout.cshtml (Razor Stránky) nebo Views/Shared/_Layout.cshtml (MVC):

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

Další informace o náležcích RCL najdete v následujících článcích:

Informace o Blazor izolaci šablon stylů CSS najdete v tématu ASP.NET Core Blazor izolace šablon stylů CSS.

Zpracování požadavků HEAD pomocí náhradní obslužné rutiny OnGet

HEAD požadavky umožňují načtení hlaviček pro konkrétní prostředek. Na rozdíl od GET požadavků HEAD nevrací požadavky text odpovědi.

Obvykle se vytvoří obslužná rutina OnHead a volá se pro HEAD požadavky:

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

Razor Stránky se vrátí do volání obslužné OnGet rutiny, pokud není definována žádná OnHead obslužná rutina.

XSRF/CSRF a Razor stránky

Razor Stránky jsou chráněny ověřením antiforgery. FormTagHelper vloží antiforgery tokeny do elementů formuláře HTML.

Použití pomocných rutin rozložení, částečných hodnot, šablon a značek se stránkami Razor

Stránky pracují se všemi funkcemi Razor modulu zobrazení. Rozložení, části, šablony, pomocné rutiny _ViewStart.cshtmlznaček a _ViewImports.cshtml fungují stejným způsobem jako u konvenčních Razor zobrazení.

Podívejme se na tuto stránku tím, že využijeme některé z těchto možností.

Přidání stránky rozložení do 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>

Rozložení:

  • Určuje rozložení jednotlivých stránek (pokud se stránka nevyhlásí z rozložení).
  • Importuje struktury HTML, jako jsou JavaScript a šablony stylů.
  • Razor Obsah stránky se vykreslí tam, kde @RenderBody() se volá.

Další informace najdete na stránce rozložení.

Vlastnost Layout je nastavena v Pages/_ViewStart.cshtml:

@{
    Layout = "_Layout";
}

Rozložení je ve složce Pages/Shared . Stránky vyhledávají další zobrazení (rozložení, šablony, části) hierarchicky, počínaje stejnou složkou jako aktuální stránka. Rozložení ve složce Pages/Shared lze použít z libovolné Razor stránky ve složce Stránky .

Soubor rozložení by měl být ve složce Pages/Shared .

Doporučujeme, abyste soubor rozložení nevložili do složky Zobrazení/Sdílené složky. Zobrazení/sdílené zobrazení je vzor zobrazení MVC. Razor Stránky jsou určené k závislosti na hierarchii složek, nikoli na konvence cest.

Zobrazení hledání ze Razor stránky obsahuje složku Stránky . Rozložení, šablony a části používané s řadiči MVC a konvenčními Razor zobrazeními fungují.

Pages/_ViewImports.cshtml Přidejte soubor:

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

@namespace je vysvětleno dále v tomto kurzu. Direktiva @addTagHelper přináší integrované pomocné rutiny značek na všechny stránky ve složce Pages .

Direktiva @namespace nastavená na stránce:

@page
@namespace RazorPagesIntro.Pages.Customers

@model NameSpaceModel

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

Direktiva @namespace nastaví obor názvů stránky. Direktiva @model nemusí zahrnovat obor názvů.

@namespace Pokud je direktiva obsažena_ViewImports.cshtml, zadaný obor názvů poskytuje předponu pro vygenerovaný obor názvů na stránce, která importuje direktivu@namespace. Zbytek vygenerovaného oboru názvů (část s příponou) je tečkovaná relativní cesta mezi složkou obsahující _ViewImports.cshtml a složkou obsahující stránku.

PageModel Například třída Pages/Customers/Edit.cshtml.cs explicitně nastaví obor názvů:

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

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

        // Code removed for brevity.

Soubor Pages/_ViewImports.cshtml nastaví následující obor názvů:

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

Vygenerovaný obor názvů stránky Pages/Customers/Edit.cshtmlRazor je stejný jako PageModel třída.

@namespacefunguje také s konvenčními Razor zobrazeními.

Pages/Create.cshtml Zvažte soubor zobrazení:

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

Aktualizovaný Pages/Create.cshtml soubor zobrazení s předchozím souborem _ViewImports.cshtml rozložení:

@page
@model CreateModel

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

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

V předchozím kódu _ViewImports.cshtml importoval obor názvů a pomocné rutiny značek. Soubor rozložení naimportoval soubory JavaScriptu.

Razor Úvodní projekt Pages obsahuje Pages/_ValidationScriptsPartial.cshtmlobjekt , který připojí ověření na straně klienta.

Další informace o částečných zobrazeních najdete v tématu Částečná zobrazení v ASP.NET Core.

Generování adres URL pro stránky

Stránka Create , která byla zobrazena dříve, používá 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");
    }
}

Aplikace má následující strukturu souborů a složek:

  • /Pages

    • Index.cshtml

    • Privacy.cshtml

    • /Customers

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

Stránky Pages/Customers/Create.cshtml a Pages/Customers/Edit.cshtml stránky se přesměrovávají na Pages/Customers/Index.cshtml po úspěšném dokončení. Řetězec ./Index je relativní název stránky použitý pro přístup k předchozí stránce. Slouží k vygenerování adres URL na Pages/Customers/Index.cshtml stránku. Například:

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

Absolutní název /Index stránky slouží k vygenerování adres URL na Pages/Index.cshtml stránku. Například:

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

Název stránky je cesta k stránce z kořenové složky /Pages včetně úvodní / (například /Index). Předchozí ukázky generování adres URL nabízejí vylepšené možnosti a funkční funkce při pevném kódování adresy URL. Generování adres URL používá směrování a může generovat a kódovat parametry podle toho, jak je trasa definovaná v cílové cestě.

Generování adres URL pro stránky podporuje relativní názvy. Následující tabulka ukazuje, která stránka indexu je vybrána pomocí různých RedirectToPage parametrů v Pages/Customers/Create.cshtml.

RedirectToPage(x) Stránka
RedirectToPage("/Index") Stránky/index
RedirectToPage("./Index"); Stránky/ Zákazníci/ Index
RedirectToPage(".. /Index") Stránky/index
RedirectToPage("Index") Stránky/ Zákazníci/ Index

RedirectToPage("Index"), RedirectToPage("./Index")a RedirectToPage("../Index") jsou relativní názvy. Parametr RedirectToPage je kombinován s cestou aktuální stránky k výpočtu názvu cílové stránky.

Propojení relativního názvu je užitečné při vytváření lokalit se složitou strukturou. Pokud se relativní názvy používají k propojení mezi stránkami ve složce:

  • Přejmenování složky nezlomí relativní odkazy.
  • Odkazy nejsou poškozené, protože neobsahují název složky.

Pokud chcete přesměrovat na stránku v jiné oblasti, zadejte oblast:

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

Další informace najdete v tématu Oblasti v ASP.NET Core a Razor konvencích tras a aplikací v ASP.NET Core.

Atribut ViewData

Data lze předat na stránku s ViewDataAttribute. Vlastnosti s atributem [ViewData] mají své hodnoty uložené a načtené z objektu ViewDataDictionary.

V následujícím příkladu AboutModel platí [ViewData] atribut pro Title vlastnost:

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

    public void OnGet()
    {
    }
}

Na stránce O aplikaci přejděte na Title vlastnost jako vlastnost modelu:

<h1>@Model.Title</h1>

V rozložení se nadpis přečte ze slovníku ViewData:

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

TempData

ASP.NET Core zveřejňuje TempData. Tato vlastnost ukládá data, dokud se nečte. Tyto Keep metody Peek lze použít k prozkoumání dat bez odstranění. TempData je užitečná pro přesměrování, pokud jsou data potřebná pro více než jeden požadavek.

Následující kód nastaví hodnotu Message použití 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");
    }
}

Následující kód v Pages/Customers/Index.cshtml souboru zobrazuje hodnotu Message použití TempData.

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

Model Pages/Customers/Index.cshtml.cs stránky použije [TempData] atribut na Message vlastnost.

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

Další informace najdete v tématu TempData.

Více obslužných rutin na stránku

Následující stránka vygeneruje kód pro dva obslužné rutiny pomocí pomocné rutiny asp-page-handler značek:

@page
@model CreateFATHModel

<html>
<body>
    <p>
        Enter your name.
    </p>
    <div asp-validation-summary="All"></div>
    <form method="POST">
        <div>Name: <input asp-for="Customer.Name" /></div>
        <!-- <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>

Formulář v předchozím příkladu obsahuje dvě tlačítka pro odeslání, z nichž každý používá FormActionTagHelper k odeslání jinou adresu URL. Atribut asp-page-handler je průvodcem asp-page. asp-page-handler generuje adresy URL, které se odesílají do každé metody obslužné rutiny definované stránkou. asp-page není zadán, protože ukázka odkazuje na aktuální stránku.

Model stránky:

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

Předchozí kód používá pojmenované metody obslužné rutiny. Pojmenované metody obslužné rutiny se vytvářejí tak, že převezmou text v názvu za On<HTTP Verb> a před Async (pokud jsou k dispozici). V předchozím příkladu jsou metody stránky OnPostJoinListAsync a OnPostJoinListUCAsync. Při odebrání OnPost a Async jsou JoinList názvy obslužných rutin a JoinListUC.

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

Pomocí předchozího kódu je cesta URL, která se odešle.OnPostJoinListAsynchttps://localhost:5001/Customers/CreateFATH?handler=JoinList Cesta URL, která se odešle, OnPostJoinListUCAsync je https://localhost:5001/Customers/CreateFATH?handler=JoinListUC.

Vlastní trasy

Direktivu @page použijte k:

  • Zadejte vlastní trasu na stránku. Můžete například nastavit /Some/Other/Path@page "/Some/Other/Path"trasu na stránku O produktu .
  • Připojte segmenty k výchozí trase stránky. Například segment "item" lze přidat do výchozí trasy stránky s @page "item".
  • Připojte parametry k výchozí trase stránky. Například parametr ID , idmůže být vyžadován pro stránku s @page "{id}".

Podporuje se kořenová relativní cesta určená vlnovkou (~) na začátku cesty. Je například @page "~/Some/Other/Path" stejný jako @page "/Some/Other/Path".

Pokud se vám řetězec ?handler=JoinList dotazu v adrese URL nelíbí, změňte trasu tak, aby název obslužné rutiny vložil do části cesty adresy URL. Trasu lze přizpůsobit přidáním šablony trasy uzavřené do dvojitých uvozovek za direktivou @page .

@page "{handler?}"
@model CreateRouteModel

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

Pomocí předchozího kódu je cesta URL, která se odešle.OnPostJoinListAsynchttps://localhost:5001/Customers/CreateFATH/JoinList Cesta URL, která se odešle, OnPostJoinListUCAsync je https://localhost:5001/Customers/CreateFATH/JoinListUC.

Následující ?handler znamená, že parametr trasy je volitelný.

Pokročilá konfigurace a nastavení

Většina aplikací nevyžaduje konfiguraci a nastavení v následujících částech.

Pokud chcete konfigurovat pokročilé možnosti, použijte AddRazorPages přetížení, které konfiguruje 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();

RazorPagesOptions Slouží k nastavení kořenového adresáře pro stránky nebo přidání konvencí modelu aplikace pro stránky. Další informace o konvencích najdete v tématu Razor Konvence autorizace stránek.

Pokud chcete předkompilovat zobrazení, podívejte se na Razor kompilaci zobrazení.

Určení, že Razor stránky jsou v kořenovém adresáři obsahu

Ve výchozím nastavení Razor jsou stránky kořenové v adresáři /Pages . Přidejte WithRazorPagesAtContentRoot , abyste určili, že vaše Razor stránky jsou v kořenovém adresáři obsahu (ContentRootPath) aplikace:

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

Určení, že Razor stránky jsou ve vlastním kořenovém adresáři

Přidejte WithRazorPagesRoot k určení, že Razor stránky jsou ve vlastním kořenovém adresáři v aplikaci (zadejte relativní cestu):

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

Další materiály

Razor Vytvoření projektu Stránky

Podrobné pokyny k vytvoření Razor projektu Pages najdete v Začínáme se stránkamiRazor.

Razor Stránky

Razor Stránky jsou povoleny v 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();
        });
    }
}

Zvažte základní stránku:

@page

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

Předchozí kód vypadá hodně jako Razor soubor zobrazení používaný v aplikaci ASP.NET Core s kontrolery a zobrazeními. Čím se direktiva @page liší. @page vytvoří soubor do akce MVC – což znamená, že zpracovává požadavky přímo, aniž by procházel kontrolerem. @page musí být první Razor direktivou na stránce. @page ovlivňuje chování jiných Razor konstruktorů. Razor Názvy souborů stránek mají příponu .cshtml .

Podobná stránka, která používá PageModel třídu, je zobrazena v následujících dvou souborech. Soubor Pages/Index2.cshtml :

@page
@using RazorPagesIntro.Pages
@model Index2Model

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

Model Pages/Index2.cshtml.cs stránky:

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

Podle konvence PageModel má soubor třídy stejný název jako Razor stránkovací soubor s připojeným .cs . Například předchozí Razor stránka je Pages/Index2.cshtml. Soubor obsahující PageModel třídu má název Pages/Index2.cshtml.cs.

Přidružení cest URL na stránky jsou určena umístěním stránky v systému souborů. Následující tabulka ukazuje Razor cestu stránky a odpovídající adresu URL:

Název souboru a cesta odpovídající adresa URL
/Pages/Index.cshtml / nebo /Index
/Pages/Contact.cshtml /Contact
/Pages/Store/Contact.cshtml /Store/Contact
/Pages/Store/Index.cshtml /Store nebo /Store/Index

Poznámky:

  • Modul runtime ve výchozím nastavení hledá Razor soubory Pages ve složce Pages .
  • Index je výchozí stránka, pokud adresa URL neobsahuje stránku.

Zápis základního formuláře

Razor Stránky jsou navržené tak, aby se při vytváření aplikace snadno implementovaly běžné vzory používané ve webových prohlížečích. Vazby modelu, pomocné rutiny značek a pomocné rutiny HTML fungují jenom s vlastnostmi definovanými ve Razor třídě Page. Zvažte stránku, která implementuje základní formulář Contact "kontaktujte nás":

Pro ukázky v tomto dokumentu DbContext se inicializuje v souboru Startup.cs .

Databáze v paměti vyžaduje Microsoft.EntityFrameworkCore.InMemory balíček NuGet.

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

Datový model:

using System.ComponentModel.DataAnnotations;

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

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

Kontext databáze:

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

Soubor Pages/Create.cshtml zobrazení:

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

Model Pages/Create.cshtml.cs stránky:

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

Podle konvence PageModel se třída volá <PageName>Model a je ve stejném oboru názvů jako stránka.

Třída PageModel umožňuje oddělení logiky stránky od prezentace. Definuje obslužné rutiny stránek pro požadavky odeslané na stránku a data použitá k vykreslení stránky. Toto oddělení umožňuje:

Stránka má metodu OnPostAsyncobslužné rutiny, která běží na POST požadavcích (když uživatel publikuje formulář). Metody obslužné rutiny pro jakékoli příkazy HTTP lze přidat. Nejběžnější obslužné rutiny jsou:

  • OnGet pro inicializaci stavu potřebného pro stránku. V předchozím kódu se OnGet v metodě zobrazí CreateModel.cshtmlRazor stránka.
  • OnPost pro zpracování odesílání formulářů.

Přípona názvu Async je volitelná, ale často se podle konvence používá pro asynchronní funkce. Předchozí kód je typický pro Razor Stránky.

Pokud znáte ASP.NET aplikace pomocí kontrolerů a zobrazení:

  • Kód OnPostAsync v předchozím příkladu vypadá podobně jako typický kód kontroleru.
  • Většina primitivních objektů MVC, jako jsou vazby modelu, ověření a výsledky akcí, fungují stejně s řadiči a Razor stránkami.

Předchozí OnPostAsync metoda:

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

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

    return RedirectToPage("./Index");
}

Základní tok OnPostAsync:

Zkontrolujte chyby ověření.

  • Pokud nedošlo k žádným chybám, uložte data a přesměrujte je.
  • Pokud dojde k chybám, zobrazte stránku znovu s ověřovacími zprávami. V mnoha případech by se v klientovi zjistily chyby ověřování a nikdy by se neodeslaly na server.

Soubor Pages/Create.cshtml zobrazení:

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

Vykreslený kód HTML z Pages/Create.cshtml:

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

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

V předchozím kódu publikujte formulář:

  • S platnými daty:

    • Metoda OnPostAsync obslužné rutiny volá pomocnou metodu RedirectToPage . RedirectToPage vrací instanci RedirectToPageResult. RedirectToPage:

      • Je výsledek akce.
      • RedirectToAction Podobá se nebo RedirectToRoute (používá se v řadičích a zobrazeních).
      • Je přizpůsoben pro stránky. V předchozí ukázce se přesměruje na kořenovou stránku indexu (/Index). RedirectToPage je podrobně popsáno v části Generování adres URL pro stránky .
  • Při ověřování chyb, které se předávají serveru:

    • Metoda OnPostAsync obslužné rutiny volá pomocnou metodu Page . Page vrací instanci PageResult. Page Vrácení se podobá tomu, jak se vrátí akce v řadičích View. PageResult je výchozí návratový typ pro metodu obslužné rutiny. Metoda obslužné rutiny, která vrátí void vykreslení stránky.
    • V předchozím příkladu publikování formuláře bez hodnoty způsobí , že ModelState.IsValid vrátí hodnotu false. V této ukázce se v klientovi nezobrazují žádné chyby ověření. Předání chyby ověření je popsané dále v tomto dokumentu.
    public async Task<IActionResult> OnPostAsync()
    {
        if (!ModelState.IsValid)
        {
            return Page();
        }
    
        _context.Customers.Add(Customer);
        await _context.SaveChangesAsync();
    
        return RedirectToPage("./Index");
    }
    
  • S chybami ověření zjištěnými ověřením na straně klienta:

    • Data se na server neodesílala.
    • Ověření na straně klienta je vysvětleno dále v tomto dokumentu.

Vlastnost Customer používá [BindProperty] atribut k vyjádření souhlasu s vazbou modelu:

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]by se neměly používat u modelů obsahujících vlastnosti, které by klient neměl měnit. Další informace naleznete v tématu Overposting.

Razor Stránky ve výchozím nastavení sváže vlastnosti pouze s jinýmiGET příkazy. Vazba na vlastnosti odebere nutnost zápisu kódu pro převod dat HTTP na typ modelu. Vazba omezuje kód pomocí stejné vlastnosti k vykreslení polí formuláře (<input asp-for="Customer.Name">) a přijetí vstupu.

Upozornění

Z bezpečnostních důvodů se musíte přihlásit k vytvoření vazby GET dat požadavku na vlastnosti modelu stránky. Před mapováním na vlastnosti ověřte vstup uživatele. Při přidělování scénářů, které se spoléhají na řetězec dotazu nebo hodnoty směrování, je vhodné vyjádřit výslovný souhlas s GET vazbou.

Chcete-li vytvořit vazbu vlastnosti na GET požadavky, nastavte vlastnost atributu [BindProperty]SupportsGet na true:

[BindProperty(SupportsGet = true)]

Další informace najdete v tématu ASP.NET Core Community Standup: Bind on GET discussion (YouTube).

Pages/Create.cshtml Kontrola souboru zobrazení:

@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>
  • V předchozím kódu pomocné rutina<input asp-for="Customer.Name" /> vstupní značky vytvoří vazbu elementu HTML <input> na Customer.Name výraz modelu.
  • @addTagHelper zpřístupňuje pomocné rutiny značek.

Domovská stránka

Index.cshtml je domovská stránka:

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

Přidružená PageModel třída (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();
    }
}

Soubor Index.cshtml obsahuje následující revize:

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

Pomocný <a /a>pomocník značky ukotveníasp-route-{value} použil atribut k vygenerování odkazu na stránku Upravit. Odkaz obsahuje směrovací data s ID kontaktu. Například, https://localhost:5001/Edit/1. Pomocné rutiny značek umožňují, aby se podíleli na vytváření a vykreslování elementů HTML v Razor souborech.

Soubor Index.cshtml obsahuje kód pro vytvoření tlačítka pro odstranění pro každý kontakt zákazníka:

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

Vykreslený kód HTML:

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

Když se tlačítko pro odstranění vykreslí ve formátu HTML, jeho formaction obsahuje parametry pro:

  • ID kontaktu zákazníka zadané atributem asp-route-id .
  • Vlastnost handler, určená atributem asp-page-handler .

Po výběru tlačítka se na server odešle žádost o formulář POST . Podle konvence je název metody obslužné rutiny vybrán na základě hodnoty handler parametru podle schématu OnPost[handler]Async.

Vzhledem k tomu, že handler je delete v tomto příkladu OnPostDeleteAsync , metoda obslužné rutiny se používá ke zpracování POST požadavku. asp-page-handler Pokud je nastavena na jinou hodnotu, například remove, je vybrána metoda obslužné rutiny s názvemOnPostRemoveAsync.

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

Metoda OnPostDeleteAsync :

  • id Získá z řetězce dotazu.
  • Dotazuje databázi na kontakt zákazníka s FindAsync.
  • Pokud se najde kontakt zákazníka, odebere se a databáze se aktualizuje.
  • Volání RedirectToPage přesměrování na kořenovou stránku indexu (/Index).

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

První řádek obsahuje direktivu @page "{id:int}" . Omezení "{id:int}" směrování informuje stránku, aby přijímala požadavky na stránku, která obsahuje int směrovací data. Pokud požadavek na stránku neobsahuje směrovací data, která lze převést na , intvrátí modul runtime chybu HTTP 404 (nenalezena). Pokud chcete, aby ID bylo volitelné, připojte ? se k omezení trasy:

@page "{id:int?}"

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

}

Ověřování

Ověřovací pravidla:

  • Jsou deklarativní zadané ve třídě modelu.
  • Vynucují se všude v aplikaci.

Obor System.ComponentModel.DataAnnotations názvů poskytuje sadu předdefinovaných ověřovacích atributů, které se aplikují deklarativním způsobem na třídu nebo vlastnost. Objekty DataAnnotation také obsahují atributy formátování, jako [DataType] je například formátování, a neposkytuje žádné ověření.

Customer Zvažte model:

using System.ComponentModel.DataAnnotations;

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

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

Pomocí následujícího Create.cshtml souboru zobrazení:

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

Předchozí kód:

  • Obsahuje ověřovací skripty jQuery a jQuery.

  • Pomocí pomocných rutin a <span /> pomocných <div />rutin značek povolíte:

    • Ověření na straně klienta
    • Vykreslování chyby ověření
  • Vygeneruje následující kód HTML:

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

Publikování formuláře Vytvořit bez hodnoty názvu zobrazí chybovou zprávu "Pole Název je požadováno" ve formuláři. Pokud je v klientovi povolený JavaScript, zobrazí se v prohlížeči chyba bez publikování na server.

Atribut [StringLength(10)] vygeneruje data-val-length-max="10" vykreslený kód HTML. data-val-length-max zabraňuje prohlížečům zadávat více než maximální zadanou délku. Pokud se nástroj, jako je Fiddler , používá k úpravám a přehrání příspěvku:

  • S názvem delším než 10.
  • Vrátí se chybová zpráva "Název pole musí být řetězec s maximální délkou 10".

Zvažte následující 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; }
    }
}

Atributy ověření určují chování, které se má vynutit u vlastností modelu, na které se použijí:

  • MinimumLength Atributy Required označují, že vlastnost musí mít hodnotu, ale nic nebrání uživateli v zadávání prázdného místa, aby toto ověření splnil.

  • Atribut RegularExpression slouží k omezení toho, jaké znaky lze zadat. V předchozím kódu "Žánr":

    • Musí používat jenom písmena.
    • První písmeno musí být velké. Prázdné znaky, čísla a speciální znaky nejsou povolené.
  • " RegularExpression Hodnocení":

    • Vyžaduje, aby první znak byl velkým písmenem.
    • Umožňuje speciální znaky a čísla v následujících mezerách. "PG-13" je platné pro hodnocení, ale selže pro "Žánr".
  • Atribut Range omezuje hodnotu v konkrétním rozsahu.

  • Atribut StringLength nastaví maximální délku vlastnosti řetězce a volitelně její minimální délku.

  • Typy hodnot (například decimal, , int, floatDateTime) jsou ze své podstaty povinné a nepotřebují [Required] atribut.

Na stránce Vytvořit pro Movie model se zobrazují chyby s neplatnými hodnotami:

Movie view form with multiple jQuery client-side validation errors

Další informace naleznete v tématu:

Zpracování požadavků HEAD pomocí náhradní obslužné rutiny OnGet

HEAD požadavky umožňují načtení hlaviček pro konkrétní prostředek. Na rozdíl od GET požadavků HEAD nevrací požadavky text odpovědi.

Obvykle se vytvoří obslužná rutina OnHead a volá se pro HEAD požadavky:

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

Razor Stránky se vrátí zpět k volání OnGet obslužné rutiny, pokud není definována žádná OnHead obslužná rutina.

XSRF/CSRF a Razor stránky

Razor Stránky jsou chráněny ověřováním antiforgery. FormTagHelper vloží antiforgery tokeny do elementů formuláře HTML.

Použití rozložení, částečných, šablon a pomocných rutin značek se stránkami Razor

Stránky pracují se všemi možnostmi Razor modulu zobrazení. Rozložení, části, šablony, pomocné rutiny _ViewStart.cshtmlznaček a _ViewImports.cshtml fungují stejným způsobem jako u konvenčních Razor zobrazení.

Probereme tuto stránku tím, že využijeme některé z těchto možností.

Přidání stránky rozložení do 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>

Rozložení:

  • Určuje rozložení každé stránky (pokud se stránka nevyhlásí z rozložení).
  • Importuje struktury HTML, jako jsou JavaScript a šablony stylů.
  • Obsah Razor stránky se vykresluje tam, kde @RenderBody() se volá.

Další informace najdete na stránce rozložení.

Vlastnost Layout je nastavena v Pages/_ViewStart.cshtml:

@{
    Layout = "_Layout";
}

Rozložení je ve složce Pages/Shared . Stránky hledají další zobrazení (rozložení, šablony, částečné) hierarchicky, počínaje stejnou složkou jako aktuální stránka. Rozložení ve složce Pages/Shared lze použít z libovolné Razor stránky ve složce Stránky .

Soubor rozložení by měl být ve složce Pages/Shared .

Doporučujeme, abyste soubor rozložení neuložili do složky Zobrazení nebo sdílené složky. Zobrazení nebo sdílení je vzor zobrazení MVC. Razor Stránky se mají spoléhat na hierarchii složek, nikoli na konvence cest.

Zobrazení hledání ze Razor stránky zahrnuje složku Stránky . Rozložení, šablony a části používané s řadiči MVC a konvenčními Razor zobrazeními fungují.

Pages/_ViewImports.cshtml Přidejte soubor:

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

@namespace je vysvětleno později v tomto kurzu. Direktiva @addTagHelper přináší integrované pomocné rutiny značek na všechny stránky ve složce Pages .

Direktiva @namespace nastavená na stránce:

@page
@namespace RazorPagesIntro.Pages.Customers

@model NameSpaceModel

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

Direktiva @namespace nastaví obor názvů stránky. Direktiva @model nemusí zahrnovat obor názvů.

@namespace Pokud je direktiva obsažena, _ViewImports.cshtmlzadaný obor názvů poskytuje předponu pro vygenerovaný obor názvů na stránce, která importuje direktivu@namespace. Zbytek generovaného oboru názvů (část přípony) je tečkovaná relativní cesta mezi složkou obsahující _ViewImports.cshtml a složkou obsahující stránku.

PageModel Například třída Pages/Customers/Edit.cshtml.cs explicitně nastaví obor názvů:

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

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

        // Code removed for brevity.

Soubor Pages/_ViewImports.cshtml nastaví následující obor názvů:

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

Vygenerovaný obor názvů stránky Pages/Customers/Edit.cshtmlRazor je stejný jako PageModel třída.

@namespacefunguje také s konvenčními Razor zobrazeními.

Pages/Create.cshtml Zvažte soubor zobrazení:

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

Aktualizovaný Pages/Create.cshtml soubor zobrazení s předchozím souborem _ViewImports.cshtml rozložení:

@page
@model CreateModel

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

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

V předchozím kódu _ViewImports.cshtml importoval obor názvů a pomocné rutiny značek. Soubor rozložení naimportoval soubory JavaScriptu.

Razor Úvodní projekt Pages obsahuje Pages/_ValidationScriptsPartial.cshtmlobjekt , který připojí ověření na straně klienta.

Další informace o částečných zobrazeních najdete v tématu Částečná zobrazení v ASP.NET Core.

Generování adres URL pro stránky

Stránka Create , která byla zobrazena dříve, používá 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");
    }
}

Aplikace má následující strukturu souborů a složek:

  • /Pages

    • Index.cshtml

    • Privacy.cshtml

    • /Customers

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

Stránky Pages/Customers/Create.cshtml a Pages/Customers/Edit.cshtml stránky se přesměrovávají na Pages/Customers/Index.cshtml po úspěšném dokončení. Řetězec ./Index je relativní název stránky použitý pro přístup k předchozí stránce. Slouží k vygenerování adres URL na Pages/Customers/Index.cshtml stránku. Například:

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

Absolutní název /Index stránky slouží k vygenerování adres URL na Pages/Index.cshtml stránku. Například:

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

Název stránky je cesta k stránce z kořenové složky /Pages včetně úvodní / (například /Index). Předchozí ukázky generování adres URL nabízejí vylepšené možnosti a funkční funkce při pevném kódování adresy URL. Generování adres URL používá směrování a může generovat a kódovat parametry podle toho, jak je trasa definovaná v cílové cestě.

Generování adres URL pro stránky podporuje relativní názvy. Následující tabulka ukazuje, která stránka indexu je vybrána pomocí různých RedirectToPage parametrů v Pages/Customers/Create.cshtml.

RedirectToPage(x) Stránka
RedirectToPage("/Index") Stránky/index
RedirectToPage("./Index"); Stránky/ Zákazníci/ Index
RedirectToPage(".. /Index") Stránky/index
RedirectToPage("Index") Stránky/ Zákazníci/ Index

RedirectToPage("Index"), RedirectToPage("./Index")a RedirectToPage("../Index") jsou relativní názvy. Parametr RedirectToPage je kombinován s cestou aktuální stránky k výpočtu názvu cílové stránky.

Propojení relativního názvu je užitečné při vytváření lokalit se složitou strukturou. Pokud se relativní názvy používají k propojení mezi stránkami ve složce:

  • Přejmenování složky nezlomí relativní odkazy.
  • Odkazy nejsou poškozené, protože neobsahují název složky.

Pokud chcete přesměrovat na stránku v jiné oblasti, zadejte oblast:

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

Další informace najdete v tématu Oblasti v ASP.NET Core a Razor konvencích tras a aplikací v ASP.NET Core.

Atribut ViewData

Data lze předat na stránku s ViewDataAttribute. Vlastnosti s atributem [ViewData] mají své hodnoty uložené a načtené z objektu ViewDataDictionary.

V následujícím příkladu AboutModel platí [ViewData] atribut pro Title vlastnost:

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

    public void OnGet()
    {
    }
}

Na stránce O aplikaci přejděte na Title vlastnost jako vlastnost modelu:

<h1>@Model.Title</h1>

V rozložení se nadpis přečte ze slovníku ViewData:

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

TempData

ASP.NET Core zveřejňuje TempData. Tato vlastnost ukládá data, dokud se nečte. Tyto Keep metody Peek lze použít k prozkoumání dat bez odstranění. TempData je užitečný pro přesměrování, pokud jsou data potřebná pro více než jeden požadavek.

Následující kód nastaví hodnotu Message použití 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");
    }
}

Následující kód v Pages/Customers/Index.cshtml souboru zobrazuje hodnotu Message použití TempData.

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

Model Pages/Customers/Index.cshtml.cs stránky použije [TempData] atribut na Message vlastnost.

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

Další informace najdete v tématu TempData.

Více obslužných rutin na stránku

Na následující stránce se vygenerují značky pro dva obslužné rutiny pomocí pomocné rutiny asp-page-handler značek:

@page
@model CreateFATHModel

<html>
<body>
    <p>
        Enter your name.
    </p>
    <div asp-validation-summary="All"></div>
    <form method="POST">
        <div>Name: <input asp-for="Customer.Name" /></div>
        <!-- <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>

Formulář v předchozím příkladu obsahuje dvě tlačítka pro odeslání, z nichž každý používá FormActionTagHelper k odeslání na jinou adresu URL. Atribut asp-page-handler je společníkem asp-page. asp-page-handler generuje adresy URL, které se odesílají do každé metody obslužné rutiny definované stránkou. asp-page není zadán, protože ukázka odkazuje na aktuální stránku.

Model stránky:

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

Předchozí kód používá pojmenované metody obslužné rutiny. Pojmenované metody obslužné rutiny jsou vytvořeny tak, že po a před Async (pokud existují) text v názvuOn<HTTP Verb>. V předchozím příkladu jsou metody stránky OnPostJoinListAsync a OnPostJoinListUCAsync. Při odebrání OnPost a Async jsou JoinList názvy obslužných rutin a JoinListUC.

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

Pomocí předchozího kódu je cesta URL, která se odešle.OnPostJoinListAsynchttps://localhost:5001/Customers/CreateFATH?handler=JoinList Cesta URL, která se odešle, OnPostJoinListUCAsync je https://localhost:5001/Customers/CreateFATH?handler=JoinListUC.

Vlastní trasy

Direktivu použijte k @page :

  • Zadejte vlastní trasu na stránku. Můžete například nastavit /Some/Other/Path@page "/Some/Other/Path"trasu na stránku O aplikaci .
  • Připojte segmenty k výchozí trase stránky. Například segment "item" lze přidat do výchozí trasy stránky s @page "item".
  • Připojte parametry k výchozí trase stránky. Například parametr idID , může být vyžadován pro stránku s @page "{id}".

Podporuje se kořenová relativní cesta určená vlnovkou (~) na začátku cesty. Například @page "~/Some/Other/Path" je stejný jako @page "/Some/Other/Path".

Pokud se vám řetězec ?handler=JoinList dotazu v adrese URL nelíbí, změňte trasu tak, aby název obslužné rutiny vložil do části cesty adresy URL. Trasu lze přizpůsobit přidáním šablony trasy uzavřené do dvojitých uvozovek za direktivu @page .

@page "{handler?}"
@model CreateRouteModel

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

Pomocí předchozího kódu je cesta URL, která se odešle.OnPostJoinListAsynchttps://localhost:5001/Customers/CreateFATH/JoinList Cesta URL, která se odešle, OnPostJoinListUCAsync je https://localhost:5001/Customers/CreateFATH/JoinListUC.

Následující ?handler znamená, že parametr trasy je volitelný.

Pokročilá konfigurace a nastavení

Většina aplikací nevyžaduje konfiguraci a nastavení v následujících částech.

Pokud chcete konfigurovat pokročilé možnosti, použijte AddRazorPages přetížení, které konfiguruje RazorPagesOptions:

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

RazorPagesOptions Použijte k nastavení kořenového adresáře pro stránky nebo přidání konvencí aplikačního modelu pro stránky. Další informace o konvencích najdete v tématu Razor Konvence autorizace stránek.

Pokud chcete předkompilovat zobrazení, podívejte se Razor na kompilaci zobrazení.

Určete, že Razor stránky jsou v kořenovém adresáři obsahu.

Ve výchozím nastavení Razor jsou stránky kořenové v adresáři /Pages . Přidejte WithRazorPagesAtContentRoot , abyste určili, že vaše Razor stránky jsou v kořenovém adresáři obsahu (ContentRootPath) aplikace:

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

Určení, že Razor stránky jsou ve vlastním kořenovém adresáři

Přidejte WithRazorPagesRoot , abyste určili, že Razor stránky jsou ve vlastním kořenovém adresáři v aplikaci (zadejte relativní cestu):

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

Další materiály