Anteckning
Åtkomst till den här sidan kräver auktorisering. Du kan prova att logga in eller ändra kataloger.
Åtkomst till den här sidan kräver auktorisering. Du kan prova att ändra kataloger.
Av Rick Anderson, Dave Brock och Kirk Larkin
Varning
Den här versionen av ASP.NET Core stöds inte längre. Mer information finns i supportpolicyn för .NET och .NET Core. För den nuvarande utgåvan, se .NET 9-versionen av den här artikeln .
Viktigt!
Den här informationen gäller en förhandsversionsprodukt som kan ändras avsevärt innan den släpps kommersiellt. Microsoft lämnar inga garantier, uttryckliga eller underförstådda, med avseende på den information som tillhandahålls här.
För den nuvarande utgåvan, se .NET 9-versionen av den här artikeln .
Razor Sidor kan göra det enklare och mer produktivt att koda sidfokuserade scenarier än att använda kontrollanter och vyer.
Om du letar efter en självstudiekurs som använder metoden Modell–View-Controller kan du läsa Komma igång med ASP.NET Core MVC.
Det här dokumentet ger en introduktion till Razor Sidor. Det är inte en steg för steg-handledning. Om du tycker att vissa av avsnitten är för avancerade kan du läsa Komma igång med Razor Sidor. En översikt över ASP.NET Core finns i Introduktion till ASP.NET Core.
Förutsättningar
- Visual Studio 2022 med arbetsuppgiften ASP.NET och webbutveckling.
- .NET 6 SDK
Skapa ett Razor pages-projekt
Razor sidor
Razor Sidor är aktiverade i 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();
I koden ovan:
- AddRazorPages lägger till tjänster för Razor sidor i appen.
- MapRazorPages lägger till slutpunkter för Razor sidor i IEndpointRouteBuilder.
Överväg en grundläggande sida:
@page
<h1>Hello, world!</h1>
<h2>The time on the server is @DateTime.Now</h2>
Föregående kod ser ut ungefär som en Razor vyfil som används i en ASP.NET Core-app med kontrollanter och vyer. Det som gör det @page
annorlunda är direktivet.
@page
gör filen till en MVC-åtgärd, vilket innebär att den hanterar begäranden direkt, utan att gå igenom en kontrollant.
@page
måste vara det första Razor direktivet på en sida.
@page
påverkar beteendet hos andra Razor konstruktioner.
Razor Sidfilnamn har ett .cshtml
suffix.
En liknande sida, med hjälp av en PageModel
klass, visas i följande två filer. Filen Pages/Index2.cshtml
:
@page
@using RazorPagesIntro.Pages
@model Index2Model
<h2>Separate page model</h2>
<p>
@Model.Message
</p>
Sidmodellen 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 }";
}
}
}
Enligt konvention har PageModel
-klassfilen samma namn som Razor-sidfilen med .cs
bifogat. Till exempel är Razorföregående Pages/Index2.cshtml
sida . Filen som innehåller PageModel
klassen heter Pages/Index2.cshtml.cs
.
Associationerna för URL-sökvägar till sidor bestäms av sidans plats i filsystemet. I följande tabell visas en Razor sidsökväg och matchande URL:
Filnamn och sökväg | matchande URL |
---|---|
/Pages/Index.cshtml |
/ eller /Index |
/Pages/Contact.cshtml |
/Contact |
/Pages/Store/Contact.cshtml |
/Store/Contact |
/Pages/Store/Index.cshtml |
/Store eller /Store/Index |
Anteckningar:
- Körningen söker Razor efter Pages-filer i mappen Pages som standard.
-
Index
är standardsidan när en URL inte innehåller en sida.
Skriva ett grundläggande formulär
Razor Sidor är utformade för att göra vanliga mönster som används med webbläsare enkla att implementera när du skapar en app.
Modellbindning, Tag Helpers och HTML-hjälpfunktioner fungerar med de egenskaper som definierats i en Razor sidklass. Överväg en sida som implementerar ett grundläggande "kontakta oss"-formulär för Contact
modellen:
För exemplen i det här dokumentet initieras DbContext
i Program.cs.
För minnesdatabasen krävs NuGet-paketet 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();
Datamodellen:
using System.ComponentModel.DataAnnotations;
namespace RazorPagesContacts.Models
{
public class Customer
{
public int Id { get; set; }
[Required, StringLength(10)]
public string? Name { get; set; }
}
}
Databas-kontexten:
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>();
}
}
Filen för vy 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>
Sidmodellen 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");
}
}
Enligt konvention benämns PageModel
-klassen <PageName>Model
och finns i samma namnområde som sidan.
Klassen PageModel
tillåter separation av logiken för en sida från presentationen. Den definierar sidhanterare för begäranden som skickas till sidan och de data som används för att återge sidan. Den här separationen tillåter:
- Hantering av sidberoenden via dependency injection.
- Enhetstestning
Sidan har en OnPostAsync
hanteringsmetod som körs på POST
begäranden (när en användare publicerar formuläret). Du kan lägga till hanteringsmetoder för alla HTTP-verb. De vanligaste hanterarna är:
-
OnGet
för att initiera det tillstånd som behövs för sidan. I den föregående koden visarOnGet
-metodenCreate.cshtml
Razor-sidan. -
OnPost
för att hantera formulärinlämningar.
Namngivningssuffixet Async
är valfritt men används ofta av konventionen för asynkrona funktioner. Föregående kod är typisk för Razor Sidor.
Om du är bekant med ASP.NET-applikationer med kontroller och vyer:
- Koden
OnPostAsync
i föregående exempel ser ut ungefär som vanlig styrenhetskod. - De flesta av MVC-primitiverna som modellbindning, validering och åtgärdsresultat fungerar på samma sätt med kontrollanter och Razor sidor.
Föregående OnPostAsync
metod:
[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");
}
Det grundläggande flödet av OnPostAsync
:
Sök efter verifieringsfel.
- Om det inte finns några fel sparar du data och omdirigerar.
- Om det finns fel visar du sidan igen med valideringsmeddelanden. I många fall identifieras verifieringsfel på klienten och skickas aldrig till servern.
Filen för vy 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>
Den renderade HTML-koden från 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>
I föregående kod publicerar du formuläret:
Med giltiga data:
Hanteringsmetoden
OnPostAsync
anropar RedirectToPage hjälpmetoden.RedirectToPage
returnerar en instans av RedirectToPageResult.RedirectToPage
:- Är ett åtgärdsresultat.
- Liknar
RedirectToAction
ellerRedirectToRoute
(används i kontrollanter och vyer). - Är anpassad för sidor. I föregående exempel omdirigeras den till rotindexsidan (
/Index
).RedirectToPage
beskrivs i avsnittet URL-generering för sidor .
Med valideringsfel som skickas till servern:
- Hanteringsmetoden
OnPostAsync
anropar Page hjälpmetoden.Page
returnerar en instans av PageResult. Att returneraPage
är likt hur åtgärder i kontroller returnerarView
.PageResult
är standardreturtypen för en hanteringsmetod. En hanteringsmetod som returnerarvoid
återger sidan. - I föregående exempel resulterar publicering av formuläret utan värde i ModelState.IsValid som returnerar false. I det här exemplet visas inga verifieringsfel på klienten. Verifieringsfelhantering beskrivs senare i det här dokumentet.
[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"); }
- Hanteringsmetoden
Med valideringsfel som identifierats av verifiering på klientsidan:
- Data publiceras inte på servern.
- Validering på klientsidan förklaras senare i det här dokumentet.
Egenskapen Customer
använder [BindProperty]
attributet för att välja modellbindning:
[BindProperty]
public Customer? Customer { get; set; }
public async Task<IActionResult> OnPostAsync()
{
if (!ModelState.IsValid)
{
return Page();
}
if (Customer != null) _context.Customer.Add(Customer);
await _context.SaveChangesAsync();
return RedirectToPage("./Index");
}
[BindProperty]
ska inte användas på modeller som innehåller egenskaper som inte ska ändras av klienten. Mer information finns i Överpublicering.
Razor Sidor binder som standard endast egenskaper med icke-verbGET
. Bindning till egenskaper tar bort behovet av att skriva kod för att konvertera HTTP-data till modelltypen. Bindning minskar koden genom att använda samma egenskap för att återge formulärfält (<input asp-for="Customer.Name">
) och acceptera indata.
Varning
Av säkerhetsskäl måste du välja att binda GET
begärandedata till sidmodellegenskaper. Verifiera användarindata innan du mappar den till egenskaper. Att välja bindning GET
är användbart när du hanterar scenarier som förlitar sig på frågesträngar eller vägvärden.
Om du vill binda en egenskap för GET
begäranden anger du [BindProperty]
attributets SupportsGet
egenskap till true
:
[BindProperty(SupportsGet = true)]
Mer information finns i ASP.NET Core Community Standup: Bind på GET-diskussion (YouTube).
Granskning av Pages/Customers/Create.cshtml
vyfilen:
@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>
- I den föregående koden binder hjälpverktyget för indatataggen HTML-elementet
<input asp-for="Customer.Name" />
till modelluttrycket<input>
. -
@addTagHelper
gör Tag Helpers tillgängliga.
Startsidan
Index.cshtml
är startsidan:
@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>
Den associerade PageModel
klassen (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();
}
}
Filen Index.cshtml
innehåller följande markering:
<a asp-page="./Edit" asp-route-id="@contact.Id">Edit</a> |
<a /a>
Anchor Tag Helper använde asp-route-{value}
attributet för att generera en länk till Redigeringssidan. Länken innehåller routningsdata med kontakt-ID:t. Till exempel https://localhost:5001/Edit/1
.
Tagghjälpare gör det möjligt för kod på serversidan att delta i skapandet och återgivningen av HTML-element i Razor filer.
Filen Index.cshtml
innehåller markering för att skapa en borttagningsknapp för varje kundkontakt:
<button type="submit" asp-page-handler="delete" asp-route-id="@contact.Id">delete</button>
Den renderade HTML-koden:
<button type="submit" formaction="/Customers?id=1&handler=delete">delete</button>
När borttagningsknappen återges i HTML innehåller dess formaction parametrar för:
- Kundens kontakt-ID, som anges av attributet
asp-route-id
. -
handler
anges av attributetasp-page-handler
.
När knappen har valts skickas en formulärbegäran POST
till servern. Enligt konventionen väljs namnet på hanteringsmetoden baserat på värdet för parametern handler
enligt schemat OnPost[handler]Async
.
Eftersom handler
är delete
i det här exemplet, används OnPostDeleteAsync
-hanteringsmetoden för att bearbeta POST
-begäran. Om asp-page-handler
är inställt på ett annat värde, till exempel remove
, väljs en hanteringsmetod med namnet 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();
}
OnPostDeleteAsync
-metoden:
- Hämtar
id
från frågesträngen. - Söker i databasen efter kundkontakten med
FindAsync
. - Om kundkontakten hittas tas den bort och databasen uppdateras.
- Anrop RedirectToPage för att omdirigera till rotindexsidan (
/Index
).
Filen 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");}
}
Den första raden innehåller @page "{id:int}"
direktivet. Routningsbegränsningen "{id:int}"
uppmanar sidan att acceptera begäranden till sidan som innehåller int
routningsdata. Om en begäran till sidan inte innehåller routningsdata som kan konverteras till en int
returnerar körningen ett HTTP 404-fel (hittades inte). Om du vill göra ID:t valfritt lägger du till i routningsbegränsningen ?
:
@page "{id:int?}"
Filen 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);
}
}
Validering
Valideringsregler:
- Anges deklarativt i modellklassen.
- Tillämpas överallt i appen.
Namnområdet System.ComponentModel.DataAnnotations innehåller en uppsättning inbyggda valideringsattribut som tillämpas deklarativt på en klass eller egenskap. DataAnnotations innehåller också formateringsattribut som [DataType]
det hjälper till med formatering och ger ingen verifiering.
Tänk på Customer
modellen:
using System.ComponentModel.DataAnnotations;
namespace RazorPagesContacts.Models
{
public class Customer
{
public int Id { get; set; }
[Required, StringLength(10)]
public string? Name { get; set; }
}
}
Använd följande Create.cshtml
visningsfil:
@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>
Föregående kod:
Innehåller jQuery- och jQuery-valideringsskript.
Använder
<div />
och<span />
taghjälparna för att aktivera:- Validering på klientsidan.
- Renderingsfel vid validering.
Genererar följande 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>
Publicering av Skapa-formuläret utan ett namn visar felmeddelandet "Fältet Namn är obligatoriskt" i formuläret. Om JavaScript är aktiverat på klienten visar webbläsaren felet utan att publicera till servern.
Attributet [StringLength(10)]
genererar data-val-length-max="10"
på den renderade HTML-koden.
data-val-length-max
förhindrar att webbläsare anger mer än den angivna maximala längden. Om ett verktyg som Fiddler används för att redigera och spela upp inlägget igen:
- Med ett namn längre än 10 tecken.
- Felmeddelandet "Fältnamnet måste vara en sträng med en maximal längd på 10." returneras.
Tänk på följande Movie
modell:
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; }
}
}
Valideringsattributen anger beteende för att framtvinga de modellegenskaper som de tillämpas på:
Attributen
Required
ochMinimumLength
anger att en egenskap måste ha ett värde, men ingenting hindrar en användare från att ange tomt utrymme för att uppfylla den här valideringen.Attributet
RegularExpression
används för att begränsa vilka tecken som kan matas in. I föregående kod, "Genre":- Får endast använda bokstäver.
- Den första bokstaven måste vara versaler. Blanksteg, siffror och specialtecken tillåts inte.
RegularExpression
"Omdöme":- Kräver att det första tecknet är versaler.
- Tillåter specialtecken och siffror i efterföljande mellanrum. "PG-13" är giltig för en klassificering, men inte för en "Genre".
Attributet
Range
begränsar ett värde till inom ett angivet intervall.Attributet
StringLength
anger den maximala längden för en strängegenskap och eventuellt dess minsta längd.Värdetyper (till exempel
decimal
,int
,float
,DateTime
) är av sig själva nödvändiga och behöver inte attributet[Required]
.
Sidan Skapa för modellen Movie
visar fel med ogiltiga värden:
Mer information finns i:
CSS-isolering
Isolera CSS-format på enskilda sidor, vyer och komponenter för att minska eller undvika:
- Beroenden på globala format som kan vara svåra att underhålla.
- Formatkonflikter i kapslat innehåll.
För att lägga till en CSS-fil som är anpassad för en specifik sida eller vy, placera CSS-formatmallarna i en tillhörande fil med samma namn som den aktuella filen. I följande exempel tillhandahåller en Index.cshtml.css
fil CSS-formatmallar som endast tillämpas på Index.cshtml
sidan eller vyn.
Pages/Index.cshtml.css
(Razor Sidor) eller Views/Index.cshtml.css
(MVC):
h1 {
color: red;
}
CSS-isolering sker vid byggtiden. Ramverket skriver om CSS-väljare för att matcha markering som återges av appens sidor eller vyer. De omskrivna CSS-formaten paketeras och skapas som en statisk resurs, {APP ASSEMBLY}.styles.css
. Platshållaren {APP ASSEMBLY}
är projektets sammansättningsnamn. En länk till de paketerade CSS-formaten placeras i appens layout.
I innehållet i appens <head>
Pages/Shared/_Layout.cshtml
(Razor Sidor) eller Views/Shared/_Layout.cshtml
(MVC), lägg till eller bekräfta att länken till de paketerade CSS-stilmallarna finns:
<link rel="stylesheet" href="~/{APP ASSEMBLY}.styles.css" />
I följande exempel är WebApp
appens sammansättningsnamn :
<link rel="stylesheet" href="WebApp.styles.css" />
Formatmallarna som definieras i en avgränsad CSS-fil tillämpas endast på de renderade resultat från den matchande filen. I föregående exempel står inte css-deklarationer h1
som definierats någon annanstans i appen i konflikt med rubrikformatet Index
. CSS-format kaskad- och ärvningsregler gäller fortfarande för scopade CSS-filer. Format som tillämpas direkt på ett <h1>
-element i Index.cshtml
-filen åsidosätter till exempel den omfångsbestämda CSS-filens format i Index.cshtml.css
.
Anmärkning
För att garantera CSS-formatisolering vid paketering stöds inte import av CSS i Razor kodblock.
CSS-isolering gäller endast för HTML-element. CSS-isolering stöds inte för Tag Helpers.
I den paketerade CSS-filen associeras varje sida, vy eller Razor komponent med en omfångsidentifierare i formatet b-{STRING}
, där {STRING}
platshållaren är en sträng med tio tecken som genereras av ramverket. I följande exempel visas stilen för det föregående elementet <h1>
på Index
sidan i en Razor Pages-app.
/* /Pages/Index.cshtml.rz.scp.css */
h1[b-3xxtam6d07] {
color: red;
}
På sidan Index
där CSS-formatmallen tillämpas från den paketerade filen läggs omfångsidentifieraren till som ett HTML-attribut:
<h1 b-3xxtam6d07>
Identifieraren är unik för en app. Vid bygget skapas ett projektpaket med konventionen {STATIC WEB ASSETS BASE PATH}/Project.lib.scp.css
, där platshållaren {STATIC WEB ASSETS BASE PATH}
är bassökvägen för statiska webbtillgångar.
Om andra projekt används, till exempel NuGet-paket eller Razor klassbibliotek, den paketerade filen:
- Refererar till formatmallarna med css-importer.
- Publiceras inte som en statisk webbtillgång för appen som använder stilarna.
Stöd för CSS-förprocessor
CSS-förprocessorer är användbara för att förbättra CSS-utvecklingen genom att använda funktioner som variabler, kapsling, moduler, mixins och arv. Även om CSS-isolering inte har inbyggt stöd för CSS-förprocessorer som Sass eller Less, är integreringen av CSS-förprocessorer sömlös så länge förprocessorkompileringen sker innan ramverket skriver om CSS-väljare under byggprocessen. Med Visual Studio kan du till exempel konfigurera befintlig förprocessorkompilering som en Before Build-uppgift i Visual Studio Task Runner Explorer.
Många NuGet-paket från tredje part, till exempel AspNetCore.SassCompiler
, kan kompilera SASS/SCSS-filer i början av byggprocessen innan CSS-isoleringen sker, och ingen ytterligare konfiguration krävs.
CSS-isoleringskonfiguration
CSS-isolering tillåter konfiguration för vissa avancerade scenarier, till exempel när det finns beroenden för befintliga verktyg eller arbetsflöden.
Anpassa omfångsidentifierarformat
I det här avsnittet {Pages|Views}
är platshållaren antingen Pages
för Razor Pages-appar eller Views
för MVC-appar.
Som standard använder omfångsidentifierare formatet b-{STRING}
, där {STRING}
platshållaren är en sträng med tio tecken som genereras av ramverket. Om du vill anpassa omfångsidentifierarformatet uppdaterar du projektfilen till ett önskat mönster:
<ItemGroup>
<None Update="{Pages|Views}/Index.cshtml.css" CssScope="custom-scope-identifier" />
</ItemGroup>
I föregående exempel ändrar CSS som genererats för Index.cshtml.css
dess omfångsidentifierare från b-{STRING}
till custom-scope-identifier
.
Använd omfångsidentifierare för att uppnå arv med begränsade CSS-filer. I följande projektfilexempel innehåller en BaseView.cshtml.css
fil vanliga format för vyer. En DerivedView.cshtml.css
fil ärver dessa formatmallar.
<ItemGroup>
<None Update="{Pages|Views}/BaseView.cshtml.css" CssScope="custom-scope-identifier" />
<None Update="{Pages|Views}/DerivedView.cshtml.css" CssScope="custom-scope-identifier" />
</ItemGroup>
Använd jokertecknet (*
) för att dela omfångsidentifierare i flera filer:
<ItemGroup>
<None Update="{Pages|Views}/*.cshtml.css" CssScope="custom-scope-identifier" />
</ItemGroup>
Ändra bassökväg för statiska webbtillgångar
Den avgränsade CSS-filen genereras i appens rotmapp. I projektfilen använder du StaticWebAssetBasePath
egenskapen för att ändra standardsökvägen. I följande exempel placeras den begränsade CSS-filen och resten av programmets resurser på _content
-sökvägen.
<PropertyGroup>
<StaticWebAssetBasePath>_content/$(PackageId)</StaticWebAssetBasePath>
</PropertyGroup>
Inaktivera automatisk paketering
Om du vill välja bort hur ramverket publicerar och läser in begränsade filer vid körning använder du DisableScopedCssBundling
egenskapen . När du använder den här egenskapen ansvarar andra verktyg eller processer för att ta de isolerade CSS-filerna från obj
katalogen och publicera och läsa in dem vid körning:
<PropertyGroup>
<DisableScopedCssBundling>true</DisableScopedCssBundling>
</PropertyGroup>
Razor stöd för klassbibliotek (RCL)
När ett Razor klassbibliotek (RCL) tillhandahåller isolerade format pekar taggens <link>
href
attribut på {STATIC WEB ASSET BASE PATH}/{PACKAGE ID}.bundle.scp.css
, där platshållarna är:
-
{STATIC WEB ASSET BASE PATH}
: Basvägen för de statiska webbtillgångarna. -
{PACKAGE ID}
: Bibliotekets paketidentifierare. Paketidentifieraren är som standard projektets sammansättningsnamn om paketidentifieraren inte anges i projektfilen.
I följande exempel:
- Basvägen för den statiska webbresursen är
_content/ClassLib
. - Klassbibliotekets sammansättningsnamn är
ClassLib
.
Pages/Shared/_Layout.cshtml
(Razor Sidor) eller Views/Shared/_Layout.cshtml
(MVC):
<link href="_content/ClassLib/ClassLib.bundle.scp.css" rel="stylesheet">
Mer information om RCL:er finns i följande artiklar:
- Återanvändbart användargränssnitt för Razor i klassbibliotek med ASP.NET Core
- Förbruka ASP.NET Core Razor-komponenter från ett Razor-klassbibliotek (RCL)
Information om Blazor CSS-isolering finns i ASP.NET Core Blazor CSS-isolering.
Hantera HEAD-begäranden med en OnGet-hanteringsåterställning
HEAD
begäranden gör det möjligt att hämta rubrikerna för en specifik resurs. Till skillnad från GET
begäranden returnerar HEAD
begäranden inte någon svarstext.
Normalt skapas en OnHead
hanterare och anropas för HEAD
begäranden:
public void OnHead()
{
HttpContext.Response.Headers.Add("Head Test", "Handled by OnHead!");
}
Razor Sidor återgår till att anropa OnGet
hanteraren om ingen OnHead
hanterare har definierats.
XSRF/CSRF och Razor sidor
Razor Sidor skyddas av Antiforgery-validering. FormTagHelper infogar antiforgery-token i HTML-formulärelement.
Använda layouter, partiella objekt, mallar och tagghjälpare med Razor sidor
Sidorna fungerar med alla funktioner i Razor vymotorn. Layouter, delar, mallar, Tag Helpers _ViewStart.cshtml
och _ViewImports.cshtml
fungerar på samma sätt som för konventionella Razor vyer.
Låt oss rensa den här sidan genom att dra nytta av några av dessa funktioner.
Lägg till en layout-sida till 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>
- Styr layouten för varje sida (såvida inte sidan väljer bort layouten).
- Importerar HTML-strukturer som JavaScript och formatmallar.
- Innehållet på Razor sidan återges där
@RenderBody()
anropas.
Mer information finns på layoutsidan.
Egenskapen Layout anges i Pages/_ViewStart.cshtml
:
@{
Layout = "_Layout";
}
Layouten finns i mappen Pages/Shared . Sidor letar efter andra vyer (layouter, mallar, partiella objekt) hierarkiskt, med början i samma mapp som den aktuella sidan. En layout i mappen Sidor/Delad kan användas från valfri Razor sida under mappen Sidor .
Layoutfilen ska gå till mappen Pages/Shared .
Vi rekommenderar att du inte placerar layoutfilen i mappen Vyer/Delad . Vyer/delad är ett MVC-vymönster. Razor Sidor är avsedda att förlita sig på mapphierarki, inte sökvägskonventioner.
Visa sökning från en Razor sida inkluderar mappen Sidor. Layouter, mallar och delar som används med MVC-styrenheter och konventionella Razor vyer fungerar smidigt.
Lägg till en Pages/_ViewImports.cshtml
fil:
@namespace RazorPagesContacts.Pages
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
@namespace
förklaras senare i handledningen. Direktivet @addTagHelper
tar med de inbyggda Tag Helpers för alla sidor i mappen Sidor.
Direktivet @namespace
anges på en sida:
@page
@namespace RazorPagesIntro.Pages.Customers
@model NameSpaceModel
<h2>Name space</h2>
<p>
@Model.Message
</p>
Direktivet @namespace
anger sidans namnområde. Direktivet @model
behöver inte inkludera namnområdet.
@namespace
När direktivet finns i _ViewImports.cshtml
tillhandahåller det angivna namnområdet prefixet för det genererade namnområdet på sidan som importerar @namespace
direktivet. Resten av det genererade namnområdet (suffixdelen) är den punktavgränsade relativa sökvägen mellan mappen som innehåller _ViewImports.cshtml
och mappen som innehåller sidan.
Till exempel anger PageModel
klassen Pages/Customers/Edit.cshtml.cs
uttryckligen namnområdet.
namespace RazorPagesContacts.Pages
{
public class EditModel : PageModel
{
private readonly AppDbContext _db;
public EditModel(AppDbContext db)
{
_db = db;
}
// Code removed for brevity.
Filen Pages/_ViewImports.cshtml
anger följande namnområde:
@namespace RazorPagesContacts.Pages
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
Det genererade namnområdet för sidan Pages/Customers/Edit.cshtml
Razor är samma som PageModel
klassen.
@namespace
fungerar också med konventionella Razor vyer.
Överväg visningsfilen 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>
Den uppdaterade Pages/Customers/Create.cshtml
vyfilen med _ViewImports.cshtml
och den föregående layoutfilen:
@page
@model CreateModel
<p>Enter a customer name:</p>
<form method="post">
Name:
<input asp-for="Customer!.Name" />
<input type="submit" />
</form>
I föregående kod importerades _ViewImports.cshtml
namnområdet och Tag Helpers. Layoutfilen importerade JavaScript-filerna.
ProjektetRazor Pages starter innehåller Pages/_ValidationScriptsPartial.cshtml
, som kopplar upp validering på klientsidan.
Mer information om partiella vyer finns i Partiella vyer i ASP.NET Core.
URL-generering för sidor
Sidan Create
, som visades tidigare, använder 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");
}
}
Appen har följande fil-/mappstruktur:
/Sidor
Index.cshtml
Privacy.cshtml
/Kunder
Create.cshtml
Edit.cshtml
Index.cshtml
Sidorna Pages/Customers/Create.cshtml
och Pages/Customers/Edit.cshtml
omdirigeras till Pages/Customers/Index.cshtml
efter framgång. Strängen ./Index
är ett relativt sidnamn som används för att komma åt föregående sida. Den används för att generera URL:er till sidan Pages/Customers/Index.cshtml
. Till exempel:
Url.Page("./Index", ...)
<a asp-page="./Index">Customers Index Page</a>
RedirectToPage("./Index")
Det absoluta sidnamnet /Index
används för att generera URL:er till Pages/Index.cshtml
sidan. Till exempel:
Url.Page("/Index", ...)
<a asp-page="/Index">Home Index Page</a>
RedirectToPage("/Index")
Sidnamnet är sökvägen till sidan från rotmappen /Pages , inklusive en inledande /
(till exempel /Index
). De föregående exemplen på URL-generering erbjuder förbättrade alternativ och funktioner jämfört med hårdkodning av en URL. URL-genereringen använder routning och kan generera och koda parametrar beroende på hur vägen definieras i målsökvägen.
URL-generering för sidor stöder relativa namn. I följande tabell visas vilken indexsida som väljs med hjälp av olika RedirectToPage
parametrar i Pages/Customers/Create.cshtml
.
RedirectToPage(x) | Sida |
---|---|
RedirectToPage("/Index") | Sidor/Index |
RedirectToPage("./Index"); | Sidor/Kunder/Index |
RedirectToPage(".. /Index") | Sidor/Index |
OmdirigeraTillSida("Index") | Sidor/Kunder/Index |
RedirectToPage("Index")
, RedirectToPage("./Index")
och RedirectToPage("../Index")
är relativa namn. Parametern RedirectToPage
kombineras med sökvägen till den aktuella sidan för att beräkna namnet på målsidan.
Relativ namnlänkning är användbar när du skapar platser med en komplex struktur. När relativa namn används för att länka mellan sidor i en mapp:
- Om du byter namn på en mapp bryts inte de relativa länkarna.
- Länkarna är inte brutna eftersom de inte innehåller mappnamnet.
Om du vill omdirigera till en sida i ett annat område anger du området:
RedirectToPage("/Index", new { area = "Services" });
Mer information finns i Områden i ASP.NET Core - och Razor Pages-routnings- och appkonventioner i ASP.NET Core.
ViewData-attribut
Data kan skickas till en sida med ViewDataAttribute. Egenskaper med [ViewData]
attributet har sina värden lagrade och inlästa från ViewDataDictionary.
I följande exempel tillämpas AboutModel
attributet på [ViewData]
egenskapen:
public class AboutModel : PageModel
{
[ViewData]
public string Title { get; } = "About";
public void OnGet()
{
}
}
På sidan Om får du åtkomst till egenskapen Title
som en modellegenskap:
<h1>@Model.Title</h1>
I layouten läss rubriken från ordlistan ViewData:
<!DOCTYPE html>
<html lang="en">
<head>
<title>@ViewData["Title"] - WebApplication</title>
...
TempData
ASP.NET Core tillgängliggör TempData. Den här egenskapen lagrar data tills den har lästs. Metoderna Keep och Peek kan användas för att undersöka data utan borttagning.
TempData
är användbart för omdirigering, när data behövs för mer än en enskild begäran.
Följande kod anger värdet Message
för att använda 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");
}
}
Följande markering i Pages/Customers/Index.cshtml
-filen visar värdet av Message
med hjälp av TempData
.
<h3>Msg: @Model.Message</h3>
Sidmodellen Pages/Customers/Index.cshtml.cs
tillämpar [TempData]
attributet på Message
egenskapen.
[TempData]
public string Message { get; set; }
Mer information finns i TempData.
Flera hanterare per sida
Följande sida genererar markering för två hanterare med hjälp av asp-page-handler
Tag Helper:
@page
@model CreateFATHModel
<html>
<body>
<p>
Enter your name.
</p>
<div asp-validation-summary="All"></div>
<form method="POST">
<div><label>Name: <input asp-for="Customer.Name" /></label></div>
<!-- <snippet_Handlers> -->
<input type="submit" asp-page-handler="JoinList" value="Join" />
<input type="submit" asp-page-handler="JoinListUC" value="JOIN UC" />
<!-- </snippet_Handlers> -->
</form>
</body>
</html>
Formuläret i föregående exempel har två skicka-knappar som var och en använder FormActionTagHelper
för att skicka till en annan URL. Attributet asp-page-handler
är en följeslagare till asp-page
.
asp-page-handler
genererar URL:er som skickar till var och en av de hanteringsmetoder som definieras av en sida.
asp-page
anges inte eftersom exemplet länkar till den aktuella sidan.
Sidmodellen:
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();
}
}
}
Föregående kod använder namngivna hanteringsmetoder. Namngivna hanteringsmetoder skapas genom att texten tas med i namnet efter On<HTTP Verb>
och före Async
(om det finns). I föregående exempel är sidmetoderna OnPostJoinListAsync och OnPostJoinListUCAsync. När OnPost och Async har tagits bort är JoinList
hanterarnamnen och JoinListUC
.
<input type="submit" asp-page-handler="JoinList" value="Join" />
<input type="submit" asp-page-handler="JoinListUC" value="JOIN UC" />
Föregående kod används för att skicka URL-sökvägen till OnPostJoinListAsync
, vilket är https://localhost:5001/Customers/CreateFATH?handler=JoinList
. URL-sökvägen som skickas till OnPostJoinListUCAsync
är https://localhost:5001/Customers/CreateFATH?handler=JoinListUC
.
Anpassade vägar
@page
Använd direktivet för att:
- Ange en anpassad väg till en sida. Vägen till sidan Om kan till exempel anges till
/Some/Other/Path
med@page "/Some/Other/Path"
. - Lägg till segment till en sidas standardväg. Ett objektsegment kan till exempel läggas till på en sidas standardväg med
@page "item"
. - Lägg till parametrar till en sidas standardväg. Till exempel kan en ID-parameter,
id
, krävas för en sida med@page "{id}"
.
En rotrelativ sökväg som anges av en tilde (~
) i början av sökvägen stöds. Till exempel är @page "~/Some/Other/Path"
samma som @page "/Some/Other/Path"
.
Om du inte gillar frågesträngen ?handler=JoinList
i URL:en ändrar du vägen för att placera hanterarnamnet i sökvägsdelen av URL:en. Vägen kan anpassas genom att lägga till en vägmall som omges av dubbla citattecken efter @page
direktivet.
@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>
Föregående kod används för att skicka URL-sökvägen till OnPostJoinListAsync
, vilket är https://localhost:5001/Customers/CreateFATH/JoinList
. URL-sökvägen som skickas till OnPostJoinListUCAsync
är https://localhost:5001/Customers/CreateFATH/JoinListUC
.
Följande ?
handler
innebär att routningsparametern är valfri.
Sammanställning av JavaScript-filer (JS)
Att sortera JavaScript-filer (JS) för sidor och vyer är ett praktiskt sätt att organisera skript i en app.
Samla in JS filer med hjälp av följande filnamnstilläggskonventioner:
- Sidor med Razor Pages-appar och vyer för MVC-appar:
.cshtml.js
. Exempel:-
Pages/Index.cshtml.js
för sidan förIndex
en Razor pages-app påPages/Index.cshtml
. -
Views/Home/Index.cshtml.js
Index
för vyn för en MVC-app påViews/Home/Index.cshtml
.
-
Sorterade JS filer kan adresseras offentligt med hjälp av sökvägen till filen i projektet:
Sidor och vyer från en samlad skriptfil i appen:
{PATH}/{PAGE, VIEW, OR COMPONENT}.{EXTENSION}.js
- Platshållaren
{PATH}
är sökvägen till sidan, vyn eller komponenten. - Platshållaren
{PAGE, VIEW, OR COMPONENT}
är sidan, vyn eller komponenten. - Platshållaren
{EXTENSION}
matchar tillägget för sidan, vyn eller komponenten, antingenrazor
ellercshtml
.
Razor Exempel på sidor:
En JS fil för sidan
Index
placeras iPages
mappen (Pages/Index.cshtml.js
) bredvid sidanIndex
(Pages/Index.cshtml
). På sidanIndex
refereras skriptet till på sökvägen iPages
mappen:@section Scripts { <script src="~/Pages/Index.cshtml.js"></script> }
- Platshållaren
Standardlayouten Pages/Shared/_Layout.cshtml
kan konfigureras för att inkludera sorterade JS filer, vilket eliminerar behovet av att konfigurera varje sida individuellt:
<script asp-src-include="@(ViewContext.View.Path).js"></script>
Exempelnedladdningen använder föregående kodfragment för att inkludera sorterade JS filer i standardlayouten.
När appen publiceras flyttar ramverket automatiskt skriptet till webbroten. I föregående exempel flyttas skriptet till bin\Release\{TARGET FRAMEWORK MONIKER}\publish\wwwroot\Pages\Index.cshtml.js
, där {TARGET FRAMEWORK MONIKER}
platshållaren är Target Framework Moniker (TFM). Ingen ändring krävs för skriptets relativa URL på Index
sidan.
När appen publiceras flyttar ramverket automatiskt skriptet till webbroten. I föregående exempel flyttas skriptet till bin\Release\{TARGET FRAMEWORK MONIKER}\publish\wwwroot\Components\Pages\Index.razor.js
, där {TARGET FRAMEWORK MONIKER}
platshållaren är Target Framework Moniker (TFM). Ingen ändring krävs för skriptets relativa URL i komponenten Index
.
För skript som tillhandahålls av ett Razor klassbibliotek (RCL):
_content/{PACKAGE ID}/{PATH}/{PAGE, VIEW, OR COMPONENT}.{EXTENSION}.js
- Platshållaren
{PACKAGE ID}
är RCL:s paketidentifierare (eller biblioteksnamn för ett klassbibliotek som refereras av appen). - Platshållaren
{PATH}
är sökvägen till sidan, vyn eller komponenten. Om en Razor komponent finns i roten för RCL inkluderas inte sökvägssegmentet. - Platshållaren
{PAGE, VIEW, OR COMPONENT}
är sidan, vyn eller komponenten. - Platshållaren
{EXTENSION}
matchar tillägget för sida, vy eller komponent, antingenrazor
ellercshtml
.
- Platshållaren
Avancerad konfiguration och inställningar
Konfigurationen och inställningarna i följande avsnitt krävs inte av de flesta appar.
Om du vill konfigurera avancerade alternativ använder du den AddRazorPages överlagring som konfigurerar RazorPagesOptions:
using Microsoft.EntityFrameworkCore;
using RazorPagesContacts.Data;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages(options =>
{
options.RootDirectory = "/MyPages";
options.Conventions.AuthorizeFolder("/MyPages/Admin");
});
builder.Services.AddDbContext<CustomerDbContext>(options =>
options.UseInMemoryDatabase("name"));
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();
app.MapRazorPages();
app.Run();
RazorPagesOptions Använd för att ange rotkatalogen för sidor eller lägga till programmodellkonventioner för sidor. Mer information om konventioner finns i Razor Auktoriseringskonventioner för sidor.
För att förkompilera vyer, se vykompileringRazor.
Ange att Razor Sidor finns i innehållsroten
Som standardinställning är Razor Pages placerade i katalogen /Pages. Lägg WithRazorPagesAtContentRoot till för att ange att dina Razor sidor finns i innehållsroten (ContentRootPath) i appen:
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();
Ange att Razor Sidor finns i en anpassad rotkatalog
Lägg WithRazorPagesRoot till för att ange att Razor Sidor finns i en anpassad rotkatalog i appen (ange en relativ sökväg):
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();
Ytterligare resurser
- Se Kom igång med Razor Pages, som bygger på den här introduktionen.
- Auktorisera attribut och Razor sidor
- Ladda ned eller visa exempelkod
- Översikt över ASP.NET Core
- Razor syntaxreferens för ASP.NET Core
- Områden i ASP.NET Core
- Självstudie: Kom igång med Razor sidor i ASP.NET Core
- Razor Auktoriseringskonventioner för sidor i ASP.NET Core
- Razor Sidors routnings- och appkonventioner i ASP.NET Core
- Razor Pages-enhetstester i ASP.NET Core
- Partiella vyer i ASP.NET Core
- Visual Studio 2019 16.4 eller senare med arbetsbelastningen ASP.NET och webbutveckling
- .NET Core 3.1 SDK
- Visual Studio 2019 16.8 eller senare med arbetsbelastningen ASP.NET och webbutveckling
- .NET 5 SDK
Skapa ett Razor pages-projekt
Razor sidor
Razor Sidor är aktiverade i 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();
});
}
}
Överväg en grundläggande sida:
@page
<h1>Hello, world!</h1>
<h2>The time on the server is @DateTime.Now</h2>
Föregående kod ser ut ungefär som en Razor vyfil som används i en ASP.NET Core-app med kontrollanter och vyer. Det som gör det @page
annorlunda är direktivet.
@page
gör filen till en MVC-åtgärd , vilket innebär att den hanterar begäranden direkt, utan att gå igenom en kontrollant.
@page
måste vara det första Razor direktivet på en sida.
@page
påverkar beteendet hos andra Razor konstruktioner.
Razor Sidfilnamn har ett .cshtml
suffix.
En liknande sida, med hjälp av en PageModel
klass, visas i följande två filer. Filen Pages/Index2.cshtml
:
@page
@using RazorPagesIntro.Pages
@model Index2Model
<h2>Separate page model</h2>
<p>
@Model.Message
</p>
Sidmodellen 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 }";
}
}
}
Enligt konvention har PageModel
-klassfilen samma namn som Razor-sidfilen med .cs
bifogat. Till exempel är Razorföregående Pages/Index2.cshtml
sida . Filen som innehåller PageModel
klassen heter Pages/Index2.cshtml.cs
.
Associationerna för URL-sökvägar till sidor bestäms av sidans plats i filsystemet. I följande tabell visas en Razor sidsökväg och matchande URL:
Filnamn och sökväg | matchande URL |
---|---|
/Pages/Index.cshtml |
/ eller /Index |
/Pages/Contact.cshtml |
/Contact |
/Pages/Store/Contact.cshtml |
/Store/Contact |
/Pages/Store/Index.cshtml |
/Store eller /Store/Index |
Anteckningar:
- Körningen söker Razor efter Pages-filer i mappen Pages som standard.
-
Index
är standardsidan när en URL inte innehåller en sida.
Skriva ett grundläggande formulär
Razor Sidor är utformade för att göra vanliga mönster som används med webbläsare enkla att implementera när du skapar en app.
Modellbindning, Tag Helpers och HTML-hjälpverktyg fungerar bara med de egenskaper som definierats i en Razor sidklass. Överväg en sida som implementerar ett grundläggande "kontakta oss"-formulär för Contact
modellen:
För exemplen i det här dokumentet initieras DbContext
i filen Startup.cs.
För minnesdatabasen krävs NuGet-paketet Microsoft.EntityFrameworkCore.InMemory
.
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<CustomerDbContext>(options =>
options.UseInMemoryDatabase("name"));
services.AddRazorPages();
}
Datamodellen:
using System.ComponentModel.DataAnnotations;
namespace RazorPagesContacts.Models
{
public class Customer
{
public int Id { get; set; }
[Required, StringLength(10)]
public string Name { get; set; }
}
}
Databas-kontexten:
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; }
}
}
Filen för vy 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>
Sidmodellen 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");
}
}
}
Enligt konvention benämns PageModel
-klassen <PageName>Model
och finns i samma namnområde som sidan.
Klassen PageModel
tillåter separation av logiken för en sida från presentationen. Den definierar sidhanterare för begäranden som skickas till sidan och de data som används för att återge sidan. Den här separationen tillåter:
- Hantering av sidberoenden via dependency injection.
- Enhetstestning
Sidan har en OnPostAsync
hanteringsmetod som körs på POST
begäranden (när en användare publicerar formuläret). Du kan lägga till hanteringsmetoder för alla HTTP-verb. De vanligaste hanterarna är:
-
OnGet
för att initiera det tillstånd som behövs för sidan. I den föregående koden visarOnGet
-metodenCreateModel.cshtml
Razor-sidan. -
OnPost
för att hantera formulärinlämningar.
Namngivningssuffixet Async
är valfritt men används ofta av konventionen för asynkrona funktioner. Föregående kod är typisk för Razor Sidor.
Om du är bekant med ASP.NET-applikationer med kontroller och vyer:
- Koden
OnPostAsync
i föregående exempel ser ut ungefär som vanlig styrenhetskod. - De flesta av MVC-primitiverna som modellbindning, validering och åtgärdsresultat fungerar på samma sätt med kontrollanter och Razor sidor.
Föregående OnPostAsync
metod:
public async Task<IActionResult> OnPostAsync()
{
if (!ModelState.IsValid)
{
return Page();
}
_context.Customers.Add(Customer);
await _context.SaveChangesAsync();
return RedirectToPage("./Index");
}
Det grundläggande flödet av OnPostAsync
:
Sök efter verifieringsfel.
- Om det inte finns några fel sparar du data och omdirigerar.
- Om det finns fel visar du sidan igen med valideringsmeddelanden. I många fall identifieras verifieringsfel på klienten och skickas aldrig till servern.
Filen för vy 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>
Den renderade HTML-koden från 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>
I föregående kod publicerar du formuläret:
Med giltiga data:
Hanteringsmetoden
OnPostAsync
anropar RedirectToPage hjälpmetoden.RedirectToPage
returnerar en instans av RedirectToPageResult.RedirectToPage
:- Är ett åtgärdsresultat.
- Liknar
RedirectToAction
ellerRedirectToRoute
(används i kontrollanter och vyer). - Är anpassad för sidor. I föregående exempel omdirigeras den till rotindexsidan (
/Index
).RedirectToPage
beskrivs i avsnittet URL-generering för sidor .
Med valideringsfel som skickas till servern:
- Hanteringsmetoden
OnPostAsync
anropar Page hjälpmetoden.Page
returnerar en instans av PageResult. Att returneraPage
är likt hur åtgärder i kontroller returnerarView
.PageResult
är standardreturtypen för en hanteringsmetod. En hanteringsmetod som returnerarvoid
återger sidan. - I föregående exempel resulterar publicering av formuläret utan värde i ModelState.IsValid som returnerar false. I det här exemplet visas inga verifieringsfel på klienten. Verifieringsfelhantering beskrivs senare i det här dokumentet.
public async Task<IActionResult> OnPostAsync() { if (!ModelState.IsValid) { return Page(); } _context.Customers.Add(Customer); await _context.SaveChangesAsync(); return RedirectToPage("./Index"); }
- Hanteringsmetoden
Med valideringsfel som identifierats av verifiering på klientsidan:
- Data publiceras inte på servern.
- Validering på klientsidan förklaras senare i det här dokumentet.
Egenskapen Customer
använder [BindProperty]
attributet för att välja modellbindning:
public class CreateModel : PageModel
{
private readonly CustomerDbContext _context;
public CreateModel(CustomerDbContext context)
{
_context = context;
}
public IActionResult OnGet()
{
return Page();
}
[BindProperty]
public Customer Customer { get; set; }
public async Task<IActionResult> OnPostAsync()
{
if (!ModelState.IsValid)
{
return Page();
}
_context.Customers.Add(Customer);
await _context.SaveChangesAsync();
return RedirectToPage("./Index");
}
}
[BindProperty]
ska inte användas på modeller som innehåller egenskaper som inte ska ändras av klienten. Mer information finns i Överpublicering.
Razor Sidor binder som standard endast egenskaper med icke-verbGET
. Bindning till egenskaper tar bort behovet av att skriva kod för att konvertera HTTP-data till modelltypen. Bindning minskar koden genom att använda samma egenskap för att återge formulärfält (<input asp-for="Customer.Name">
) och acceptera indata.
Varning
Av säkerhetsskäl måste du välja att binda GET
begärandedata till sidmodellegenskaper. Verifiera användarindata innan du mappar den till egenskaper. Att välja bindning GET
är användbart när du hanterar scenarier som förlitar sig på frågesträngar eller vägvärden.
Om du vill binda en egenskap för GET
begäranden anger du [BindProperty]
attributets SupportsGet
egenskap till true
:
[BindProperty(SupportsGet = true)]
Mer information finns i ASP.NET Core Community Standup: Bind på GET-diskussion (YouTube).
Granskning av Pages/Create.cshtml
vyfilen:
@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>
- I den föregående koden binder hjälpverktyget för indatataggen HTML-elementet
<input asp-for="Customer.Name" />
till modelluttrycket<input>
. -
@addTagHelper
gör Tag Helpers tillgängliga.
Startsidan
Index.cshtml
är startsidan:
@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>
Den associerade PageModel
klassen (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();
}
}
Filen Index.cshtml
innehåller följande markering:
<a asp-page="./Edit" asp-route-id="@contact.Id">Edit</a> |
<a /a>
Anchor Tag Helper använde asp-route-{value}
attributet för att generera en länk till Redigeringssidan. Länken innehåller routningsdata med kontakt-ID:t. Till exempel https://localhost:5001/Edit/1
.
Tagghjälpare gör det möjligt för kod på serversidan att delta i skapandet och återgivningen av HTML-element i Razor filer.
Filen Index.cshtml
innehåller markering för att skapa en borttagningsknapp för varje kundkontakt:
<button type="submit" asp-page-handler="delete" asp-route-id="@contact.Id">delete</button>
Den renderade HTML-koden:
<button type="submit" formaction="/Customers?id=1&handler=delete">delete</button>
När borttagningsknappen återges i HTML innehåller dess formaction parametrar för:
- Kundens kontakt-ID, som anges av attributet
asp-route-id
. -
handler
anges av attributetasp-page-handler
.
När knappen har valts skickas en formulärbegäran POST
till servern. Enligt konventionen väljs namnet på hanteringsmetoden baserat på värdet för parametern handler
enligt schemat OnPost[handler]Async
.
Eftersom handler
är delete
i det här exemplet, används OnPostDeleteAsync
-hanteringsmetoden för att bearbeta POST
-begäran. Om asp-page-handler
är inställt på ett annat värde, till exempel remove
, väljs en hanteringsmetod med namnet 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();
}
OnPostDeleteAsync
-metoden:
- Hämtar
id
från frågesträngen. - Söker i databasen efter kundkontakten med
FindAsync
. - Om kundkontakten hittas tas den bort och databasen uppdateras.
- Anrop RedirectToPage för att omdirigera till rotindexsidan (
/Index
).
Filen 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>
Den första raden innehåller @page "{id:int}"
direktivet. Routningsbegränsningen "{id:int}"
uppmanar sidan att acceptera begäranden till sidan som innehåller int
routningsdata. Om en begäran till sidan inte innehåller routningsdata som kan konverteras till en int
returnerar körningen ett HTTP 404-fel (hittades inte). Om du vill göra ID:t valfritt lägger du till i routningsbegränsningen ?
:
@page "{id:int?}"
Filen 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");
}
}
Validering
Valideringsregler:
- Anges deklarativt i modellklassen.
- Tillämpas överallt i appen.
Namnområdet System.ComponentModel.DataAnnotations innehåller en uppsättning inbyggda valideringsattribut som tillämpas deklarativt på en klass eller egenskap. DataAnnotations innehåller också formateringsattribut som [DataType]
det hjälper till med formatering och ger ingen verifiering.
Tänk på Customer
modellen:
using System.ComponentModel.DataAnnotations;
namespace RazorPagesContacts.Models
{
public class Customer
{
public int Id { get; set; }
[Required, StringLength(10)]
public string Name { get; set; }
}
}
Använd följande Create.cshtml
visningsfil:
@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>
Föregående kod:
Innehåller jQuery- och jQuery-valideringsskript.
Använder
<div />
och<span />
taghjälparna för att aktivera:- Validering på klientsidan.
- Renderingsfel vid validering.
Genererar följande 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>
Publicering av Skapa-formuläret utan ett namn visar felmeddelandet "Fältet Namn är obligatoriskt" i formuläret. Om JavaScript är aktiverat på klienten visar webbläsaren felet utan att publicera till servern.
Attributet [StringLength(10)]
genererar data-val-length-max="10"
på den renderade HTML-koden.
data-val-length-max
förhindrar att webbläsare anger mer än den angivna maximala längden. Om ett verktyg som Fiddler används för att redigera och spela upp inlägget igen:
- Med ett namn längre än 10 tecken.
- Felmeddelandet "Fältnamnet måste vara en sträng med en maximal längd på 10." returneras.
Tänk på följande Movie
modell:
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; }
}
}
Valideringsattributen anger beteende för att framtvinga de modellegenskaper som de tillämpas på:
Attributen
Required
ochMinimumLength
anger att en egenskap måste ha ett värde, men ingenting hindrar en användare från att ange tomt utrymme för att uppfylla den här valideringen.Attributet
RegularExpression
används för att begränsa vilka tecken som kan matas in. I föregående kod, "Genre":- Får endast använda bokstäver.
- Den första bokstaven måste vara versaler. Blanksteg, siffror och specialtecken tillåts inte.
RegularExpression
"Omdöme":- Kräver att det första tecknet är versaler.
- Tillåter specialtecken och siffror i efterföljande mellanrum. "PG-13" är giltig för en klassificering, men inte för en "Genre".
Attributet
Range
begränsar ett värde till inom ett angivet intervall.Attributet
StringLength
anger den maximala längden för en strängegenskap och eventuellt dess minsta längd.Värdetyper (till exempel
decimal
,int
,float
,DateTime
) är av sig själva nödvändiga och behöver inte attributet[Required]
.
Sidan Skapa för modellen Movie
visar fel med ogiltiga värden:
Mer information finns i:
Hantera HEAD-begäranden med en OnGet-hanteringsåterställning
HEAD
begäranden gör det möjligt att hämta rubrikerna för en specifik resurs. Till skillnad från GET
begäranden returnerar HEAD
begäranden inte någon svarstext.
Normalt skapas en OnHead
hanterare och anropas för HEAD
begäranden:
public void OnHead()
{
HttpContext.Response.Headers.Add("Head Test", "Handled by OnHead!");
}
Razor Sidor återgår till att anropa OnGet
hanteraren om ingen OnHead
hanterare har definierats.
XSRF/CSRF och Razor sidor
Razor Sidor skyddas av Antiforgery-validering. FormTagHelper infogar antiforgery-token i HTML-formulärelement.
Använda layouter, partiella objekt, mallar och tagghjälpare med Razor sidor
Sidorna fungerar med alla funktioner i Razor vymotorn. Layouter, delar, mallar, Tag Helpers _ViewStart.cshtml
och _ViewImports.cshtml
fungerar på samma sätt som för konventionella Razor vyer.
Låt oss rensa den här sidan genom att dra nytta av några av dessa funktioner.
Lägg till en layout-sida till 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>
- Styr layouten för varje sida (såvida inte sidan väljer bort layouten).
- Importerar HTML-strukturer som JavaScript och formatmallar.
- Innehållet på Razor sidan återges där
@RenderBody()
anropas.
Mer information finns på layoutsidan.
Egenskapen Layout anges i Pages/_ViewStart.cshtml
:
@{
Layout = "_Layout";
}
Layouten finns i mappen Pages/Shared . Sidor letar efter andra vyer (layouter, mallar, partiella objekt) hierarkiskt, med början i samma mapp som den aktuella sidan. En layout i mappen Sidor/Delad kan användas från valfri Razor sida under mappen Sidor .
Layoutfilen ska gå till mappen Pages/Shared .
Vi rekommenderar att du inte placerar layoutfilen i mappen Vyer/Delad . Vyer/delad är ett MVC-vymönster. Razor Sidor är avsedda att förlita sig på mapphierarki, inte sökvägskonventioner.
Visa sökning från en Razor sida inkluderar mappen Sidor. Layouter, mallar och delar som används med MVC-styrenheter och konventionella Razor vyer fungerar smidigt.
Lägg till en Pages/_ViewImports.cshtml
fil:
@namespace RazorPagesContacts.Pages
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
@namespace
förklaras senare i handledningen. Direktivet @addTagHelper
tar med de inbyggda Tag Helpers för alla sidor i mappen Sidor.
Direktivet @namespace
anges på en sida:
@page
@namespace RazorPagesIntro.Pages.Customers
@model NameSpaceModel
<h2>Name space</h2>
<p>
@Model.Message
</p>
Direktivet @namespace
anger sidans namnområde. Direktivet @model
behöver inte inkludera namnområdet.
@namespace
När direktivet finns i _ViewImports.cshtml
tillhandahåller det angivna namnområdet prefixet för det genererade namnområdet på sidan som importerar @namespace
direktivet. Resten av det genererade namnområdet (suffixdelen) är den punktavgränsade relativa sökvägen mellan mappen som innehåller _ViewImports.cshtml
och mappen som innehåller sidan.
Till exempel anger PageModel
klassen Pages/Customers/Edit.cshtml.cs
uttryckligen namnområdet.
namespace RazorPagesContacts.Pages
{
public class EditModel : PageModel
{
private readonly AppDbContext _db;
public EditModel(AppDbContext db)
{
_db = db;
}
// Code removed for brevity.
Filen Pages/_ViewImports.cshtml
anger följande namnområde:
@namespace RazorPagesContacts.Pages
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
Det genererade namnområdet för sidan Pages/Customers/Edit.cshtml
Razor är samma som PageModel
klassen.
@namespace
fungerar också med konventionella Razor vyer.
Överväg visningsfilen 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>
Den uppdaterade Pages/Create.cshtml
vyfilen med _ViewImports.cshtml
och den föregående layoutfilen:
@page
@model CreateModel
<p>Enter a customer name:</p>
<form method="post">
Name:
<input asp-for="Customer.Name" />
<input type="submit" />
</form>
I föregående kod importerades _ViewImports.cshtml
namnområdet och Tag Helpers. Layoutfilen importerade JavaScript-filerna.
ProjektetRazor Pages starter innehåller Pages/_ValidationScriptsPartial.cshtml
, som kopplar upp validering på klientsidan.
Mer information om partiella vyer finns i Partiella vyer i ASP.NET Core.
URL-generering för sidor
Sidan Create
, som visades tidigare, använder 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");
}
}
Appen har följande fil-/mappstruktur:
/Sidor
Index.cshtml
Privacy.cshtml
/Kunder
Create.cshtml
Edit.cshtml
Index.cshtml
Sidorna Pages/Customers/Create.cshtml
och Pages/Customers/Edit.cshtml
omdirigeras till Pages/Customers/Index.cshtml
efter framgång. Strängen ./Index
är ett relativt sidnamn som används för att komma åt föregående sida. Den används för att generera URL:er till sidan Pages/Customers/Index.cshtml
. Till exempel:
Url.Page("./Index", ...)
<a asp-page="./Index">Customers Index Page</a>
RedirectToPage("./Index")
Det absoluta sidnamnet /Index
används för att generera URL:er till Pages/Index.cshtml
sidan. Till exempel:
Url.Page("/Index", ...)
<a asp-page="/Index">Home Index Page</a>
RedirectToPage("/Index")
Sidnamnet är sökvägen till sidan från rotmappen /Pages , inklusive en inledande /
(till exempel /Index
). De föregående exemplen på URL-generering erbjuder förbättrade alternativ och funktioner jämfört med hårdkodning av en URL. URL-genereringen använder routning och kan generera och koda parametrar beroende på hur vägen definieras i målsökvägen.
URL-generering för sidor stöder relativa namn. I följande tabell visas vilken indexsida som väljs med hjälp av olika RedirectToPage
parametrar i Pages/Customers/Create.cshtml
.
RedirectToPage(x) | Sida |
---|---|
RedirectToPage("/Index") | Sidor/Index |
RedirectToPage("./Index"); | Sidor/Kunder/Index |
RedirectToPage(".. /Index") | Sidor/Index |
OmdirigeraTillSida("Index") | Sidor/Kunder/Index |
RedirectToPage("Index")
, RedirectToPage("./Index")
och RedirectToPage("../Index")
är relativa namn. Parametern RedirectToPage
kombineras med sökvägen till den aktuella sidan för att beräkna namnet på målsidan.
Relativ namnlänkning är användbar när du skapar platser med en komplex struktur. När relativa namn används för att länka mellan sidor i en mapp:
- Om du byter namn på en mapp bryts inte de relativa länkarna.
- Länkarna är inte brutna eftersom de inte innehåller mappnamnet.
Om du vill omdirigera till en sida i ett annat område anger du området:
RedirectToPage("/Index", new { area = "Services" });
Mer information finns i Områden i ASP.NET Core - och Razor Pages-routnings- och appkonventioner i ASP.NET Core.
ViewData-attribut
Data kan skickas till en sida med ViewDataAttribute. Egenskaper med [ViewData]
attributet har sina värden lagrade och inlästa från ViewDataDictionary.
I följande exempel tillämpas AboutModel
attributet på [ViewData]
egenskapen:
public class AboutModel : PageModel
{
[ViewData]
public string Title { get; } = "About";
public void OnGet()
{
}
}
På sidan Om får du åtkomst till egenskapen Title
som en modellegenskap:
<h1>@Model.Title</h1>
I layouten läss rubriken från ordlistan ViewData:
<!DOCTYPE html>
<html lang="en">
<head>
<title>@ViewData["Title"] - WebApplication</title>
...
TempData
ASP.NET Core tillgängliggör TempData. Den här egenskapen lagrar data tills den har lästs. Metoderna Keep och Peek kan användas för att undersöka data utan borttagning.
TempData
är användbart för omdirigering, när data behövs för mer än en enskild begäran.
Följande kod anger värdet Message
för att använda 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");
}
}
Följande markering i Pages/Customers/Index.cshtml
-filen visar värdet av Message
med hjälp av TempData
.
<h3>Msg: @Model.Message</h3>
Sidmodellen Pages/Customers/Index.cshtml.cs
tillämpar [TempData]
attributet på Message
egenskapen.
[TempData]
public string Message { get; set; }
Mer information finns i TempData.
Flera hanterare per sida
Följande sida genererar markering för två hanterare med hjälp av asp-page-handler
Tag Helper:
@page
@model CreateFATHModel
<html>
<body>
<p>
Enter your name.
</p>
<div asp-validation-summary="All"></div>
<form method="POST">
<div><label>Name: <input asp-for="Customer.Name" /></label></div>
<!-- <snippet_Handlers> -->
<input type="submit" asp-page-handler="JoinList" value="Join" />
<input type="submit" asp-page-handler="JoinListUC" value="JOIN UC" />
<!-- </snippet_Handlers> -->
</form>
</body>
</html>
Formuläret i föregående exempel har två skicka-knappar som var och en använder FormActionTagHelper
för att skicka till en annan URL. Attributet asp-page-handler
är en följeslagare till asp-page
.
asp-page-handler
genererar URL:er som skickar till var och en av de hanteringsmetoder som definieras av en sida.
asp-page
anges inte eftersom exemplet länkar till den aktuella sidan.
Sidmodellen:
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();
}
}
}
Föregående kod använder namngivna hanteringsmetoder. Namngivna hanteringsmetoder skapas genom att texten tas med i namnet efter On<HTTP Verb>
och före Async
(om det finns). I föregående exempel är sidmetoderna OnPostJoinListAsync och OnPostJoinListUCAsync. När OnPost och Async har tagits bort är JoinList
hanterarnamnen och JoinListUC
.
<input type="submit" asp-page-handler="JoinList" value="Join" />
<input type="submit" asp-page-handler="JoinListUC" value="JOIN UC" />
Föregående kod används för att skicka URL-sökvägen till OnPostJoinListAsync
, vilket är https://localhost:5001/Customers/CreateFATH?handler=JoinList
. URL-sökvägen som skickas till OnPostJoinListUCAsync
är https://localhost:5001/Customers/CreateFATH?handler=JoinListUC
.
Anpassade vägar
@page
Använd direktivet för att:
- Ange en anpassad väg till en sida. Vägen till sidan Om kan till exempel anges till
/Some/Other/Path
med@page "/Some/Other/Path"
. - Lägg till segment till en sidas standardväg. Ett objektsegment kan till exempel läggas till på en sidas standardväg med
@page "item"
. - Lägg till parametrar till en sidas standardväg. Till exempel kan en ID-parameter,
id
, krävas för en sida med@page "{id}"
.
En rotrelativ sökväg som anges av en tilde (~
) i början av sökvägen stöds. Till exempel är @page "~/Some/Other/Path"
samma som @page "/Some/Other/Path"
.
Om du inte gillar frågesträngen ?handler=JoinList
i URL:en ändrar du vägen för att placera hanterarnamnet i sökvägsdelen av URL:en. Vägen kan anpassas genom att lägga till en vägmall som omges av dubbla citattecken efter @page
direktivet.
@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>
Föregående kod används för att skicka URL-sökvägen till OnPostJoinListAsync
, vilket är https://localhost:5001/Customers/CreateFATH/JoinList
. URL-sökvägen som skickas till OnPostJoinListUCAsync
är https://localhost:5001/Customers/CreateFATH/JoinListUC
.
Följande ?
handler
innebär att routningsparametern är valfri.
Avancerad konfiguration och inställningar
Konfigurationen och inställningarna i följande avsnitt krävs inte av de flesta appar.
Om du vill konfigurera avancerade alternativ använder du den AddRazorPages överlagring som konfigurerar RazorPagesOptions:
public void ConfigureServices(IServiceCollection services)
{
services.AddRazorPages(options =>
{
options.RootDirectory = "/MyPages";
options.Conventions.AuthorizeFolder("/MyPages/Admin");
});
}
RazorPagesOptions Använd för att ange rotkatalogen för sidor eller lägga till programmodellkonventioner för sidor. Mer information om konventioner finns i Razor Auktoriseringskonventioner för sidor.
För att förkompilera vyer, se vykompileringRazor.
Ange att Razor Sidor finns i innehållsroten
Som standardinställning är Razor Pages placerade i katalogen /Pages. Lägg WithRazorPagesAtContentRoot till för att ange att dina Razor sidor finns i innehållsroten (ContentRootPath) i appen:
public void ConfigureServices(IServiceCollection services)
{
services.AddRazorPages(options =>
{
options.Conventions.AuthorizeFolder("/MyPages/Admin");
})
.WithRazorPagesAtContentRoot();
}
Ange att Razor Sidor finns i en anpassad rotkatalog
Lägg WithRazorPagesRoot till för att ange att Razor Sidor finns i en anpassad rotkatalog i appen (ange en relativ sökväg):
public void ConfigureServices(IServiceCollection services)
{
services.AddRazorPages(options =>
{
options.Conventions.AuthorizeFolder("/MyPages/Admin");
})
.WithRazorPagesRoot("/path/to/razor/pages");
}
Ytterligare resurser
- Se Kom igång med Razor Pages, som bygger på den här introduktionen.
- Auktorisera attribut och Razor sidor
- Ladda ned eller visa exempelkod
- Översikt över ASP.NET Core
- Razor syntaxreferens för ASP.NET Core
- Områden i ASP.NET Core
- Självstudie: Kom igång med Razor sidor i ASP.NET Core
- Razor Auktoriseringskonventioner för sidor i ASP.NET Core
- Razor Sidors routnings- och appkonventioner i ASP.NET Core
- Razor Pages-enhetstester i ASP.NET Core
- Partiella vyer i ASP.NET Core
ASP.NET Core