Úvod do Razor Pages v ASP.NET Core

Autoři: Rick Anderson, Dave Brock a Kirk Larkin

Poznámka:

Toto není nejnovější verze tohoto článku. Aktuální verzi najdete ve verzi .NET 8 tohoto článku.

Upozorňující

Tato verze ASP.NET Core se už nepodporuje. Další informace najdete v tématu .NET a .NET Core Zásady podpory. Aktuální verzi najdete ve verzi .NET 8 tohoto článku.

Důležité

Tyto informace se týkají předběžného vydání produktu, který může být podstatně změněn před komerčním vydáním. Microsoft neposkytuje žádné záruky, výslovné ani předpokládané, týkající se zde uváděných informací.

Aktuální verzi najdete ve verzi .NET 8 tohoto článku.

Model Razor Pages může usnadnit a zefektivnit kódování scénářů zaměřených na stránky oproti používání kontrolerů a zobrazení.

Pokud hledáte kurz zaměřený na model MVC (Model-View-Controller), projděte si téma Začínáme s ASP.NET Core MVC.

Tento dokument poskytuje úvod k Razor Pages. Nejedná se o podrobný kurz. Pokud zjistíte, že jsou pro vás některé části příliš pokročilé, projděte si téma Začínáme s Razor Pages. Přehled ASP.NET Core najdete v tématu Úvod do ASP.NET Core.

Požadavky

Vytvoření projektu Razor Pages

Podrobné pokyny k vytvoření projektu Razor Pages najdete v tématu Začínáme s Razor Pages.

Razor Pages

Razor Pages se povoluje v souboru 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:

Podívejte se například na základní stránku:

@page

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

Výše uvedený kód se velmi podobá souboru zobrazení Razor, který se používá v aplikacích ASP.NET Core s kontrolery a zobrazeními. Liší se v direktivě @page. Direktiva @page ze souboru udělá akci MVC, což znamená, že bude zpracovávat požadavky přímo, aniž by procházely kontrolerem. Direktiva @page musí být první direktivou Razor na stránce. Direktiva @page ovlivňuje chování dalších konstrukcí Razor. Názvy souborů Razor Pages mají příponu .cshtml.

V následujících dvou souborech je ukázka podobné stránky s použitím třídy PageModel. Soubor Pages/Index2.cshtml:

@page
@using RazorPagesIntro.Pages
@model Index2Model

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

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

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

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

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

Podle konvence má soubor třídy PageModel stejný název jako soubor stránky Razor s příponou .cs. Například výše uvedená stránka Razor se nachází v souboru Pages/Index2.cshtml. Soubor obsahující třídu PageModel má název Pages/Index2.cshtml.cs.

Přidružení cest URL ke stránkám se určuje podle umístění stránky v systému souborů. Následující tabulka ukazuje cestu ke stránce Razor 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á soubory Razor Pages ve složce Pages.
  • Pokud adresa URL neobsahuje žádnou stránku, výchozí stránka je Index.

Napsání základního formuláře

Model Razor Pages je navržený tak, aby při vytváření aplikace usnadňoval implementaci běžných modelů používaných ve webových prohlížečích. Vazba modelu, pomocné rutiny značek a pomocné rutiny HTML fungují s vlastnostmi definovanými v třídě stránky Razor. Podívejte se například na stránku, která pro model Contact implementuje základní kontaktní formulář:

U ukázek v tomto dokumentu DbContext se inicializuje v souboru Program.cs .

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

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 => Set<RazorPagesContacts.Models.Customer>();
    }
}

Soubor zobrazení Pages/Customers/Create.cshtml:

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

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

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

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

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

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

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

Stránka má metodu obslužné OnPostAsync rutiny, která se spouští na POST žádostech (když uživatel publikuje formulář). Je možné přidat metody obslužných událostí pro jakékoli příkazy HTTP. Nejběžnější obslužné rutiny jsou:

  • OnGet pro inicializaci stavu potřebného pro stránku. Ve výše uvedeném kódu metoda OnGet zobrazí stránku Razor Create.cshtml.
  • 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. Výše uvedený kód je pro Razor Pages typický.

Pokud máte zkušenosti s aplikacemi ASP.NET využívajícími kontrolery a zobrazení:

  • Kód metody OnPostAsync ve výše uvedeném příkladu se podobá typickému kódu kontroleru.
  • Většina primitiv MVC, jako jsou vazba modelu, ověřování a výsledky akcí, funguje v Razor Pages stejně jako u kontrolerů.

Výše uvedená metoda OnPostAsync:

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

Základní tok metody OnPostAsync:

Zkontroluje, jestli nedošlo k chybám ověřování.

  • Pokud nedošlo k žádným chybám, uloží data a provede přesměrování.
  • Pokud došlo k chybám, znovu zobrazí stránku 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 zobrazení Pages/Customers/Create.cshtml:

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

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

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

Vykreslený kód HTML ze souboru Pages/Customers/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>

Ve výše uvedeném kódu se po odeslání formuláře stane následující:

  • V případě platných dat:

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

      • Je výsledek akce.
      • Je metoda podobná metodám RedirectToAction nebo RedirectToRoute (které se používají v kontrolerech a zobrazeních).
      • Je metoda přizpůsobená pro stránky. Ve výše uvedené ukázce provádí přesměrování na kořenovou indexovou stránku (/Index). Metoda RedirectToPage je podrobně popsaná v části Generování adres URL pro stránky.
  • V případě chyb ověřování předaných na server:

    • Metoda obslužné rutiny OnPostAsync zavolá metodu obslužné rutiny Page. Page vrací instanci PageResult. Vrácení objektu Page se podobá tomu, jak akce v kontrolerech vrací objekt View. Výchozí návratový typ metody obslužné rutiny je PageResult. Metoda obslužné rutiny, která vrátí hodnotu void, vykreslí stránku.
    • Ve výše uvedeném příkladu odeslání formuláře bez jakékoli hodnoty způsobí, že ModelState.IsValid vrátí hodnotu false. V této ukázce se v klientovi nezobrazí žádné chyby ověřování. Zpracování chyb ověřování se věnujeme dále v tomto dokumentu.
    [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");
    }
    
  • V případě detekce chyb ověřování při ověřování na straně klienta:

    • Data se neodešlou na server.
    • Ověřování na straně klienta se věnujeme dále v tomto dokumentu.

Vlastnost Customer pro přihlášení k vazbě modelu používá atribut [BindProperty]:

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

Atribut [BindProperty] by se neměl používat u modelů obsahujících vlastnosti, které by klient neměl měnit. Další informace najdete v části Útoky typu overpost.

Razor Pages ve výchozím nastavení váže vlastnosti pouze k jiným příkazům než GET. Díky vazbě na vlastnosti odpadá nutnost psát kód pro převod dat HTTP na typ modelu. Vazba snižuje množství kódu díky tomu, že se k vykreslení polí formuláře (<input asp-for="Customer.Name">) a příjmu vstupu používá stejná vlastnost.

Upozorňující

Z bezpečnostních důvodů musíte vyjádřit souhlas s vazbou dat požadavků GET na vlastnosti modelu stránky. Před mapováním uživatelského vstupu na vlastnosti tento vstup ověřte. Vyjádření souhlasu s vazbou požadavků GET je užitečné při řešení scénářů, které se spoléhají na řetězec dotazu nebo hodnoty trasy.

Pokud chcete vytvořit vazbu vlastnosti na požadavky GET, nastavte vlastnost SupportsGet atributu [BindProperty] na hodnotu true:

[BindProperty(SupportsGet = true)]

Další informace najdete ve videu Přehled novinek v komunitě ASP.NET Core: Diskuze k vazbě požadavků GET (YouTube).

Projděte si soubor zobrazení Pages/Customers/Create.cshtml:

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

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

<form method="post">
    Name:
    <input asp-for="Customer!.Name" />
    <input type="submit" />
</form>
  • V předchozím kódu pomocné rutina <input asp-for="Customer.Name" /> vstupní značky sváže element HTML <input> s výrazem Customer.Name modelu.
  • Direktiva @addTagHelper zpřístupňuje pomocné rutiny značek.

Stránka home

Index.cshtmlhome je 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>
        @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>

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

Soubor Index.cshtml obsahuje následující kód:

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

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

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

<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í v HTML, jeho atribut formaction obsahuje parametry pro:

  • ID kontaktu zákazníka zadané atributem asp-route-id
  • Obslužnou rutinu handler zadanou atributem asp-page-handler

Při výběru tohoto tlačítka se na server odešle požadavek POST formuláře. Podle konvence se název metody obslužné rutiny vybírá na základě hodnoty parametru handler ve schématu OnPost[handler]Async.

Vzhledem k tomu, že parametr handler má v tomto příkladu hodnotu delete, ke zpracování požadavku POST se použije metoda obslužné rutiny OnPostDeleteAsync. Pokud je atribut asp-page-handler nastavený na jinou hodnotu, například remove, vybere se metoda obslužné rutiny s názvem OnPostRemoveAsync.

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

Metoda OnPostDeleteAsync:

  • Získá z řetězce dotazu hodnotu id.
  • Pomocí metody FindAsync odešle do databáze dotaz na kontakt zákazníka.
  • Pokud se kontakt zákazníka najde, odebere se a databáze se aktualizuje.
  • Zavolá metodu RedirectToPage, která provede přesměrování na kořenovou indexovou stránku (/Index).

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

První řádek obsahuje direktivu @page "{id:int}". Omezení směrování "{id:int}" stránce říká, že má přijímat požadavky na stránku, které obsahují data trasy typu int. Pokud požadavek na stránku neobsahuje data trasy, která je možné převést na hodnotu typu int, modul runtime vrátí chybu HTTP 404 (Nenalezeno). Pokud chcete nastavit ID jako volitelné, připojte k omezení trasy symbol ?:

@page "{id:int?}"

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

Ověřování

Pravidla ověřování:

  • Zadávají se deklarativně v třídě modelu.
  • Vynucují se v rámci celé aplikace.

Obor názvů System.ComponentModel.DataAnnotations nabízí sadu předdefinovaných atributů ověřování, které je možné deklarativně použít na třídu nebo vlastnost. Obor názvů DataAnnotations obsahuje také atributy formátování, jako je [DataType], které pomáhají s formátováním a neposkytují žádné ověřování.

Podívejte se například na model Customer:

using System.ComponentModel.DataAnnotations;

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

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

Používá se následující soubor zobrazení Create.cshtml:

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

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

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

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

Předchozí kód:

  • Vkládá knihovnu jQuery a ověřovací skripty jQuery.

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

    • Ověřování na straně klienta
    • Vykreslování chyb ověřování
  • Generuje 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>
    

Při odeslání formuláře pro vytvoření bez hodnoty názvu se ve formuláři zobrazí chybová zpráva Pole Name je povinné. Pokud je v klientovi povolený JavaScript, v prohlížeči se zobrazí chyba, aniž by se formulář odeslal na server.

Atribut [StringLength(10)] ve vykresleném kódu HTML vygeneruje atribut data-val-length-max="10". Atribut data-val-length-max brání v prohlížečích v zadání více znaků, než je zadaná maximální délka. Pokud se k úpravě a opětovnému odeslání použije nástroj typu Fiddler:

  • Pokud je název delší než 10 znaků:
  • Vrátí se chybová zpráva Pole Name musí obsahovat řetězec o maximální délce 10 znaků.

Podívejte se například na následující model Movie:

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ěřování určují chování, které se má vynucovat u vlastností modelu, na které se použijí:

  • Atributy Required a MinimumLength značí, že vlastnost musí mít nějakou hodnotu, ale uživateli nic nebrání v zadání prázdných znaků, které tímto ověřením projdou.

  • Atribut RegularExpression slouží k omezení množiny znaků, které je možné zadat. Pro vlastnost Genre ve výše uvedeném kódu platí následující:

    • Může obsahovat pouze písmena.
    • Počáteční písmeno musí být velké. Nemůže obsahovat prázdné znaky, číslice ani speciální znaky.
  • Regulární výraz (RegularExpression) u vlastnosti Rating:

    • Vyžaduje, aby prvním znakem bylo velké písmeno.
    • Na dalších místech povoluje speciální znaky a číslice. PG-13 je platná hodnota pro vlastnost Rating, ale ne pro vlastnost Genre.
  • Atribut Range omezuje hodnotu v konkrétním rozsahu.

  • Atribut StringLength nastavuje maximální délku řetězcové vlastnosti a volitelně i její minimální délku.

  • Typy hodnot (například decimal, int, float, DateTime) jsou ze své podstaty povinné a nevyžadují atribut [Required].

Na stránce pro vytvoření pro model Movie se v případě neplatných hodnot zobrazí chyby:

Formulář zobrazení Movie s několika chybami ověřování jQuery na straně klienta

Další informace naleznete v tématu:

Izolace šablon stylů CSS

Izolujte styly CSS na jednotlivé stránky, zobrazení a komponenty, abyste omezili nebo eliminovali:

  • Závislosti na globálních stylech, jejichž údržba může být náročná
  • Konflikty stylů ve vnořeném obsahu

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

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

h1 {
    color: red;
}

K izolaci šablon stylů CSS dochází v okamžiku sestavení. Architektura přepíše selektory CSS tak, aby odpovídaly kódu vykreslenému stránkami nebo zobrazeními aplikace. Přepsané styly CSS se sdruží do statického prostředku {APP ASSEMBLY}.styles.css. Zástupný symbol {APP ASSEMBLY} je název sestavení projektu. Do rozložení aplikace se umístí odkaz na sdružené styly CSS.

Ověřte, že element <head> v souboru Pages/Shared/_Layout.cshtml (Razor Pages) nebo Views/Shared/_Layout.cshtml (MVC) aplikace obsahuje odkaz na sdružené styly CSS, případně tento odkaz přidejte:

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

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

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

Styly definované v souboru CSS s vymezeným oborem se použijí pouze pro vykreslený výstup odpovídajícího souboru. Ve výše uvedeném příkladu nejsou žádné deklarace CSS elementu h1 definované v jiných částech aplikace v konfliktu se stylem nadpisu pro Index. Pro soubory CSS s vymezeným oborem stále platí pravidla kaskádování a dědičnosti stylů CSS. Například styly použité přímo pro element <h1> v souboru Index.cshtml přepíší styly v souboru CSS s vymezeným oborem Index.cshtml.css.

Poznámka:

V zájmu zajištění izolace stylů CSS při sdružování se nepodporuje import šablon stylů CSS v blocích kódu Razor.

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

V rámci sdruženého souboru CSS je ke každé stránce, každému zobrazení a každé komponentě Razor přidružený identifikátor oboru ve formátu b-{STRING}, kde zástupný symbol {STRING} je řetězec 10 znaků vygenerovaný architekturou. Následující příklad ukazuje styl pro výše uvedený element <h1> na stránce Index aplikace Razor Pages:

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

Na stránce Index, na které se použije tento styl CSS ze sdruženého souboru, se identifikátor oboru připojí jako atribut HTML:

<h1 b-3xxtam6d07>

Identifikátor je pro každou aplikaci jedinečný. V okamžiku sestavení se vytvoří sada prostředků projektu s použitím konvence {STATIC WEB ASSETS BASE PATH}/Project.lib.scp.css, kde zástupný symbol {STATIC WEB ASSETS BASE PATH} je základní cesta ke statickým webovým prostředkům.

Pokud se využívají jiné projekty, jako jsou balíčky NuGet nebo knihovny tříd Razor, sdružený soubor:

  • Odkazuje na styly pomocí importu šablon stylů CSS.
  • Není publikovaný jako statický webový prostředek aplikace, která styly využívá.

Podpora preprocesorů CSS

Preprocesory CSS jsou užitečné pro zlepšení vývoje šablon stylů CSS díky tomu, že umožňují využívat funkce, jako jsou proměnné, vnořování, moduly, mixiny nebo dědičnost. I když izolace šablon stylů CSS nativně nepodporuje preprocesory CSS, jako jsou Sass nebo Less, integrace preprocesorů CSS je bezproblémová, pokud ke kompilaci preprocesoru dochází před tím, než architektura během procesu sestavení přepíše selektory CSS. Pokud například používáte sadu Visual Studio, v Průzkumníku spouštěče úloh sady Visual Studio nakonfigurujte kompilaci stávajícího preprocesoru jako úlohu Před sestavením.

Řada balíčků NuGet třetích stran, jako je AspNetCore.SassCompiler, dokáže bez nutnosti další konfigurace kompilovat soubory SASS/SCSS na začátku procesu sestavení, než dojde k izolaci šablon stylů CSS.

Konfigurace izolace šablon stylů CSS

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

Úprava formátu identifikátoru oboru

Zástupný symbol {Pages|Views} v této části má hodnotu Pages v případě aplikací Razor Pages, nebo Views v případě aplikací MVC.

Ve výchozím nastavení jsou identifikátory oboru ve formátu b-{STRING}, kde zástupný symbol {STRING} je řetězec 10 znaků vygenerovaný architekturou. Pokud chcete formát identifikátoru oboru upravit, aktualizujte soubor projektu s použitím požadovaného vzoru:

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

Ve výše uvedeném příkladu se v šablonách stylů CSS vygenerovaných pro soubor Index.cshtml.css změní identifikátor oboru z formátu b-{STRING} na custom-scope-identifier.

Pomocí identifikátorů oboru můžete dosáhnout dědičnosti u souborů CSS s vymezeným oborem. V následujícím příkladu souboru projektu soubor BaseView.cshtml.css obsahuje společné styly pro všechna zobrazení. Soubor DerivedView.cshtml.css tyto styly dědí.

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

Pokud chcete sdílet identifikátory oboru mezi několika soubory, použijte operátor zástupného znaku (*):

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

Změna základní cesty ke statickým webovým prostředkům

Soubor CSS s vymezeným oborem se vygeneruje v kořenovém adresáři aplikace. Výchozí cestu můžete změnit pomocí vlastnosti StaticWebAssetBasePath v souboru projektu. Následující příklad umístí soubor CSS s vymezeným oborem a rest prostředky aplikace na _content cestu:

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

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

Pokud chcete vyjádřit výslovný nesouhlas s tím, jak architektura publikuje a načítá soubory s vymezeným oborem za běhu, použijte vlastnost DisableScopedCssBundling. Pokud použijete tuto vlastnost, za přebírání izolovaných souborů CSS z adresáře obj a jejich publikování a načítání za běhu budou zodpovídat jiné nástroje nebo procesy:

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

Podpora knihovny tříd Razor (RCL)

Pokud knihovna tříd Razor (RCL) nabízí izolované styly, atribut href značky <link> odkazuje na soubor {STATIC WEB ASSET BASE PATH}/{PACKAGE ID}.bundle.scp.css, kde zástupné symboly mají následující hodnoty:

  • {STATIC WEB ASSET BASE PATH}: Základní cesta ke statickým webovým prostředkům.
  • {PACKAGE ID}: Identifikátor balíčku knihovny. Pokud identifikátor balíčku není zadaný v souboru projektu, ve výchozím nastavení se jako identifikátor balíčku použije název sestavení projektu.

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

  • Základní cesta ke statickým webovým prostředkům je _content/ClassLib.
  • Název sestavení knihovny tříd je ClassLib.

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

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

Další informace o knihovnách tříd Razor najdete v následujících článcích:

Informace o izolaci šablon stylů CSS v architektuře Blazor najdete v tématu Izolace šablon stylů CSS v architektuře ASP.NET Core Blazor.

Zpracování požadavků HEAD s využitím záložní obslužné rutiny OnGet

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

Pro požadavky HEAD se obvykle vytváří a volá obslužná rutina OnHead:

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

Pokud obslužná rutina OnHead není definovaná, Razor Pages se vrátí k volání obslužné rutiny OnGet.

XSRF/CSRF a Razor Pages

Stránky Razor jsou chráněné ověřováním proti padělkům. Obslužná rutina značky form vkládá do elementů formulářů HTML tokeny proti padělkům.

Používání rozložení, částečných zobrazení, šablon a obslužných rutin značek s Razor Pages

Stránky fungují se všemi funkcemi zobrazovacího modulu Razor. Rozložení, částečná zobrazení, šablony, obslužné rutiny značek a soubory _ViewStart.cshtml a _ViewImports.cshtml fungují stejně jako v běžných zobrazeních Razor.

Pojďme tuto stránku zpřehlednit s využitím některých z těchto funkcí.

Přidejte stránku rozložení do souboru 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í:

  • Řídí rozložení každé stránky (pokud stránka rozložení výslovně neodmítne).
  • Importuje struktury HTML, jako jsou JavaScript nebo šablony stylů.
  • Při zavolání metody @RenderBody() vykreslí obsah stránky Razor.

Další informace najdete v tématu věnovaném stránce rozložení.

Hodnota Layout se nastavuje v souboru Pages/_ViewStart.cshtml:

@{
    Layout = "_Layout";
}

Rozložení se nachází ve složce Pages/Shared. Stránky hierarchicky hledají další zobrazení (rozložení, šablony, částečná zobrazení) počínaje stejnou složkou, ve které se nachází aktuální stránka. Rozložení ve složce Pages/Shared je možné použít na jakékoli stránce Razor ve složce Pages.

Soubor rozložení by se měl nacházet ve složce Pages/Shared.

Doporučujeme neumisťovat soubor rozložení do složky Views/Shared. Složka Views/Shared se používá pro model zobrazení MVC. Stránky Razor se mají spoléhat na hierarchii složek, a ne na konvence cest.

Vyhledávání zobrazení na stránce Razor zahrnuje i složku Pages. Rozložení, šablony a částečná zobrazení používaná s kontrolery MVC a běžnými zobrazeními Razor prostě fungují.

Přidejte soubor Pages/_ViewImports.cshtml:

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

Direktivě @namespace se věnujeme dále v tomto kurzu. Direktiva @addTagHelper na všech stránkách ve složce Pages zpřístupní předdefinované obslužné rutiny značek.

Nastavená direktiva @namespace na stránce:

@page
@namespace RazorPagesIntro.Pages.Customers

@model NameSpaceModel

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

Direktiva @namespace nastaví pro stránku obor názvů. Direktiva @model nemusí obsahovat obor názvů.

Pokud soubor _ViewImports.cshtml obsahuje direktivu @namespace, zadaný obor názvů bude představovat předponu vygenerovaného oboru názvů na stránce, která importuje direktivu @namespace. Vygenerovaný rest obor 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.

Například třída PageModel v souboru 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.

V souboru Pages/_ViewImports.cshtml se nastaví následující obor názvů:

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

Vygenerovaný obor názvů pro stránku Razor Pages/Customers/Edit.cshtml bude stejný jako obor názvů třídy PageModel.

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

Podívejte se například na soubor zobrazení Pages/Customers/Create.cshtml:

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

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

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

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

Aktualizovaný soubor zobrazení Pages/Customers/Create.cshtml se souborem _ViewImports.cshtml a výše uvedeným souborem rozložení:

@page
@model CreateModel

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

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

Ve výše uvedeném kódu soubor _ViewImports.cshtml importoval obor názvů a obslužné rutiny značek. Soubor rozložení importoval soubory JavaScriptu.

Úvodní projekt Razor Pages obsahuje soubor Pages/_ValidationScriptsPartial.cshtml, který aktivuje ověřování 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

Na stránce Create uvedené výše se používá metoda 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");
    }
}

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

  • /Pages

    • Index.cshtml

    • Privacy.cshtml

    • /Customers

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

Stránky Pages/Customers/Create.cshtml a Pages/Customers/Edit.cshtml se v případě úspěchu přesměrují na stránku Pages/Customers/Index.cshtml. Řetězec ./Index je relativní název stránky, který se používá pro přístup k předchozí stránce. Slouží ke generování adres URL na stránku Pages/Customers/Index.cshtml. Příklad:

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

Absolutní název stránky /Index slouží ke generování adres URL na stránku Pages/Index.cshtml. Příklad:

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

Název stránky představuje cestu ke stránce z kořenové složky /Pages včetně počátečního lomítka / (například /Index). Výše uvedené ukázky generování adres URL nabízejí oproti pevnému zakódování adresy URL rozšířené možnosti a funkce. Generování adres URL využívá směrování a dokáže generovat a kódovat parametry v závislosti na tom, jak je trasa definovaná v cílové cestě.

Generování adres URL pro stránky podporuje relativní názvy. Následující tabulka ukazuje, jaká indexová stránka se vybere při použití různých parametrů RedirectToPage v souboru 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") a RedirectToPage("../Index") jsou relativní názvy. Parametr RedirectToPage se za účelem určení názvu cílové stránky kombinuje s cestou k aktuální stránce.

Odkazování pomocí relativních názvů je užitečné při vytváření webů se složitou strukturou. Pokud se k propojení mezi stránkami ve složce používají relativní názvy:

  • Přejmenování složky neporuší relativní odkazy.
  • Odkazy se neporuší, protože nezahrnují název složky.

Pokud chcete provést přesměrování na stránku v jiné oblasti, zadejte oblast:

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

Další informace najdete v tématech Oblasti v ASP.NET Core a Konvence směrování a aplikací Razor Pages v ASP.NET Core.

Atribut ViewData

Pomocí třídy ViewDataAttribute je možné na stránku předat data. Hodnoty vlastností s atributem [ViewData] se uchovávají v třídě ViewDataDictionary, ze které se také načítají.

V následujícím příkladu třída AboutModel používá atribut [ViewData] u vlastnosti Title:

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

    public void OnGet()
    {
    }
}

Na stránce About můžete k vlastnosti Title přistupovat jako k vlastnosti modelu:

<h1>@Model.Title</h1>

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

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

TempData

ASP.NET Core zpřístupňuje vlastnost TempData. Tato vlastnost zajišťuje uchovávání dat, dokud se nepřečtou. Ke zkoumání dat, aniž by došlo k jejich odstranění, je možné použít metody Keep a Peek. Vlastnost TempData je užitečná pro přesměrování, kdy se data vyžadují pro více než jeden požadavek.

Následující kód nastaví hodnotu Message s použitím vlastnosti 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 souboru Pages/Customers/Index.cshtml zobrazí hodnotu Message s použitím vlastnosti TempData.

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

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

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

Další informace najdete v části TempData.

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

Následující stránka vygeneruje kód pro dvě obslužné rutiny s použitím obslužné rutiny značky asp-page-handler:

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

Formulář ve výše uvedeném příkladu obsahuje dvě tlačítka pro odeslání, z nichž každé používá obslužnou rutinu FormActionTagHelper k odeslání formuláře na jinou adresu URL. Atribut asp-page-handler doplňuje atribut asp-page. Atribut asp-page-handler vygeneruje adresy URL, které se odešlou do všech metod obslužných rutin definovaných na stránce. Atribut asp-page není zadaný, 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();
        }
    }
}

Ve výše uvedeném kódu se používají pojmenované metody obslužných rutin. Názvy pojmenovaných metod obslužných rutin se vytvářejí z textu v názvu mezi On<HTTP Verb> a Async (pokud je k dispozici). Ve výše uvedeném příkladu jsou na stránce metody OnPostJoinListAsync a OnPostJoinListUCAsync. Po odebrání OnPost a Async jsou názvy obslužných rutin JoinList a JoinListUC.

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

Ve výše uvedeném kódu se pro odesílání do metody OnPostJoinListAsync používá cesta URL https://localhost:5001/Customers/CreateFATH?handler=JoinList. Pro odesílání do metody OnPostJoinListUCAsync se používá cesta URL https://localhost:5001/Customers/CreateFATH?handler=JoinListUC.

Vlastní trasy

Direktiva @page umožňuje:

  • Zadat vlastní trasu ke stránce. Například pomocí direktivy @page "/Some/Other/Path" můžete nastavit trasu ke stránce About na /Some/Other/Path.
  • Připojit segmenty k výchozí trase stránky. Například pomocí direktivy @page "item" můžete do výchozí trasy stránky přidat segment item.
  • Připojit parametry k výchozí trase stránky. Například při použití direktivy @page "{id}" se může pro stránku vyžadovat parametr ID (id).

Podporuje se relativní cesta vzhledem ke kořenovému adresáři určená znakem tildy (~) na začátku trasy. Například trasa @page "~/Some/Other/Path" je stejná jako @page "/Some/Other/Path".

Pokud se vám nelíbí řetězec dotazu ?handler=JoinList v adrese URL, změňte trasu tak, že název obslužné rutiny umístíte do části adresy URL s cestou. Trasu můžete upravit přidáním šablony trasy v dvojitých uvozovkách za direktivu @page.

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

Ve výše uvedeném kódu se pro odesílání do metody OnPostJoinListAsync používá cesta URL https://localhost:5001/Customers/CreateFATH/JoinList. Pro odesílání do metody OnPostJoinListUCAsync se používá cesta URL https://localhost:5001/Customers/CreateFATH/JoinListUC.

Symbol ? za parametrem handler znamená, že je tento parametr trasy volitelný.

Umístění souborů JavaScriptu (JS)

Umístění souborů JavaScriptu (JS) pro stránky a zobrazení je pohodlný způsob, jak uspořádat skripty v aplikaci.

Soubory JS umístěte společně s využitím následujících konvencí přípon názvů souborů:

  • Stránky aplikací Razor Pages a zobrazení aplikací MVC: .cshtml.js. Příklady:
    • Pages/Index.cshtml.js pro stránku Index aplikace Razor Pages v Pages/Index.cshtml
    • Views/Home/Index.cshtml.js pro zobrazení Index aplikace MVC v Views/Home/Index.cshtml

Společně umístěné soubory JS jsou veřejně adresovatelné pomocí cesty k souborům v projektu:

  • Stránky a zobrazení ze souboru kompletovaných skriptů v aplikaci:

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

    • Zástupný symbol {PATH} je cesta ke stránce, zobrazení nebo komponentě.
    • Zástupný symbol {PAGE, VIEW, OR COMPONENT} je příslušná stránka, zobrazení nebo komponenta.
    • Zástupný symbol {EXTENSION} odpovídá rozšíření stránky, zobrazení nebo komponenty, buď razor, nebo cshtml.

    Příklad Razor Pages:

    Soubor JS pro stránku Index je umístěný ve složce Pages (Pages/Index.cshtml.js) vedle stránky Index (Pages/Index.cshtml). Na stránce Index se na skript odkazuje v cestě k složce Pages:

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

Výchozí rozložení Pages/Shared/_Layout.cshtml je možné nakonfigurovat tak, aby zahrnovalo kompletované JS soubory, což eliminuje nutnost konfigurovat jednotlivé stránky:

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

Stažení ukázky používá předchozí fragment kódu k zahrnutí kompletovaných JS souborů do výchozího rozložení.

Když je aplikace publikovaná, architektura automaticky přesune skript do webového kořenového adresáře. V předchozím příkladu se skript přesune do bin\Release\{TARGET FRAMEWORK MONIKER}\publish\wwwroot\Pages\Index.cshtml.js, kde zástupný symbol {TARGET FRAMEWORK MONIKER} je moniker cílové architektury (TFM). Nevyžaduje se žádná změna relativní adresy URL na stránce Index.

Když je aplikace publikovaná, architektura automaticky přesune skript do webového kořenového adresáře. V předchozím příkladu se skript přesune do bin\Release\{TARGET FRAMEWORK MONIKER}\publish\wwwroot\Components\Pages\Index.razor.js, kde zástupný symbol {TARGET FRAMEWORK MONIKER} je moniker cílové architektury (TFM). Nevyžaduje se žádná změna relativní adresy URL v komponentě Index.

  • Skripty poskytované knihovnou tříd Razor (RCL):

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

    • Zástupný symbol {PACKAGE ID} je identifikátor balíčku RCL (nebo název knihovny tříd, na kterou aplikace odkazuje).
    • Zástupný symbol {PATH} je cesta ke stránce, zobrazení nebo komponentě. Pokud je komponenta Razor umístěná v kořenovém adresáři knihovny RCL, segment cesty není zahrnutý.
    • Zástupný symbol {PAGE, VIEW, OR COMPONENT} je příslušná stránka, zobrazení nebo komponenta.
    • Zástupný symbol {EXTENSION} odpovídá rozšíření stránky, zobrazení nebo komponenty, buď razor, nebo cshtml.

Pokročilá konfigurace a upřesňující nastavení

Pro většinu aplikací se konfigurace a nastavení v následujících částech nevyžadují.

Pokud chcete konfigurovat upřesňující nastavení použijte přetížení AddRazorPages, které konfiguruje objekt 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();

Pomocí objektu RazorPagesOptions můžete pro stránky nastavit kořenový adresář nebo přidat konvence modelu aplikace. Další informace o konvencích najdete v tématu Konvence autorizace Razor Pages.

Pokud chcete předkompilovat zobrazení, projděte si téma Kompilace zobrazení Razor.

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

Ve výchozím nastavení je kořenovým adresářem Razor Pages adresář /Pages. Pokud chcete určit, že se vaše stránky Razor Pages nacházejí v kořenovém adresáři obsahu (ContentRootPath) aplikace, přidejte metodu WithRazorPagesAtContentRoot:

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 se stránky Razor Pages nacházejí ve vlastním kořenovém adresáři

Pokud chcete určit, že se stránky Razor Pages nacházejí ve vlastním kořenovém adresáři v rámci aplikace, přidejte metodu WithRazorPagesRoot (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

Vytvoření projektu Razor Pages

Podrobné pokyny k vytvoření projektu Razor Pages najdete v tématu Začínáme s Razor Pages.

Razor Pages

Razor Pages se povoluje v souboru 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();
        });
    }
}

Podívejte se například na základní stránku:

@page

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

Výše uvedený kód se velmi podobá souboru zobrazení Razor, který se používá v aplikacích ASP.NET Core s kontrolery a zobrazeními. Liší se v direktivě @page. Direktiva @page ze souboru udělá akci MVC – to znamená, že bude zpracovávat požadavky přímo, aniž by procházely kontrolerem. Direktiva @page musí být první direktivou Razor na stránce. Direktiva @page ovlivňuje chování dalších konstrukcí Razor. Názvy souborů Razor Pages mají příponu .cshtml.

V následujících dvou souborech je ukázka podobné stránky s použitím třídy PageModel. Soubor Pages/Index2.cshtml:

@page
@using RazorPagesIntro.Pages
@model Index2Model

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

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

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

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

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

Podle konvence má soubor třídy PageModel stejný název jako soubor stránky Razor s příponou .cs. Například výše uvedená stránka Razor se nachází v souboru Pages/Index2.cshtml. Soubor obsahující třídu PageModel má název Pages/Index2.cshtml.cs.

Přidružení cest URL ke stránkám se určuje podle umístění stránky v systému souborů. Následující tabulka ukazuje cestu ke stránce Razor 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á soubory Razor Pages ve složce Pages.
  • Pokud adresa URL neobsahuje žádnou stránku, výchozí stránka je Index.

Napsání základního formuláře

Model Razor Pages je navržený tak, aby při vytváření aplikace usnadňoval implementaci běžných modelů používaných ve webových prohlížečích. Vazba modelu, pomocné rutiny značek a pomocné rutiny HTML prostě fungují s vlastnostmi definovanými v třídě stránky Razor. Podívejte se například na stránku, která pro model Contact implementuje základní kontaktní formulář:

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

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

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 zobrazení Pages/Create.cshtml:

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Stránka má metodu obslužné OnPostAsync rutiny, která se spouští na POST žádostech (když uživatel publikuje formulář). Je možné přidat metody obslužných událostí pro jakékoli příkazy HTTP. Nejběžnější obslužné rutiny jsou:

  • OnGet pro inicializaci stavu potřebného pro stránku. Ve výše uvedeném kódu metoda OnGet zobrazí stránku Razor CreateModel.cshtml.
  • 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. Výše uvedený kód je pro Razor Pages typický.

Pokud máte zkušenosti s aplikacemi ASP.NET využívajícími kontrolery a zobrazení:

  • Kód metody OnPostAsync ve výše uvedeném příkladu se podobá typickému kódu kontroleru.
  • Většina primitiv MVC, jako jsou vazba modelu, ověřování a výsledky akcí, funguje v Razor Pages stejně jako u kontrolerů.

Výše uvedená metoda OnPostAsync:

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

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

    return RedirectToPage("./Index");
}

Základní tok metody OnPostAsync:

Zkontroluje, jestli nedošlo k chybám ověřování.

  • Pokud nedošlo k žádným chybám, uloží data a provede přesměrování.
  • Pokud došlo k chybám, znovu zobrazí stránku 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 zobrazení Pages/Create.cshtml:

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

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

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

Vykreslený kód HTML ze souboru 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>

Ve výše uvedeném kódu se po odeslání formuláře stane následující:

  • V případě platných dat:

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

      • Je výsledek akce.
      • Je metoda podobná metodám RedirectToAction nebo RedirectToRoute (které se používají v kontrolerech a zobrazeních).
      • Je metoda přizpůsobená pro stránky. Ve výše uvedené ukázce provádí přesměrování na kořenovou indexovou stránku (/Index). Metoda RedirectToPage je podrobně popsaná v části Generování adres URL pro stránky.
  • V případě chyb ověřování předaných na server:

    • Metoda obslužné rutiny OnPostAsync zavolá metodu obslužné rutiny Page. Page vrací instanci PageResult. Vrácení objektu Page se podobá tomu, jak akce v kontrolerech vrací objekt View. Výchozí návratový typ metody obslužné rutiny je PageResult. Metoda obslužné rutiny, která vrátí hodnotu void, vykreslí stránku.
    • Ve výše uvedeném příkladu odeslání formuláře bez jakékoli hodnoty způsobí, že ModelState.IsValid vrátí hodnotu false. V této ukázce se v klientovi nezobrazí žádné chyby ověřování. Zpracování chyb ověřování se věnujeme 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");
    }
    
  • V případě detekce chyb ověřování při ověřování na straně klienta:

    • Data se neodešlou na server.
    • Ověřování na straně klienta se věnujeme dále v tomto dokumentu.

Vlastnost Customer pro přihlášení k vazbě modelu používá atribut [BindProperty]:

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

Atribut [BindProperty] by se neměl používat u modelů obsahujících vlastnosti, které by klient neměl měnit. Další informace najdete v části Útoky typu overpost.

Razor Pages ve výchozím nastavení váže vlastnosti pouze k jiným příkazům než GET. Díky vazbě na vlastnosti odpadá nutnost psát kód pro převod dat HTTP na typ modelu. Vazba snižuje množství kódu díky tomu, že se k vykreslení polí formuláře (<input asp-for="Customer.Name">) a příjmu vstupu používá stejná vlastnost.

Upozorňující

Z bezpečnostních důvodů musíte vyjádřit souhlas s vazbou dat požadavků GET na vlastnosti modelu stránky. Před mapováním uživatelského vstupu na vlastnosti tento vstup ověřte. Vyjádření souhlasu s vazbou požadavků GET je užitečné při řešení scénářů, které se spoléhají na řetězec dotazu nebo hodnoty trasy.

Pokud chcete vytvořit vazbu vlastnosti na požadavky GET, nastavte vlastnost SupportsGet atributu [BindProperty] na hodnotu true:

[BindProperty(SupportsGet = true)]

Další informace najdete ve videu Přehled novinek v komunitě ASP.NET Core: Diskuze k vazbě požadavků GET (YouTube).

Projděte si soubor zobrazení Pages/Create.cshtml:

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

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

<form method="post">
    Name:
    <input asp-for="Customer.Name" />
    <input type="submit" />
</form>
  • V předchozím kódu pomocné rutina <input asp-for="Customer.Name" /> vstupní značky sváže element HTML <input> s výrazem Customer.Name modelu.
  • Direktiva @addTagHelper zpřístupňuje pomocné rutiny značek.

Stránka home

Index.cshtmlhome je 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á třída PageModel (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í kód:

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

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

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

<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í v HTML, jeho atribut formaction obsahuje parametry pro:

  • ID kontaktu zákazníka zadané atributem asp-route-id
  • Obslužnou rutinu handler zadanou atributem asp-page-handler

Při výběru tohoto tlačítka se na server odešle požadavek POST formuláře. Podle konvence se název metody obslužné rutiny vybírá na základě hodnoty parametru handler ve schématu OnPost[handler]Async.

Vzhledem k tomu, že parametr handler má v tomto příkladu hodnotu delete, ke zpracování požadavku POST se použije metoda obslužné rutiny OnPostDeleteAsync. Pokud je atribut asp-page-handler nastavený na jinou hodnotu, například remove, vybere se metoda obslužné rutiny s názvem OnPostRemoveAsync.

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:

  • Získá z řetězce dotazu hodnotu id.
  • Pomocí metody FindAsync odešle do databáze dotaz na kontakt zákazníka.
  • Pokud se kontakt zákazníka najde, odebere se a databáze se aktualizuje.
  • Zavolá metodu RedirectToPage, která provede přesměrování na kořenovou indexovou stránku (/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í směrování "{id:int}" stránce říká, že má přijímat požadavky na stránku, které obsahují data trasy typu int. Pokud požadavek na stránku neobsahuje data trasy, která je možné převést na hodnotu typu int, modul runtime vrátí chybu HTTP 404 (Nenalezeno). Pokud chcete nastavit ID jako volitelné, připojte k omezení trasy symbol ?:

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

Pravidla ověřování:

  • Zadávají se deklarativně v třídě modelu.
  • Vynucují se v rámci celé aplikace.

Obor názvů System.ComponentModel.DataAnnotations nabízí sadu předdefinovaných atributů ověřování, které je možné deklarativně použít na třídu nebo vlastnost. Obor názvů DataAnnotations obsahuje také atributy formátování, jako je [DataType], které pomáhají s formátováním a neposkytují žádné ověřování.

Podívejte se například na model Customer:

using System.ComponentModel.DataAnnotations;

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

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

Používá se následující soubor zobrazení Create.cshtml:

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

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

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

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

Předchozí kód:

  • Vkládá knihovnu jQuery a ověřovací skripty jQuery.

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

    • Ověřování na straně klienta
    • Vykreslování chyb ověřování
  • Generuje 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>
    

Při odeslání formuláře pro vytvoření bez hodnoty názvu se ve formuláři zobrazí chybová zpráva Pole Name je povinné. Pokud je v klientovi povolený JavaScript, v prohlížeči se zobrazí chyba, aniž by se formulář odeslal na server.

Atribut [StringLength(10)] ve vykresleném kódu HTML vygeneruje atribut data-val-length-max="10". Atribut data-val-length-max brání v prohlížečích v zadání více znaků, než je zadaná maximální délka. Pokud se k úpravě a opětovnému odeslání použije nástroj typu Fiddler:

  • Pokud je název delší než 10 znaků:
  • Vrátí se chybová zpráva Pole Name musí obsahovat řetězec o maximální délce 10 znaků.

Podívejte se například na následující model Movie:

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ěřování určují chování, které se má vynucovat u vlastností modelu, na které se použijí:

  • Atributy Required a MinimumLength značí, že vlastnost musí mít nějakou hodnotu, ale uživateli nic nebrání v zadání prázdných znaků, které tímto ověřením projdou.

  • Atribut RegularExpression slouží k omezení množiny znaků, které je možné zadat. Pro vlastnost Genre ve výše uvedeném kódu platí následující:

    • Může obsahovat pouze písmena.
    • Počáteční písmeno musí být velké. Nemůže obsahovat prázdné znaky, číslice ani speciální znaky.
  • Regulární výraz (RegularExpression) u vlastnosti Rating:

    • Vyžaduje, aby prvním znakem bylo velké písmeno.
    • Na dalších místech povoluje speciální znaky a číslice. PG-13 je platná hodnota pro vlastnost Rating, ale ne pro vlastnost Genre.
  • Atribut Range omezuje hodnotu v konkrétním rozsahu.

  • Atribut StringLength nastavuje maximální délku řetězcové vlastnosti a volitelně i její minimální délku.

  • Typy hodnot (například decimal, int, float, DateTime) jsou ze své podstaty povinné a nevyžadují atribut [Required].

Na stránce pro vytvoření pro model Movie se v případě neplatných hodnot zobrazí chyby:

Formulář zobrazení Movie s několika chybami ověřování jQuery na straně klienta

Další informace naleznete v tématu:

Zpracování požadavků HEAD s využitím záložní obslužné rutiny OnGet

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

Pro požadavky HEAD se obvykle vytváří a volá obslužná rutina OnHead:

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

Pokud obslužná rutina OnHead není definovaná, Razor Pages se vrátí k volání obslužné rutiny OnGet.

XSRF/CSRF a Razor Pages

Stránky Razor jsou chráněné ověřováním proti padělkům. Obslužná rutina značky form vkládá do elementů formulářů HTML tokeny proti padělkům.

Používání rozložení, částečných zobrazení, šablon a obslužných rutin značek s Razor Pages

Stránky fungují se všemi funkcemi zobrazovacího modulu Razor. Rozložení, částečná zobrazení, šablony, obslužné rutiny značek a soubory _ViewStart.cshtml a _ViewImports.cshtml fungují stejně jako v běžných zobrazeních Razor.

Pojďme tuto stránku zpřehlednit s využitím některých z těchto funkcí.

Přidejte stránku rozložení do souboru 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í:

  • Řídí rozložení každé stránky (pokud stránka rozložení výslovně neodmítne).
  • Importuje struktury HTML, jako jsou JavaScript nebo šablony stylů.
  • Při zavolání metody @RenderBody() vykreslí obsah stránky Razor.

Další informace najdete v tématu věnovaném stránce rozložení.

Hodnota Layout se nastavuje v souboru Pages/_ViewStart.cshtml:

@{
    Layout = "_Layout";
}

Rozložení se nachází ve složce Pages/Shared. Stránky hierarchicky hledají další zobrazení (rozložení, šablony, částečná zobrazení) počínaje stejnou složkou, ve které se nachází aktuální stránka. Rozložení ve složce Pages/Shared je možné použít na jakékoli stránce Razor ve složce Pages.

Soubor rozložení by se měl nacházet ve složce Pages/Shared.

Doporučujeme neumisťovat soubor rozložení do složky Views/Shared. Složka Views/Shared se používá pro model zobrazení MVC. Stránky Razor se mají spoléhat na hierarchii složek, a ne na konvence cest.

Vyhledávání zobrazení na stránce Razor zahrnuje i složku Pages. Rozložení, šablony a částečná zobrazení používaná s kontrolery MVC a běžnými zobrazeními Razor prostě fungují.

Přidejte soubor Pages/_ViewImports.cshtml:

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

Direktivě @namespace se věnujeme dále v tomto kurzu. Direktiva @addTagHelper na všech stránkách ve složce Pages zpřístupní předdefinované obslužné rutiny značek.

Nastavená direktiva @namespace na stránce:

@page
@namespace RazorPagesIntro.Pages.Customers

@model NameSpaceModel

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

Direktiva @namespace nastaví pro stránku obor názvů. Direktiva @model nemusí obsahovat obor názvů.

Pokud soubor _ViewImports.cshtml obsahuje direktivu @namespace, zadaný obor názvů bude představovat předponu vygenerovaného oboru názvů na stránce, která importuje direktivu @namespace. Vygenerovaný rest obor 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.

Například třída PageModel v souboru 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.

V souboru Pages/_ViewImports.cshtml se nastaví následující obor názvů:

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

Vygenerovaný obor názvů pro stránku Razor Pages/Customers/Edit.cshtml bude stejný jako obor názvů třídy PageModel.

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

Podívejte se například na soubor zobrazení Pages/Create.cshtml:

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

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

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

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

Aktualizovaný soubor zobrazení Pages/Create.cshtml se souborem _ViewImports.cshtml a výše uvedeným souborem rozložení:

@page
@model CreateModel

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

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

Ve výše uvedeném kódu soubor _ViewImports.cshtml importoval obor názvů a obslužné rutiny značek. Soubor rozložení importoval soubory JavaScriptu.

Úvodní projekt Razor Pages obsahuje soubor Pages/_ValidationScriptsPartial.cshtml, který aktivuje ověřování 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

Na stránce Create uvedené výše se používá metoda 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 složek a souborů:

  • /Pages

    • Index.cshtml

    • Privacy.cshtml

    • /Customers

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

Stránky Pages/Customers/Create.cshtml a Pages/Customers/Edit.cshtml se v případě úspěchu přesměrují na stránku Pages/Customers/Index.cshtml. Řetězec ./Index je relativní název stránky, který se používá pro přístup k předchozí stránce. Slouží ke generování adres URL na stránku Pages/Customers/Index.cshtml. Příklad:

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

Absolutní název stránky /Index slouží ke generování adres URL na stránku Pages/Index.cshtml. Příklad:

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

Název stránky představuje cestu ke stránce z kořenové složky /Pages včetně počátečního lomítka / (například /Index). Výše uvedené ukázky generování adres URL nabízejí oproti pevnému zakódování adresy URL rozšířené možnosti a funkce. Generování adres URL využívá směrování a dokáže generovat a kódovat parametry v závislosti na tom, jak je trasa definovaná v cílové cestě.

Generování adres URL pro stránky podporuje relativní názvy. Následující tabulka ukazuje, jaká indexová stránka se vybere při použití různých parametrů RedirectToPage v souboru 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") a RedirectToPage("../Index") jsou relativní názvy. Parametr RedirectToPage se za účelem určení názvu cílové stránky kombinuje s cestou k aktuální stránce.

Odkazování pomocí relativních názvů je užitečné při vytváření webů se složitou strukturou. Pokud se k propojení mezi stránkami ve složce používají relativní názvy:

  • Přejmenování složky neporuší relativní odkazy.
  • Odkazy se neporuší, protože nezahrnují název složky.

Pokud chcete provést přesměrování na stránku v jiné oblasti, zadejte oblast:

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

Další informace najdete v tématech Oblasti v ASP.NET Core a Konvence směrování a aplikací Razor Pages v ASP.NET Core.

Atribut ViewData

Pomocí třídy ViewDataAttribute je možné na stránku předat data. Hodnoty vlastností s atributem [ViewData] se uchovávají v třídě ViewDataDictionary, ze které se také načítají.

V následujícím příkladu třída AboutModel používá atribut [ViewData] u vlastnosti Title:

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

    public void OnGet()
    {
    }
}

Na stránce About můžete k vlastnosti Title přistupovat jako k vlastnosti modelu:

<h1>@Model.Title</h1>

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

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

TempData

ASP.NET Core zpřístupňuje vlastnost TempData. Tato vlastnost zajišťuje uchovávání dat, dokud se nepřečtou. Ke zkoumání dat, aniž by došlo k jejich odstranění, je možné použít metody Keep a Peek. Vlastnost TempData je užitečná pro přesměrování, kdy se data vyžadují pro více než jeden požadavek.

Následující kód nastaví hodnotu Message s použitím vlastnosti 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 souboru Pages/Customers/Index.cshtml zobrazí hodnotu Message s použitím vlastnosti TempData.

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

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

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

Další informace najdete v části TempData.

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

Následující stránka vygeneruje kód pro dvě obslužné rutiny s použitím obslužné rutiny značky asp-page-handler:

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

Formulář ve výše uvedeném příkladu obsahuje dvě tlačítka pro odeslání, z nichž každé používá obslužnou rutinu FormActionTagHelper k odeslání formuláře na jinou adresu URL. Atribut asp-page-handler doplňuje atribut asp-page. Atribut asp-page-handler vygeneruje adresy URL, které se odešlou do všech metod obslužných rutin definovaných na stránce. Atribut asp-page není zadaný, 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();
        }
    }
}

Ve výše uvedeném kódu se používají pojmenované metody obslužných rutin. Názvy pojmenovaných metod obslužných rutin se vytvářejí z textu v názvu mezi On<HTTP Verb> a Async (pokud je k dispozici). Ve výše uvedeném příkladu jsou na stránce metody OnPostJoinListAsync a OnPostJoinListUCAsync. Po odebrání OnPost a Async jsou názvy obslužných rutin JoinList a JoinListUC.

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

Ve výše uvedeném kódu se pro odesílání do metody OnPostJoinListAsync používá cesta URL https://localhost:5001/Customers/CreateFATH?handler=JoinList. Pro odesílání do metody OnPostJoinListUCAsync se používá cesta URL https://localhost:5001/Customers/CreateFATH?handler=JoinListUC.

Vlastní trasy

Direktiva @page umožňuje:

  • Zadat vlastní trasu ke stránce. Například pomocí direktivy @page "/Some/Other/Path" můžete nastavit trasu ke stránce About na /Some/Other/Path.
  • Připojit segmenty k výchozí trase stránky. Například pomocí direktivy @page "item" můžete do výchozí trasy stránky přidat segment item.
  • Připojit parametry k výchozí trase stránky. Například při použití direktivy @page "{id}" se může pro stránku vyžadovat parametr ID (id).

Podporuje se relativní cesta vzhledem ke kořenovému adresáři určená znakem tildy (~) na začátku trasy. Například trasa @page "~/Some/Other/Path" je stejná jako @page "/Some/Other/Path".

Pokud se vám nelíbí řetězec dotazu ?handler=JoinList v adrese URL, změňte trasu tak, že název obslužné rutiny umístíte do části adresy URL s cestou. Trasu můžete upravit přidáním šablony trasy v dvojitých uvozovkách za direktivu @page.

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

Ve výše uvedeném kódu se pro odesílání do metody OnPostJoinListAsync používá cesta URL https://localhost:5001/Customers/CreateFATH/JoinList. Pro odesílání do metody OnPostJoinListUCAsync se používá cesta URL https://localhost:5001/Customers/CreateFATH/JoinListUC.

Symbol ? za parametrem handler znamená, že je tento parametr trasy volitelný.

Pokročilá konfigurace a upřesňující nastavení

Pro většinu aplikací se konfigurace a nastavení v následujících částech nevyžadují.

Pokud chcete konfigurovat upřesňující nastavení použijte přetížení AddRazorPages, které konfiguruje objekt RazorPagesOptions:

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

Pomocí objektu RazorPagesOptions můžete pro stránky nastavit kořenový adresář nebo přidat konvence modelu aplikace. Další informace o konvencích najdete v tématu Konvence autorizace Razor Pages.

Pokud chcete předkompilovat zobrazení, projděte si téma Kompilace zobrazení Razor.

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

Ve výchozím nastavení je kořenovým adresářem Razor Pages adresář /Pages. Pokud chcete určit, že se vaše stránky Razor Pages nacházejí v kořenovém adresáři obsahu (ContentRootPath) aplikace, přidejte metodu WithRazorPagesAtContentRoot:

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

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

Pokud chcete určit, že se stránky Razor Pages nacházejí ve vlastním kořenovém adresáři v rámci aplikace, přidejte metodu WithRazorPagesRoot (zadejte relativní cestu):

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

Další materiály