Pengantar Razor Pages di ASP.NET Core
Oleh Rick Anderson, Dave Brock, dan Kirk Larkin
Catatan
Ini bukan versi terbaru dari artikel ini. Untuk rilis saat ini, lihat versi .NET 8 dari artikel ini.
Peringatan
Versi ASP.NET Core ini tidak lagi didukung. Untuk informasi selengkapnya, lihat Kebijakan Dukungan .NET dan .NET Core. Untuk rilis saat ini, lihat versi .NET 8 dari artikel ini.
Penting
Informasi ini berkaitan dengan produk pra-rilis yang mungkin dimodifikasi secara substansial sebelum dirilis secara komersial. Microsoft tidak memberikan jaminan, tersirat maupun tersurat, sehubungan dengan informasi yang diberikan di sini.
Untuk rilis saat ini, lihat versi .NET 8 dari artikel ini.
Razor Pages dapat membuat pengodean skenario yang berfokus pada halaman lebih mudah dan lebih produktif daripada menggunakan pengontrol dan tampilan.
Jika Anda mencari tutorial yang menggunakan pendekatan Model-View-Controller, lihat Mulai menggunakan MVC ASP.NET Core.
Dokumen ini memberikan pengantar untuk Razor Pages. Ini bukan tutorial langkah demi langkah. Jika Anda menganggap bahwa beberapa bagian sulit untuk dipahami, lihat Mulai menggunakan Razor Pages. Untuk gambaran umum ASP.NET Core, lihat Pengantar ASP.NET Core.
Prasyarat
- Visual Studio 2022 dengan beban kerja ASP.NET serta pengembangan web.
- .NET 6.0 SDK
Buat proyek Razor Pages
Lihat Mulai menggunakan Razor Pages untuk petunjuk terperinci tentang cara membuat proyek Razor Pages.
Razor Pages
Razor Pages diaktifkan di 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();
Dalam kode sebelumnya:
- AddRazorPages menambahkan layanan untuk Razor Pages ke aplikasi.
- MapRazorPages menambahkan titik akhir untuk Razor Pages ke IEndpointRouteBuilder.
@page
<h1>Hello, world!</h1>
<h2>The time on the server is @DateTime.Now</h2>
Kode sebelumnya sangat mirip dengan file tampilan Razor yang digunakan dalam aplikasi ASP.NET Core dengan pengontrol dan tampilan. Yang membuatnya berbeda adalah arahan @page
. @page
membuat file menjadi tindakan MVC, yang berarti ini menangani permintaan secara langsung, tanpa melalui pengontrol. @page
harus menjadi arahan Razor pertama di halaman. @page
memengaruhi perilaku konstruksi Razor lainnya. Nama file Razor Pages memiliki akhiran .cshtml
.
Halaman serupa, menggunakan kelas PageModel
, ditampilkan dalam dua file berikut. File Pages/Index2.cshtml
:
@page
@using RazorPagesIntro.Pages
@model Index2Model
<h2>Separate page model</h2>
<p>
@Model.Message
</p>
Model halaman 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 }";
}
}
}
Menurut konvensi, file kelas PageModel
memiliki nama yang sama dengan file Razor Pages dengan .cs
yang ditambahkan. Misalnya, Razor Pages sebelumnya adalah Pages/Index2.cshtml
. File yang berisi kelas PageModel
diberi nama Pages/Index2.cshtml.cs
.
Asosiasi jalur URL ke halaman ditentukan oleh lokasi halaman di sistem file. Tabel berikut menunjukkan jalur Razor Pages dan URL yang cocok:
Nama file dan jalur | URL yang cocok |
---|---|
/Pages/Index.cshtml |
/ atau /Index |
/Pages/Contact.cshtml |
/Contact |
/Pages/Store/Contact.cshtml |
/Store/Contact |
/Pages/Store/Index.cshtml |
/Store atau /Store/Index |
Catatan:
- Runtime bahasa umum mencari file Razor Pages dalam folder Pages secara default.
Index
adalah halaman bawaan jika URL tidak menyertakan halaman.
Menulis formulir dasar
Razor Pages dirancang untuk menjadikan pola umum yang digunakan dengan browser web mudah diimplementasikan saat membuat aplikasi. Pengikatan model, Pembantu Tag, dan pembantu HTML bekerja dengan properti yang ditentukan dalam kelas Razor Page. Pertimbangkan halaman yang mengimplementasikan formulir "hubungi kami" dasar untuk model Contact
:
Untuk sampel dalam dokumen ini, DbContext
diinisialisasi dalam file Program.cs .
Database dalam memori memerlukan paket 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();
Model data:
using System.ComponentModel.DataAnnotations;
namespace RazorPagesContacts.Models
{
public class Customer
{
public int Id { get; set; }
[Required, StringLength(10)]
public string? Name { get; set; }
}
}
Konteks db:
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>();
}
}
File tampilan 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 halaman 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");
}
}
Berdasarkan konvensi, kelas PageModel
disebut <PageName>Model
dan berada dalam namespace layanan yang sama dengan halaman.
Kelas PageModel
memungkinkan pemisahan logika halaman dari presentasinya. Ini mendefinisikan penanganan halaman untuk permintaan yang dikirim ke halaman dan data yang digunakan untuk merender halaman. Pemisahan ini memungkinkan:
- Pengelolaan dependensi halaman melalui injeksi dependensi.
- Pengujian unit
Halaman memiliki OnPostAsync
metode handler, yang berjalan berdasarkan POST
permintaan (saat pengguna memposting formulir). Metode penanganan untuk kata kerja HTTP apa pun dapat ditambahkan. Penanganan yang paling umum adalah:
OnGet
untuk menginisialisasi status yang diperlukan halaman. Pada kode sebelumnya, metodeOnGet
menampilkanCreate.cshtml
Razor Page.OnPost
untuk menangani pengiriman formulir.
Akhiran penamaan Async
sifatnya opsional tetapi sering digunakan oleh konvensi untuk fungsi asinkron. Kode sebelumnya umum untuk Razor Pages.
Jika Anda terbiasa dengan aplikasi ASP.NET yang menggunakan pengontrol dan tampilan:
- Kode
OnPostAsync
dalam contoh sebelumnya terlihat mirip dengan kode pengontrol biasa. - Sebagian besar primitif MVC seperti pengikatan model, validasi, dan hasil tindakan bekerja dengan cara yang sama seperti Pengontrol dan Razor Pages.
Metode OnPostAsync
sebelumnya:
[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");
}
Alur dasar OnPostAsync
:
Periksa kesalahan validasi.
- Jika tidak ada kesalahan, simpan data dan alihkan.
- Jika ada kesalahan, tampilkan kembali halaman dengan pesan validasi. Dalam banyak kasus, kesalahan validasi akan terdeteksi pada klien, dan tidak pernah dikirimkan ke server.
File tampilan 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>
HTML yang dirender dari 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>
Dalam kode sebelumnya, posting formulir:
Dengan data yang valid:
Metode penanganan
OnPostAsync
memanggil metode pembantu RedirectToPage.RedirectToPage
mengembalikan instans dari RedirectToPageResult.RedirectToPage
:- Merupakan hasil tindakan.
- Mirip dengan
RedirectToAction
atauRedirectToRoute
(digunakan dalam pengontrol dan tampilan). - Dikustomisasi untuk halaman. Dalam sampel sebelumnya, ini dialihkan ke halaman Indeks akar (
/Index
).RedirectToPage
dijelaskan lebih lanjut di bagian pembuatan URL untuk Pages.
Dengan kesalahan validasi yang diteruskan ke server:
- Metode penanganan
OnPostAsync
memanggil metode pembantu Page.Page
mengembalikan instans dari PageResult. PengembalianPage
mirip dengan bagaimana tindakan di pengontrol mengembalikanView
.PageResult
adalah jenis pengembalian default untuk metode penanganan. Metode penanganan yang mengembalikanvoid
merender halaman. - Pada contoh sebelumnya, memposting formulir tanpa nilai akan menyebabkan ModelState.IsValid mengembalikan false. Dalam sampel ini, tidak ada kesalahan validasi yang ditampilkan pada klien. Penanganan kesalahan validasi dibahas nanti dalam dokumen ini.
[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"); }
- Metode penanganan
Dengan kesalahan validasi yang terdeteksi oleh validasi sisi klien:
- Data tidak diposting ke server.
- Validasi sisi klien dijelaskan nanti dalam dokumen ini.
Properti Customer
menggunakan atribut [BindProperty]
untuk ikut serta dalam pengikatan model:
[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]
tidak boleh digunakan pada model yang berisi properti yang tidak boleh diubah oleh klien. Untuk informasi lebih lanjut, lihat Overposting.
Razor Pages, secara default, hanya mengikat properti dengan kata kerja non-GET
. Pengikatan ke properti menghilangkan kebutuhan untuk menulis kode guna mengonversi data HTTP ke jenis model. Pengikatan mengurangi kode dengan menggunakan properti yang sama untuk merender bidang isian borang (<input asp-for="Customer.Name">
) dan menerima input.
Peringatan
Karena alasan keamanan, Anda harus memilih untuk mengikat GET
data permintaan ke properti model halaman. Verifikasi input pengguna sebelum memetakannya ke properti. Memilih pengikatan GET
berguna saat menangani skenario yang mengandalkan string kueri atau nilai rute.
Untuk mengikat properti pada permintaan GET
, atur properti SupportsGet
atribut [BindProperty]
ke true
:
[BindProperty(SupportsGet = true)]
Untuk informasi lebih lanjut, lihat ASP.NET Core Community Standup: Bind on GET discussion (YouTube).
Meninjau file tampilan 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>
- Dalam kode sebelumnya, pembantu tag
<input asp-for="Customer.Name" />
input mengikat elemen HTML<input>
keCustomer.Name
ekspresi model. @addTagHelper
membuat Pembantu Tag tersedia.
Halaman home
Index.cshtml
home adalah halaman:
@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>
Kelas PageModel
terkait (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();
}
}
File Index.cshtml
berisi markup berikut:
<a asp-page="./Edit" asp-route-id="@contact.Id">Edit</a> |
Pembantu <a /a>
Tag Jangkar menggunakan asp-route-{value}
atribut untuk menghasilkan tautan ke halaman Edit. Tautan berisi data rute dengan ID kontak. Contohnya,https://localhost:5001/Edit/1
. Pembantu Tag mengaktifkan kode sisi server untuk berpartisipasi dalam membuat dan merender elemen HTML dalam file Razor.
File Index.cshtml
berisi markup untuk membuat tombol hapus untuk setiap kontak pelanggan:
<button type="submit" asp-page-handler="delete" asp-route-id="@contact.Id">delete</button>
HTML yang dirender:
<button type="submit" formaction="/Customers?id=1&handler=delete">delete</button>
Saat tombol hapus ditampilkan dalam HTML, formaction-nya menyertakan parameter untuk:
- ID kontak pelanggan, ditentukan oleh atribut
asp-route-id
. handler
, ditentukan oleh atributasp-page-handler
.
Saat tombol dipilih, permintaan POST
formulir dikirim ke server. Berdasarkan konvensi, nama metode penanganan dipilih berdasarkan nilai parameter handler
menurut skema OnPost[handler]Async
.
Karena handler
adalah delete
dalam contoh ini, metode penanganan OnPostDeleteAsync
digunakan untuk memproses permintaan POST
. Jika asp-page-handler
diatur ke nilai yang berbeda, seperti remove
, metode penanganan dengan nama OnPostRemoveAsync
dipilih.
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();
}
Metode OnPostDeleteAsync
:
- Mendapatkan
id
dari string kueri. - Kueri database untuk kontak pelanggan dengan
FindAsync
. - Jika kontak pelanggan ditemukan, ini akan dihapus dan database diperbarui.
- Memanggil RedirectToPage untuk mengalihkan ke halaman Indeks akar (
/Index
).
File 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");}
}
Baris pertama berisi arahan @page "{id:int}"
. Batasan perutean "{id:int}"
memberi tahu halaman untuk menerima permintaan ke halaman yang berisi data rute int
. Jika permintaan ke halaman tidak berisi data rute yang dapat dikonversi ke int
, runtime bahasa umum mengembalikan kesalahan HTTP 404 (tidak ditemukan). Untuk menjadikan ID bersifat opsional, tambahkan ?
ke batasan rute:
@page "{id:int?}"
File 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);
}
}
Validasi
Aturan validasi:
- Secara deklaratif ditentukan dalam kelas model.
- Diberlakukan di mana-mana di aplikasi.
Namespace layanan System.ComponentModel.DataAnnotations menyediakan satu set atribut validasi bawaan yang diterapkan secara deklaratif ke kelas atau properti. DataAnnotations juga berisi atribut pemformatan seperti [DataType]
yang membantu pemformatan dan tidak memberikan validasi apa pun.
Pertimbangkan 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; }
}
}
Dengan file tampilan Create.cshtml
berikut:
@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>
Kode sebelumnya:
Termasuk skrip validasi jQuery dan jQuery.
<div />
Menggunakan dan<span />
Tag Helpers untuk mengaktifkan:- Validasi sisi klien.
- Perenderan kesalahan validasi.
Menghasilkan HTML berikut:
<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>
Memposting formulir Buat tanpa nilai nama akan menampilkan pesan kesalahan "Bidang Nama diperlukan." pada formulir. Jika JavaScript diaktifkan pada klien, browser menampilkan kesalahan tanpa memposting ke server.
Atribut [StringLength(10)]
menghasilkan data-val-length-max="10"
pada HTML yang dirender. data-val-length-max
mencegah browser agar tidak memasukkan lebih dari panjang maksimum yang ditentukan. Jika alat seperti Fiddler digunakan untuk mengedit dan memutar kembali pos:
- Dengan nama yang melebihi 10.
- Pesan kesalahan "Nama bidang harus berupa string dengan panjang maksimum 10." dikembalikan.
Perhatikan model Movie
berikut:
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; }
}
}
Atribut validasi menentukan perilaku yang akan diberlakukan pada properti model tempatnya diterapkan:
Atribut
Required
danMinimumLength
menunjukkan bahwa properti harus memiliki nilai, tetapi tidak ada yang mencegah pengguna memasukkan spasi kosong untuk memenuhi validasi ini.Atribut
RegularExpression
digunakan untuk membatasi karakter apa yang dapat dimasukkan. Dalam kode sebelumnya, "Genre":- Hanya boleh menggunakan huruf.
- Huruf pertama harus huruf besar. Spasi kosong, angka, dan karakter khusus tidak diperbolehkan.
RegularExpression
"Rating":- Mengharuskan karakter pertama berupa huruf besar.
- Mengizinkan karakter dan angka khusus di spasi berikutnya. "PG-13" valid untuk rating, tetapi gagal untuk "Genre".
Atribut
Range
membatasi nilai dalam rentang yang ditentukan.Atribut
StringLength
mengatur panjang maksimum properti string, dan secara opsional, panjang minimumnya.Jenis nilai (seperti
decimal
,int
,float
,DateTime
) secara inheren diperlukan dan tidak memerlukan atribut[Required]
.
Halaman Buat untuk model Movie
menunjukkan kesalahan tampilan dengan nilai yang tidak valid:
Untuk informasi selengkapnya, lihat:
Isolasi CSS
Isolasi gaya CSS ke halaman, tampilan, dan komponen individual untuk mengurangi atau menghindari:
- Dependensi pada gaya global yang sulit dipertahankan.
- Konflik gaya dalam konten yang disarangkan.
Guna menambahkan file CSS cakupan untuk halaman atau tampilan, tempatkan gaya CSS di file .cshtml.css
pengiring yang cocok dengan nama file .cshtml
. Dalam contoh berikut, file Index.cshtml.css
menyediakan gaya CSS yang hanya diterapkan pada halaman atau tampilan Index.cshtml
.
Pages/Index.cshtml.css
(Razor Pages) atau Views/Index.cshtml.css
(MVC):
h1 {
color: red;
}
Isolasi CSS terjadi pada waktu pembuatan. Kerangka kerja menulis ulang pemilih CSS agar sesuai dengan markup yang dirender oleh halaman atau tampilan aplikasi. Gaya CSS yang ditulis kembali dibundel dan diproduksi sebagai aset statis, {APP ASSEMBLY}.styles.css
. Tempat penampung {APP ASSEMBLY}
adalah nama rakitan proyek. Tautan ke gaya CSS yang dibundel ditempatkan di tata letak aplikasi.
Di konten <head>
dari Pages/Shared/_Layout.cshtml
aplikasi (Razor Pages) atau Views/Shared/_Layout.cshtml
(MVC), tambahkan atau konfirmasi keberadaan tautan ke gaya CSS yang dibundel:
<link rel="stylesheet" href="~/{APP ASSEMBLY}.styles.css" />
Dalam contoh berikut, nama rakitan aplikasi adalah WebApp
:
<link rel="stylesheet" href="WebApp.styles.css" />
Gaya yang ditentukan dalam file CSS cakupan hanya diterapkan pada output yang dirender dari file yang cocok. Dalam contoh sebelumnya, semua deklarasi CSS h1
yang ditentukan di tempat lain dalam aplikasi tidak bertentangan dengan gaya judul Index
. Aturan kaskading dan pewarisan gaya CSS tetap berlaku untuk file CSS cakupan. Misalnya, gaya yang diterapkan langsung ke elemen <h1>
dalam file Index.cshtml
menimpa gaya file CSS cakupan di Index.cshtml.css
.
Catatan
Untuk menjamin isolasi gaya CSS saat terjadi bundling, mengimpor CSS dalam blok kode Razor tidak didukung.
Isolasi CSS hanya berlaku untuk elemen HTML. Isolasi CSS tidak didukung untuk Pembantu Tag.
Dalam file CSS yang dibundel, setiap halaman, tampilan, atau komponen Razor dikaitkan dengan pengidentifikasi cakupan dalam b-{STRING}
format, di mana tempat penampung {STRING}
adalah string dengan sepuluh karakter yang dihasilkan oleh kerangka kerja. Contoh berikut memberikan gaya untuk elemen <h1>
sebelumnya di halaman Index
aplikasi Razor Pages:
/* /Pages/Index.cshtml.rz.scp.css */
h1[b-3xxtam6d07] {
color: red;
}
Di halaman Index
tempat gaya CSS diterapkan dari file yang dibundel, pengidentifikasi cakupan ditambahkan sebagai atribut HTML:
<h1 b-3xxtam6d07>
Pengidentifikasi sifatnya unik untuk suatu aplikasi. Pada waktu pembuatan, bundel proyek dibuat dengan konvensi {STATIC WEB ASSETS BASE PATH}/Project.lib.scp.css
, di mana tempat penampung {STATIC WEB ASSETS BASE PATH}
adalah jalur dasar aset web statis.
Jika proyek lain digunakan, seperti paket NuGet atau pustaka kelas Razor, file yang dibundel:
- Mereferensikan gaya menggunakan impor CSS.
- Tidak diterbitkan sebagai aset web statis aplikasi yang menggunakan gaya.
Dukungan praprosesor CSS
Praprosesor CSS berguna untuk meningkatkan pengembangan CSS dengan memanfaatkan fitur seperti variabel, bersarang, modul, mixin, dan pewarisan. Meskipun isolasi CSS tidak secara native mendukung praprosesor CSS seperti Sass atau Less, integrasi praprosesor CSS berjalan mulus selama kompilasi praprosesor terjadi sebelum kerangka kerja menulis kembali pemilih CSS selama proses pembuatan. Menggunakan Visual Studio sebagai contoh, konfigurasikan kompilasi praprosesor yang ada sebagai tugas Sebelum Build di Visual Studio Task Runner Explorer.
Banyak paket NuGet pihak ketiga, seperti AspNetCore.SassCompiler
, yang dapat mengompilasi file SASS/SCSS di awal proses pembuatan sebelum isolasi CSS terjadi, dan tidak memerlukan konfigurasi tambahan.
Konfigurasi isolasi CSS
Isolasi CSS memungkinkan konfigurasi untuk beberapa skenario tingkat lanjut, seperti ketika ada dependensi pada alat atau alur kerja yang ada.
Mengkustomisasi format pengidentifikasi cakupan
Di bagian ini, tempat penampung {Pages|Views}
adalah Pages
untuk aplikasi Razor Pages atau Views
untuk aplikasi MVC.
Secara default, pengidentifikasi cakupan menggunakan format b-{STRING}
, di mana tempat penampung {STRING}
adalah string sepuluh karakter yang dihasilkan oleh kerangka kerja. Untuk mengkustomisasi format pengidentifikasi cakupan, perbarui file proyek menjadi pola yang diinginkan:
<ItemGroup>
<None Update="{Pages|Views}/Index.cshtml.css" CssScope="custom-scope-identifier" />
</ItemGroup>
Pada contoh sebelumnya, CSS yang dihasilkan untuk Index.cshtml.css
mengubah pengidentifikasi cakupannya dari b-{STRING}
menjadi custom-scope-identifier
.
Gunakan pengidentifikasi cakupan untuk mencapai warisan dengan file CSS cakupan. Dalam contoh file proyek berikut, file BaseView.cshtml.css
berisi gaya umum di seluruh tampilan. File DerivedView.cshtml.css
mewarisi gaya ini.
<ItemGroup>
<None Update="{Pages|Views}/BaseView.cshtml.css" CssScope="custom-scope-identifier" />
<None Update="{Pages|Views}/DerivedView.cshtml.css" CssScope="custom-scope-identifier" />
</ItemGroup>
Gunakan operator wildcard (*
) untuk berbagi pengidentifikasi cakupan di beberapa file:
<ItemGroup>
<None Update="{Pages|Views}/*.cshtml.css" CssScope="custom-scope-identifier" />
</ItemGroup>
Mengubah jalur dasar untuk aset web statis
File CSS cakupan dibuat di akar aplikasi. Dalam file proyek, gunakan properti StaticWebAssetBasePath
untuk mengubah jalur default. Contoh berikut menempatkan file CSS terlingkup, dan rest aset aplikasi, di _content
jalur:
<PropertyGroup>
<StaticWebAssetBasePath>_content/$(PackageId)</StaticWebAssetBasePath>
</PropertyGroup>
Menonaktifkan bundling otomatis
Untuk menolak cara kerangka menerbitkan dan memuat file cakupan saat runtime bahasa umum, gunakan properti DisableScopedCssBundling
. Saat menggunakan properti ini, alat atau proses lain bertanggung jawab untuk mengambil file CSS yang terisolasi dari direktori obj
dan menerbitkan serta memuatnya pada runtime bahasa umum:
<PropertyGroup>
<DisableScopedCssBundling>true</DisableScopedCssBundling>
</PropertyGroup>
Dukungan pustaka kelas Razor (RCL)
Saat pustaka kelas Razor (RCL) menyediakan gaya terisolasi, atribut href
tag <link>
menunjuk ke {STATIC WEB ASSET BASE PATH}/{PACKAGE ID}.bundle.scp.css
, dengan tempat penampung:
{STATIC WEB ASSET BASE PATH}
: Jalur dasar aset web statis.{PACKAGE ID}
: pengidentifikasi paket pustaka. Pengidentifikasi paket diatur ke default, yakni nama rakitan proyek, jika pengidentifikasi paket tidak ditentukan dalam file proyek.
Dalam contoh berikut:
- Jalur dasar aset web statis adalah
_content/ClassLib
. - Nama rakitan pustaka kelas adalah
ClassLib
.
Pages/Shared/_Layout.cshtml
(Razor Pages) atau Views/Shared/_Layout.cshtml
(MVC):
<link href="_content/ClassLib/ClassLib.bundle.scp.css" rel="stylesheet">
Untuk informasi lebih lanjut tentang RCL, lihat artikel berikut:
- Antarmuka pengguna Razor yang dapat digunakan kembali di pustaka kelas dengan ASP.NET Core
- Menggunakan komponen Razor ASP.NET Core dari pustaka kelas Razor (RCL)
Untuk informasi tentang isolasi CSS Blazor, lihat Isolasi CSS Blazor ASP.NET Core.
Menangani permintaan HEAD dengan fallback penanganan OnGet
Permintaan HEAD
memungkinkan pengambilan header untuk sumber daya tertentu. Tidak seperti permintaan GET
, permintaan HEAD
tidak mengembalikan isi respons.
Biasanya, penanganan OnHead
dibuat dan dipanggil untuk permintaan HEAD
:
public void OnHead()
{
HttpContext.Response.Headers.Add("Head Test", "Handled by OnHead!");
}
Razor Pages kembali memanggil penanganan OnGet
jika tidak ada penanganan OnHead
yang ditentukan.
XSRF/CSRF dan Razor Pages
Razor Pages dilindungi oleh Validasi anti-pemalsuan. FormTagHelper menyuntikkan token anti-pemalsuan ke dalam elemen formulir HTML.
Menggunakan Tata Letak, parsial, template, dan Pembantu Tag dengan Razor Pages
Pages berfungsi dengan semua kemampuan mesin tampilan Razor. Tata letak, parsial, template, Pembantu Tag, _ViewStart.cshtml
, dan _ViewImports.cshtml
bekerja dengan cara yang sama seperti tampilan Razor konvensional.
Mari kita rapikan halaman ini dengan memanfaatkan beberapa kemampuan tersebut.
Tambahkan halaman tata letak ke 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>
- Mengontrol tata letak setiap halaman (kecuali halaman menolak tata letak).
- Mengimpor struktur HTML seperti JavaScript dan stylesheet.
- Konten halaman Razor dirender di tempat
@RenderBody()
dipanggil.
Untuk informasi lebih lanjut, lihat halaman tata letak.
Properti Tata letak diatur di Pages/_ViewStart.cshtml
:
@{
Layout = "_Layout";
}
Tata letaknya ada di folder Pages/Shared. Halaman mencari tampilan lain (tata letak, template, parsial) secara hierarkis, dimulai dari folder yang sama dengan halaman saat ini. Tata letak dalam folder Pages/Shared dapat digunakan dari halaman Razor mana pun di pada folder Pages.
File tata letak harus masuk ke dalam folder Pages/Shared.
Sebaiknya jangan meletakkan file tata letak di folder Views/Shared. Views/Shared adalah pola tampilan MVC. Razor Pages dimaksudkan untuk mengandalkan hierarki folder, bukan konvensi jalur.
Lihat pencarian dari Razor Page yang menyertakan folder Page. Tata letak, template, dan parsial yang digunakan dengan pengontrol MVC dan tampilan Razor konvensional berfungsi.
Tambahkan file Pages/_ViewImports.cshtml
:
@namespace RazorPagesContacts.Pages
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
@namespace
dijelaskan nanti dalam tutorial. Arahan @addTagHelper
membawa Pembantu Tag bawaan ke semua halaman dalam folder Pages.
Arahan @namespace
diatur pada halaman:
@page
@namespace RazorPagesIntro.Pages.Customers
@model NameSpaceModel
<h2>Name space</h2>
<p>
@Model.Message
</p>
Arahan @namespace
mengatur namespace layanan untuk halaman. Arahan @model
tidak perlu menyertakan namespace layanan.
Jika arahan @namespace
ada dalam _ViewImports.cshtml
, namespace layanan yang ditentukan akan menyediakan awalan untuk namespace layanan yang dihasilkan di Page yang mengimpor arahan @namespace
. Namespace rest yang dihasilkan (bagian akhiran) adalah jalur relatif yang dipisahkan titik antara folder yang berisi _ViewImports.cshtml
dan folder yang berisi halaman.
Misalnya, kelas PageModel
Pages/Customers/Edit.cshtml.cs
secara eksplisit mengatur namespace layanan:
namespace RazorPagesContacts.Pages
{
public class EditModel : PageModel
{
private readonly AppDbContext _db;
public EditModel(AppDbContext db)
{
_db = db;
}
// Code removed for brevity.
File Pages/_ViewImports.cshtml
mengatur namespace layanan berikut:
@namespace RazorPagesContacts.Pages
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
Namespace layanan yang dihasilkan untuk Pages/Customers/Edit.cshtml
RazorPage sama dengan kelas PageModel
.
@namespace
juga berfungsi dengan tampilan konvensionalRazor.
Pertimbangkan file tampilan 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>
File tampilan Pages/Customers/Create.cshtml
yang diperbarui dengan _ViewImports.cshtml
dan file tata letak sebelumnya:
@page
@model CreateModel
<p>Enter a customer name:</p>
<form method="post">
Name:
<input asp-for="Customer!.Name" />
<input type="submit" />
</form>
Dalam kode sebelumnya, _ViewImports.cshtml
mengimpor namespace layanan dan Pembantu Tag. File tata letak mengimpor file JavaScript.
Proyek starter Razor Pages berisi Pages/_ValidationScriptsPartial.cshtml
, yang menghubungkan validasi sisi klien.
Untuk informasi lebih lanjut tentang tampilan parsial, lihat Tampilan parsial di ASP.NET Core.
Pembuatan URL untuk Pages
Halaman Create
, yang ditampilkan sebelumnya, menggunakan 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");
}
}
Aplikasi ini memiliki struktur file/folder berikut:
/Pages
Index.cshtml
Privacy.cshtml
/Customers
Create.cshtml
Edit.cshtml
Index.cshtml
Halaman Pages/Customers/Create.cshtml
dan Pages/Customers/Edit.cshtml
dialihkan ke Pages/Customers/Index.cshtml
setelah berhasil. ./Index
string adalah nama halaman relatif yang digunakan untuk mengakses halaman sebelumnya. Ini digunakan untuk membuat URL ke halaman Pages/Customers/Index.cshtml
. Contohnya:
Url.Page("./Index", ...)
<a asp-page="./Index">Customers Index Page</a>
RedirectToPage("./Index")
/Index
nama halaman absolut digunakan untuk membuat URL ke halaman Pages/Index.cshtml
. Contohnya:
Url.Page("/Index", ...)
<a asp-page="/Index">Home Index Page</a>
RedirectToPage("/Index")
Nama halaman adalah jalur ke halaman dari folder /Pages akar termasuk awalan /
(misalnya, /Index
). Sampel pembuatan URL sebelumnya menawarkan opsi yang disempurnakan dan kemampuan fungsional jika dibandingkan dengan hard-coding URL. Pembuatan URL menggunakan perutean dan dapat membuat serta mengodekan parameter sesuai dengan cara rute ditentukan di jalur tujuan.
Pembuatan URL untuk halaman mendukung nama relatif. Tabel berikut menunjukkan halaman Indeks mana yang dipilih menggunakan parameter RedirectToPage
yang berbeda di Pages/Customers/Create.cshtml
.
RedirectToPage(x) | Halaman |
---|---|
RedirectToPage("/Index") | Pages/Index |
RedirectToPage("./Index"); | Pages/Customers/Index |
RedirectToPage("../Index") | Pages/Index |
RedirectToPage("Index") | Pages/Customers/Index |
RedirectToPage("Index")
, RedirectToPage("./Index")
, dan RedirectToPage("../Index")
adalah nama relatif. Parameter RedirectToPage
digabungkan dengan jalur halaman saat ini untuk menghitung nama halaman tujuan.
Tautan nama relatif berguna saat membangun situs dengan struktur yang kompleks. Saat nama relatif digunakan untuk menautkan antar-halaman dalam folder:
- Mengganti nama folder tidak merusak tautan relatif.
- Tautan tidak rusak karena tautan tidak menyertakan nama folder.
Untuk mengalihkan ke halaman di Area yang berbeda, tentukan area:
RedirectToPage("/Index", new { area = "Services" });
Untuk informasi lebih lanjut, lihat Area di ASP.NET Core serta Rute dan konvensi aplikasi Razor Pages di ASP.NET Core.
Atribut ViewData
Data dapat diteruskan ke halaman dengan ViewDataAttribute. Properti dengan atribut [ViewData]
memiliki nilai yang disimpan dan dimuat dari ViewDataDictionary.
Dalam contoh berikut, AboutModel
menerapkan atribut [ViewData]
ke properti Title
:
public class AboutModel : PageModel
{
[ViewData]
public string Title { get; } = "About";
public void OnGet()
{
}
}
Di halaman Tentang, akses properti Title
sebagai properti model:
<h1>@Model.Title</h1>
Dalam tata letak, judul dibaca dari kamus ViewData:
<!DOCTYPE html>
<html lang="en">
<head>
<title>@ViewData["Title"] - WebApplication</title>
...
TempData
ASP.NET Core mengekspos TempData. Properti ini menyimpan data sampai data dibaca. Metode Keep dan Peek dapat digunakan untuk memeriksa data tanpa menghapusnya. TempData
berguna untuk pengalihan, ketika data diperlukan untuk lebih dari satu permintaan.
Kode berikut menetapkan nilai Message
menggunakan 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");
}
}
Markup berikut dalam file Pages/Customers/Index.cshtml
menampilkan nilai Message
menggunakan TempData
.
<h3>Msg: @Model.Message</h3>
Model halaman Pages/Customers/Index.cshtml.cs
menerapkan atribut [TempData]
ke properti Message
.
[TempData]
public string Message { get; set; }
Untuk informasi lebih lanjut, lihat TempData.
Beberapa penanganan per halaman
Halaman berikut menghasilkan markup untuk dua penanganan menggunakan Pembantu Tag 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>
Formulir dalam contoh sebelumnya memiliki dua tombol kirim, masing-masing menggunakan FormActionTagHelper
untuk mengirim ke URL yang berbeda. Atribut asp-page-handler
adalah pendamping asp-page
. asp-page-handler
menghasilkan URL yang dikirimkan ke setiap metode penanganan yang ditentukan oleh halaman. asp-page
tidak ditentukan karena sampel menautkan ke halaman saat ini.
Model halaman :
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();
}
}
}
Kode sebelumnya menggunakan metode penanganan bernama. Metode pengendali bernama dibuat dengan mengambil teks dalam nama setelah On<HTTP Verb>
dan sebelum Async
(jika ada). Dalam contoh sebelumnya, metode halaman adalah OnPostJoinListAsync dan OnPostJoinListUCAsync. Dengan OnPost dan Async dihapus, nama penangannya adalah JoinList
dan JoinListUC
.
<input type="submit" asp-page-handler="JoinList" value="Join" />
<input type="submit" asp-page-handler="JoinListUC" value="JOIN UC" />
Dengan menggunakan kode sebelumnya, jalur URL yang mengirimkan ke OnPostJoinListAsync
adalah https://localhost:5001/Customers/CreateFATH?handler=JoinList
. Jalur URL yang mengirimkan ke OnPostJoinListUCAsync
adalah https://localhost:5001/Customers/CreateFATH?handler=JoinListUC
.
Rute kustom
Gunakan arahan @page
untuk:
- Menentukan rute kustom ke halaman. Misalnya, rute ke halaman Tentang dapat diatur ke
/Some/Other/Path
dengan@page "/Some/Other/Path"
. - Menambahkan segmen ke rute default halaman. Misalnya, segmen "item" dapat ditambahkan ke rute default halaman dengan
@page "item"
. - Menambahkan parameter ke rute default halaman. Misalnya, parameter ID,
id
, dapat diperlukan untuk halaman dengan@page "{id}"
.
Jalur relatif akar yang ditunjuk oleh tilde (~
) di awal jalur didukung. Misalnya, @page "~/Some/Other/Path"
sama dengan @page "/Some/Other/Path"
.
Jika Anda tidak menyukai ?handler=JoinList
string kueri di URL, ubah rute untuk meletakkan nama penanganan di bagian jalur URL. Rute dapat dikustomisasi dengan menambahkan template rute yang diapit tanda kutip ganda setelah arahan @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>
Dengan menggunakan kode sebelumnya, jalur URL yang mengirimkan ke OnPostJoinListAsync
adalah https://localhost:5001/Customers/CreateFATH/JoinList
. Jalur URL yang mengirimkan ke OnPostJoinListUCAsync
adalah https://localhost:5001/Customers/CreateFATH/JoinListUC
.
?
setelah handler
berarti parameter rute adalah opsional.
Kolokasi file JavaScript (JS)
Kolokasi file JavaScript (JS) untuk halaman dan tampilan adalah cara mudah untuk mengatur skrip di aplikasi.
Kolokasikan file JS menggunakan konvensi ekstensi nama file berikut:
- Halaman dari Aplikasi halaman Razor dan tampilan aplikasi MVC:
.cshtml.js
. Contoh:Pages/Index.cshtml.js
untuk halamanIndex
dari aplikasi Halaman Razor diPages/Index.cshtml
.Views/Home/Index.cshtml.js
untuk tampilanIndex
aplikasi MVC diViews/Home/Index.cshtml
.
File JS yang dikumpulkan dapat diatasi secara publik menggunakan jalur ke file dalam proyek:
Halaman dan tampilan dari file skrip yang dikolokasi di aplikasi:
{PATH}/{PAGE, VIEW, OR COMPONENT}.{EXTENSION}.js
- Tempat penampung
{PATH}
adalah jalur ke halaman, tampilan, atau komponen. - Tempat penampung
{PAGE, VIEW, OR COMPONENT}
adalah halaman, tampilan, atau komponen. - Tempat penampung
{EXTENSION}
cocok dengan ekstensi halaman, tampilan, atau komponen, baikrazor
ataucshtml
.
RazorContoh halaman:
File JS untuk halaman
Index
ditempatkan di folderPages
(Pages/Index.cshtml.js
) di sebelah halamanIndex
(Pages/Index.cshtml
). Di halamanIndex
, skrip direferensikan pada jalur di folderPages
:@section Scripts { <script src="~/Pages/Index.cshtml.js"></script> }
- Tempat penampung
Tata letak Pages/Shared/_Layout.cshtml
default dapat dikonfigurasi untuk menyertakan file yang dikolokasi JS , menghilangkan kebutuhan untuk mengonfigurasi setiap halaman satu per satu:
<script asp-src-include="@(ViewContext.View.Path).js"></script>
Unduhan sampel menggunakan cuplikan kode sebelumnya untuk menyertakan file yang dikolokasi JS dalam tata letak default.
Saat aplikasi diterbitkan, kerangka kerja secara otomatis memindahkan skrip ke akar web. Pada contoh sebelumnya, skrip dipindahkan ke bin\Release\{TARGET FRAMEWORK MONIKER}\publish\wwwroot\Pages\Index.cshtml.js
, dengan tempat penampung {TARGET FRAMEWORK MONIKER}
adalah Target Framework Moniker (TFM). Tidak diperlukan perubahan pada URL relatif skrip di halaman Index
.
Saat aplikasi diterbitkan, kerangka kerja secara otomatis memindahkan skrip ke akar web. Pada contoh sebelumnya, skrip dipindahkan ke bin\Release\{TARGET FRAMEWORK MONIKER}\publish\wwwroot\Components\Pages\Index.razor.js
, dengan tempat penampung {TARGET FRAMEWORK MONIKER}
adalah Target Framework Moniker (TFM). Tidak diperlukan perubahan pada URL relatif skrip di komponen Index
.
Untuk skrip yang disediakan oleh pustaka kelas (RCL) Razor:
_content/{PACKAGE ID}/{PATH}/{PAGE, VIEW, OR COMPONENT}.{EXTENSION}.js
- Tempat penampung
{PACKAGE ID}
adalah pengidentifikasi paket RCL (atau nama pustaka untuk pustaka kelas yang dirujuk oleh aplikasi). - Tempat penampung
{PATH}
adalah jalur ke halaman, tampilan, atau komponen. Jika komponen Razor terletak di akar RCL, segmen jalur tidak disertakan. - Tempat penampung
{PAGE, VIEW, OR COMPONENT}
adalah halaman, tampilan, atau komponen. - Tempat penampung
{EXTENSION}
cocok dengan ekstensi halaman, tampilan, atau komponen, baikrazor
ataucshtml
.
- Tempat penampung
Konfigurasi dan pengaturan tingkat lanjut
Konfigurasi dan pengaturan di bagian berikut tidak diperlukan oleh sebagian besar aplikasi.
Untuk mengonfigurasi opsi tingkat lanjut, gunakan overload AddRazorPages yang mengonfigurasi 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();
Gunakan RazorPagesOptions untuk mengatur direktori akar untuk halaman, atau menambahkan konvensi model aplikasi untuk halaman. Untuk informasi lebih lanjut tentang konvensi, lihat Konvensi otorisasi Razor Pages.
Untuk mengompilasi tampilan sebelumnya, lihat kompilasi tampilan Razor.
Menentukan bahwa Razor Pages berada di akar konten
Secara default, Razor Pages berakar di direktori /Pages. Tambahkan WithRazorPagesAtContentRoot untuk menentukan bahwa Razor Pages Anda berada di akar konten (ContentRootPath) aplikasi:
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();
Menentukan bahwa Razor Pages berada di direktori akar kustom
Tambahkan WithRazorPagesRoot untuk menentukan bahwa Razor Pages berada di direktori akar kustom di aplikasi (berikan jalur relatif):
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();
Sumber Daya Tambahan:
- Lihat Mulai menggunakan Razor Pages, yang dibuat berdasarkan pengantar ini.
- Mengotorisasi atribut dan Razor Pages
- Mengunduh atau melihat sampel kode
- Gambaran umum ASP.NET Core
- Referensi sintaks Razor untuk ASP.NET Core
- Area di ASP.NET Core
- Tutorial: Mulai menggunakan Razor Pages di ASP.NET Core
- Konvensi otorisasi Razor Pages di ASP.NET Core
- Konvensi rute dan aplikasi Razor Pages di ASP.NET Core
- Pengujian unit Razor Pages di ASP.NET Core
- Tampilan parsial di ASP.NET Core
- Visual Studio 2019 16.4 atau yang lebih baru dengan beban kerja ASP.NET dan pengembangan web
- .NET Core 3.1 SDK
- Visual Studio 2019 16.8 atau versi terbaru dengan beban kerja ASP.NET dan pengembangan web
- .NET 5.0 SDK
Buat proyek Razor Pages
Lihat Mulai menggunakan Razor Pages untuk petunjuk terperinci tentang cara membuat proyek Razor Pages.
Razor Pages
Razor Pages diaktifkan di 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();
});
}
}
@page
<h1>Hello, world!</h1>
<h2>The time on the server is @DateTime.Now</h2>
Kode sebelumnya sangat mirip dengan file tampilan Razor yang digunakan dalam aplikasi ASP.NET Core dengan pengontrol dan tampilan. Yang membuatnya berbeda adalah arahan @page
. @page
membuat file menjadi tindakan MVC - yang berarti menangani permintaan secara langsung, tanpa melalui pengontrol. @page
harus menjadi arahan Razor pertama di halaman. @page
memengaruhi perilaku konstruksi Razor lainnya. Nama file Razor Pages memiliki akhiran .cshtml
.
Halaman serupa, menggunakan kelas PageModel
, ditampilkan dalam dua file berikut. File Pages/Index2.cshtml
:
@page
@using RazorPagesIntro.Pages
@model Index2Model
<h2>Separate page model</h2>
<p>
@Model.Message
</p>
Model halaman 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 }";
}
}
}
Menurut konvensi, file kelas PageModel
memiliki nama yang sama dengan file Razor Pages dengan .cs
yang ditambahkan. Misalnya, Razor Pages sebelumnya adalah Pages/Index2.cshtml
. File yang berisi kelas PageModel
diberi nama Pages/Index2.cshtml.cs
.
Asosiasi jalur URL ke halaman ditentukan oleh lokasi halaman di sistem file. Tabel berikut menunjukkan jalur Razor Pages dan URL yang cocok:
Nama file dan jalur | URL yang cocok |
---|---|
/Pages/Index.cshtml |
/ atau /Index |
/Pages/Contact.cshtml |
/Contact |
/Pages/Store/Contact.cshtml |
/Store/Contact |
/Pages/Store/Index.cshtml |
/Store atau /Store/Index |
Catatan:
- Runtime bahasa umum mencari file Razor Pages dalam folder Pages secara default.
Index
adalah halaman bawaan jika URL tidak menyertakan halaman.
Menulis formulir dasar
Razor Pages dirancang untuk menjadikan pola umum yang digunakan dengan browser web mudah diimplementasikan saat membuat aplikasi. Pengikatan model, Pembantu Tag, dan pembantu HTML, semuanya berfungsi dengan properti yang ditentukan dalam kelas Razor Page. Pertimbangkan halaman yang mengimplementasikan formulir "hubungi kami" dasar untuk model Contact
:
Untuk sampel dalam dokumen ini, DbContext
diinisialisasi dalam file Startup.cs.
Database dalam memori memerlukan paket NuGet Microsoft.EntityFrameworkCore.InMemory
.
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<CustomerDbContext>(options =>
options.UseInMemoryDatabase("name"));
services.AddRazorPages();
}
Model data:
using System.ComponentModel.DataAnnotations;
namespace RazorPagesContacts.Models
{
public class Customer
{
public int Id { get; set; }
[Required, StringLength(10)]
public string Name { get; set; }
}
}
Konteks db:
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; }
}
}
File tampilan 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 halaman 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");
}
}
}
Berdasarkan konvensi, kelas PageModel
disebut <PageName>Model
dan berada dalam namespace layanan yang sama dengan halaman.
Kelas PageModel
memungkinkan pemisahan logika halaman dari presentasinya. Ini mendefinisikan penanganan halaman untuk permintaan yang dikirim ke halaman dan data yang digunakan untuk merender halaman. Pemisahan ini memungkinkan:
- Pengelolaan dependensi halaman melalui injeksi dependensi.
- Pengujian unit
Halaman memiliki OnPostAsync
metode handler, yang berjalan berdasarkan POST
permintaan (saat pengguna memposting formulir). Metode penanganan untuk kata kerja HTTP apa pun dapat ditambahkan. Penanganan yang paling umum adalah:
OnGet
untuk menginisialisasi status yang diperlukan halaman. Pada kode sebelumnya, metodeOnGet
menampilkanCreateModel.cshtml
Razor Page.OnPost
untuk menangani pengiriman formulir.
Akhiran penamaan Async
sifatnya opsional tetapi sering digunakan oleh konvensi untuk fungsi asinkron. Kode sebelumnya umum untuk Razor Pages.
Jika Anda terbiasa dengan aplikasi ASP.NET yang menggunakan pengontrol dan tampilan:
- Kode
OnPostAsync
dalam contoh sebelumnya terlihat mirip dengan kode pengontrol biasa. - Sebagian besar primitif MVC seperti pengikatan model, validasi, dan hasil tindakan bekerja dengan cara yang sama seperti Pengontrol dan Razor Pages.
Metode OnPostAsync
sebelumnya:
public async Task<IActionResult> OnPostAsync()
{
if (!ModelState.IsValid)
{
return Page();
}
_context.Customers.Add(Customer);
await _context.SaveChangesAsync();
return RedirectToPage("./Index");
}
Alur dasar OnPostAsync
:
Periksa kesalahan validasi.
- Jika tidak ada kesalahan, simpan data dan alihkan.
- Jika ada kesalahan, tampilkan kembali halaman dengan pesan validasi. Dalam banyak kasus, kesalahan validasi akan terdeteksi pada klien, dan tidak pernah dikirimkan ke server.
File tampilan 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>
HTML yang dirender dari 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>
Dalam kode sebelumnya, posting formulir:
Dengan data yang valid:
Metode penanganan
OnPostAsync
memanggil metode pembantu RedirectToPage.RedirectToPage
mengembalikan instans dari RedirectToPageResult.RedirectToPage
:- Merupakan hasil tindakan.
- Mirip dengan
RedirectToAction
atauRedirectToRoute
(digunakan dalam pengontrol dan tampilan). - Dikustomisasi untuk halaman. Dalam sampel sebelumnya, ini dialihkan ke halaman Indeks akar (
/Index
).RedirectToPage
dijelaskan lebih lanjut di bagian pembuatan URL untuk Pages.
Dengan kesalahan validasi yang diteruskan ke server:
- Metode penanganan
OnPostAsync
memanggil metode pembantu Page.Page
mengembalikan instans dari PageResult. PengembalianPage
mirip dengan bagaimana tindakan di pengontrol mengembalikanView
.PageResult
adalah jenis pengembalian default untuk metode penanganan. Metode penanganan yang mengembalikanvoid
merender halaman. - Pada contoh sebelumnya, memposting formulir tanpa nilai akan menyebabkan ModelState.IsValid mengembalikan false. Dalam sampel ini, tidak ada kesalahan validasi yang ditampilkan pada klien. Penanganan kesalahan validasi dibahas nanti dalam dokumen ini.
public async Task<IActionResult> OnPostAsync() { if (!ModelState.IsValid) { return Page(); } _context.Customers.Add(Customer); await _context.SaveChangesAsync(); return RedirectToPage("./Index"); }
- Metode penanganan
Dengan kesalahan validasi yang terdeteksi oleh validasi sisi klien:
- Data tidak diposting ke server.
- Validasi sisi klien dijelaskan nanti dalam dokumen ini.
Properti Customer
menggunakan atribut [BindProperty]
untuk ikut serta dalam pengikatan model:
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]
tidak boleh digunakan pada model yang berisi properti yang tidak boleh diubah oleh klien. Untuk informasi lebih lanjut, lihat Overposting.
Razor Pages, secara default, hanya mengikat properti dengan kata kerja non-GET
. Pengikatan ke properti menghilangkan kebutuhan untuk menulis kode guna mengonversi data HTTP ke jenis model. Pengikatan mengurangi kode dengan menggunakan properti yang sama untuk merender bidang isian borang (<input asp-for="Customer.Name">
) dan menerima input.
Peringatan
Karena alasan keamanan, Anda harus memilih untuk mengikat GET
data permintaan ke properti model halaman. Verifikasi input pengguna sebelum memetakannya ke properti. Memilih pengikatan GET
berguna saat menangani skenario yang mengandalkan string kueri atau nilai rute.
Untuk mengikat properti pada permintaan GET
, atur properti SupportsGet
atribut [BindProperty]
ke true
:
[BindProperty(SupportsGet = true)]
Untuk informasi lebih lanjut, lihat ASP.NET Core Community Standup: Bind on GET discussion (YouTube).
Meninjau file tampilan 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>
- Dalam kode sebelumnya, pembantu tag
<input asp-for="Customer.Name" />
input mengikat elemen HTML<input>
keCustomer.Name
ekspresi model. @addTagHelper
membuat Pembantu Tag tersedia.
Halaman home
Index.cshtml
home adalah halaman:
@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>
Kelas PageModel
terkait (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();
}
}
File Index.cshtml
berisi markup berikut:
<a asp-page="./Edit" asp-route-id="@contact.Id">Edit</a> |
Pembantu <a /a>
Tag Jangkar menggunakan asp-route-{value}
atribut untuk menghasilkan tautan ke halaman Edit. Tautan berisi data rute dengan ID kontak. Contohnya,https://localhost:5001/Edit/1
. Pembantu Tag mengaktifkan kode sisi server untuk berpartisipasi dalam membuat dan merender elemen HTML dalam file Razor.
File Index.cshtml
berisi markup untuk membuat tombol hapus untuk setiap kontak pelanggan:
<button type="submit" asp-page-handler="delete" asp-route-id="@contact.Id">delete</button>
HTML yang dirender:
<button type="submit" formaction="/Customers?id=1&handler=delete">delete</button>
Saat tombol hapus ditampilkan dalam HTML, formaction-nya menyertakan parameter untuk:
- ID kontak pelanggan, ditentukan oleh atribut
asp-route-id
. handler
, ditentukan oleh atributasp-page-handler
.
Saat tombol dipilih, permintaan POST
formulir dikirim ke server. Berdasarkan konvensi, nama metode penanganan dipilih berdasarkan nilai parameter handler
menurut skema OnPost[handler]Async
.
Karena handler
adalah delete
dalam contoh ini, metode penanganan OnPostDeleteAsync
digunakan untuk memproses permintaan POST
. Jika asp-page-handler
diatur ke nilai yang berbeda, seperti remove
, metode penanganan dengan nama OnPostRemoveAsync
dipilih.
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();
}
Metode OnPostDeleteAsync
:
- Mendapatkan
id
dari string kueri. - Kueri database untuk kontak pelanggan dengan
FindAsync
. - Jika kontak pelanggan ditemukan, ini akan dihapus dan database diperbarui.
- Memanggil RedirectToPage untuk mengalihkan ke halaman Indeks akar (
/Index
).
File 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>
Baris pertama berisi arahan @page "{id:int}"
. Batasan perutean "{id:int}"
memberi tahu halaman untuk menerima permintaan ke halaman yang berisi data rute int
. Jika permintaan ke halaman tidak berisi data rute yang dapat dikonversi ke int
, runtime bahasa umum mengembalikan kesalahan HTTP 404 (tidak ditemukan). Untuk menjadikan ID bersifat opsional, tambahkan ?
ke batasan rute:
@page "{id:int?}"
File 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");
}
}
Validasi
Aturan validasi:
- Secara deklaratif ditentukan dalam kelas model.
- Diberlakukan di mana-mana di aplikasi.
Namespace layanan System.ComponentModel.DataAnnotations menyediakan satu set atribut validasi bawaan yang diterapkan secara deklaratif ke kelas atau properti. DataAnnotations juga berisi atribut pemformatan seperti [DataType]
yang membantu pemformatan dan tidak memberikan validasi apa pun.
Pertimbangkan 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; }
}
}
Dengan file tampilan Create.cshtml
berikut:
@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>
Kode sebelumnya:
Termasuk skrip validasi jQuery dan jQuery.
<div />
Menggunakan dan<span />
Tag Helpers untuk mengaktifkan:- Validasi sisi klien.
- Perenderan kesalahan validasi.
Menghasilkan HTML berikut:
<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>
Memposting formulir Buat tanpa nilai nama akan menampilkan pesan kesalahan "Bidang Nama diperlukan." pada formulir. Jika JavaScript diaktifkan pada klien, browser menampilkan kesalahan tanpa memposting ke server.
Atribut [StringLength(10)]
menghasilkan data-val-length-max="10"
pada HTML yang dirender. data-val-length-max
mencegah browser agar tidak memasukkan lebih dari panjang maksimum yang ditentukan. Jika alat seperti Fiddler digunakan untuk mengedit dan memutar kembali pos:
- Dengan nama yang melebihi 10.
- Pesan kesalahan "Nama bidang harus berupa string dengan panjang maksimum 10." dikembalikan.
Perhatikan model Movie
berikut:
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; }
}
}
Atribut validasi menentukan perilaku yang akan diberlakukan pada properti model tempatnya diterapkan:
Atribut
Required
danMinimumLength
menunjukkan bahwa properti harus memiliki nilai, tetapi tidak ada yang mencegah pengguna memasukkan spasi kosong untuk memenuhi validasi ini.Atribut
RegularExpression
digunakan untuk membatasi karakter apa yang dapat dimasukkan. Dalam kode sebelumnya, "Genre":- Hanya boleh menggunakan huruf.
- Huruf pertama harus huruf besar. Spasi kosong, angka, dan karakter khusus tidak diperbolehkan.
RegularExpression
"Rating":- Mengharuskan karakter pertama berupa huruf besar.
- Mengizinkan karakter dan angka khusus di spasi berikutnya. "PG-13" valid untuk rating, tetapi gagal untuk "Genre".
Atribut
Range
membatasi nilai dalam rentang yang ditentukan.Atribut
StringLength
mengatur panjang maksimum properti string, dan secara opsional, panjang minimumnya.Jenis nilai (seperti
decimal
,int
,float
,DateTime
) secara inheren diperlukan dan tidak memerlukan atribut[Required]
.
Halaman Buat untuk model Movie
menunjukkan kesalahan tampilan dengan nilai yang tidak valid:
Untuk informasi selengkapnya, lihat:
Menangani permintaan HEAD dengan fallback penanganan OnGet
Permintaan HEAD
memungkinkan pengambilan header untuk sumber daya tertentu. Tidak seperti permintaan GET
, permintaan HEAD
tidak mengembalikan isi respons.
Biasanya, penanganan OnHead
dibuat dan dipanggil untuk permintaan HEAD
:
public void OnHead()
{
HttpContext.Response.Headers.Add("Head Test", "Handled by OnHead!");
}
Razor Pages kembali memanggil penanganan OnGet
jika tidak ada penanganan OnHead
yang ditentukan.
XSRF/CSRF dan Razor Pages
Razor Pages dilindungi oleh Validasi anti-pemalsuan. FormTagHelper menyuntikkan token anti-pemalsuan ke dalam elemen formulir HTML.
Menggunakan Tata Letak, parsial, template, dan Pembantu Tag dengan Razor Pages
Pages berfungsi dengan semua kemampuan mesin tampilan Razor. Tata letak, parsial, template, Pembantu Tag, _ViewStart.cshtml
, dan _ViewImports.cshtml
bekerja dengan cara yang sama seperti tampilan Razor konvensional.
Mari kita rapikan halaman ini dengan memanfaatkan beberapa kemampuan tersebut.
Tambahkan halaman tata letak ke 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>
- Mengontrol tata letak setiap halaman (kecuali halaman menolak tata letak).
- Mengimpor struktur HTML seperti JavaScript dan stylesheet.
- Konten halaman Razor dirender di tempat
@RenderBody()
dipanggil.
Untuk informasi lebih lanjut, lihat halaman tata letak.
Properti Tata letak diatur di Pages/_ViewStart.cshtml
:
@{
Layout = "_Layout";
}
Tata letaknya ada di folder Pages/Shared. Halaman mencari tampilan lain (tata letak, template, parsial) secara hierarkis, dimulai dari folder yang sama dengan halaman saat ini. Tata letak dalam folder Pages/Shared dapat digunakan dari halaman Razor mana pun di pada folder Pages.
File tata letak harus masuk ke dalam folder Pages/Shared.
Sebaiknya jangan meletakkan file tata letak di folder Views/Shared. Views/Shared adalah pola tampilan MVC. Razor Pages dimaksudkan untuk mengandalkan hierarki folder, bukan konvensi jalur.
Lihat pencarian dari Razor Page yang menyertakan folder Page. Tata letak, template, dan parsial yang digunakan dengan pengontrol MVC dan tampilan Razor konvensional berfungsi.
Tambahkan file Pages/_ViewImports.cshtml
:
@namespace RazorPagesContacts.Pages
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
@namespace
dijelaskan nanti dalam tutorial. Arahan @addTagHelper
membawa Pembantu Tag bawaan ke semua halaman dalam folder Pages.
Arahan @namespace
diatur pada halaman:
@page
@namespace RazorPagesIntro.Pages.Customers
@model NameSpaceModel
<h2>Name space</h2>
<p>
@Model.Message
</p>
Arahan @namespace
mengatur namespace layanan untuk halaman. Arahan @model
tidak perlu menyertakan namespace layanan.
Jika arahan @namespace
ada dalam _ViewImports.cshtml
, namespace layanan yang ditentukan akan menyediakan awalan untuk namespace layanan yang dihasilkan di Page yang mengimpor arahan @namespace
. Namespace rest yang dihasilkan (bagian akhiran) adalah jalur relatif yang dipisahkan titik antara folder yang berisi _ViewImports.cshtml
dan folder yang berisi halaman.
Misalnya, kelas PageModel
Pages/Customers/Edit.cshtml.cs
secara eksplisit mengatur namespace layanan:
namespace RazorPagesContacts.Pages
{
public class EditModel : PageModel
{
private readonly AppDbContext _db;
public EditModel(AppDbContext db)
{
_db = db;
}
// Code removed for brevity.
File Pages/_ViewImports.cshtml
mengatur namespace layanan berikut:
@namespace RazorPagesContacts.Pages
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
Namespace layanan yang dihasilkan untuk Pages/Customers/Edit.cshtml
RazorPage sama dengan kelas PageModel
.
@namespace
juga berfungsi dengan tampilan konvensionalRazor.
Pertimbangkan file tampilan 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>
File tampilan Pages/Create.cshtml
yang diperbarui dengan _ViewImports.cshtml
dan file tata letak sebelumnya:
@page
@model CreateModel
<p>Enter a customer name:</p>
<form method="post">
Name:
<input asp-for="Customer.Name" />
<input type="submit" />
</form>
Dalam kode sebelumnya, _ViewImports.cshtml
mengimpor namespace layanan dan Pembantu Tag. File tata letak mengimpor file JavaScript.
Proyek starter Razor Pages berisi Pages/_ValidationScriptsPartial.cshtml
, yang menghubungkan validasi sisi klien.
Untuk informasi lebih lanjut tentang tampilan parsial, lihat Tampilan parsial di ASP.NET Core.
Pembuatan URL untuk Pages
Halaman Create
, yang ditampilkan sebelumnya, menggunakan 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");
}
}
Aplikasi ini memiliki struktur file/folder berikut:
/Pages
Index.cshtml
Privacy.cshtml
/Customers
Create.cshtml
Edit.cshtml
Index.cshtml
Halaman Pages/Customers/Create.cshtml
dan Pages/Customers/Edit.cshtml
dialihkan ke Pages/Customers/Index.cshtml
setelah berhasil. ./Index
string adalah nama halaman relatif yang digunakan untuk mengakses halaman sebelumnya. Ini digunakan untuk membuat URL ke halaman Pages/Customers/Index.cshtml
. Contohnya:
Url.Page("./Index", ...)
<a asp-page="./Index">Customers Index Page</a>
RedirectToPage("./Index")
/Index
nama halaman absolut digunakan untuk membuat URL ke halaman Pages/Index.cshtml
. Contohnya:
Url.Page("/Index", ...)
<a asp-page="/Index">Home Index Page</a>
RedirectToPage("/Index")
Nama halaman adalah jalur ke halaman dari folder /Pages akar termasuk awalan /
(misalnya, /Index
). Sampel pembuatan URL sebelumnya menawarkan opsi yang disempurnakan dan kemampuan fungsional jika dibandingkan dengan hard-coding URL. Pembuatan URL menggunakan perutean dan dapat membuat serta mengodekan parameter sesuai dengan cara rute ditentukan di jalur tujuan.
Pembuatan URL untuk halaman mendukung nama relatif. Tabel berikut menunjukkan halaman Indeks mana yang dipilih menggunakan parameter RedirectToPage
yang berbeda di Pages/Customers/Create.cshtml
.
RedirectToPage(x) | Halaman |
---|---|
RedirectToPage("/Index") | Pages/Index |
RedirectToPage("./Index"); | Pages/Customers/Index |
RedirectToPage("../Index") | Pages/Index |
RedirectToPage("Index") | Pages/Customers/Index |
RedirectToPage("Index")
, RedirectToPage("./Index")
, dan RedirectToPage("../Index")
adalah nama relatif. Parameter RedirectToPage
digabungkan dengan jalur halaman saat ini untuk menghitung nama halaman tujuan.
Tautan nama relatif berguna saat membangun situs dengan struktur yang kompleks. Saat nama relatif digunakan untuk menautkan antar-halaman dalam folder:
- Mengganti nama folder tidak merusak tautan relatif.
- Tautan tidak rusak karena tautan tidak menyertakan nama folder.
Untuk mengalihkan ke halaman di Area yang berbeda, tentukan area:
RedirectToPage("/Index", new { area = "Services" });
Untuk informasi lebih lanjut, lihat Area di ASP.NET Core serta Rute dan konvensi aplikasi Razor Pages di ASP.NET Core.
Atribut ViewData
Data dapat diteruskan ke halaman dengan ViewDataAttribute. Properti dengan atribut [ViewData]
memiliki nilai yang disimpan dan dimuat dari ViewDataDictionary.
Dalam contoh berikut, AboutModel
menerapkan atribut [ViewData]
ke properti Title
:
public class AboutModel : PageModel
{
[ViewData]
public string Title { get; } = "About";
public void OnGet()
{
}
}
Di halaman Tentang, akses properti Title
sebagai properti model:
<h1>@Model.Title</h1>
Dalam tata letak, judul dibaca dari kamus ViewData:
<!DOCTYPE html>
<html lang="en">
<head>
<title>@ViewData["Title"] - WebApplication</title>
...
TempData
ASP.NET Core mengekspos TempData. Properti ini menyimpan data sampai data dibaca. Metode Keep dan Peek dapat digunakan untuk memeriksa data tanpa menghapusnya. TempData
berguna untuk pengalihan, ketika data diperlukan untuk lebih dari satu permintaan.
Kode berikut menetapkan nilai Message
menggunakan 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");
}
}
Markup berikut dalam file Pages/Customers/Index.cshtml
menampilkan nilai Message
menggunakan TempData
.
<h3>Msg: @Model.Message</h3>
Model halaman Pages/Customers/Index.cshtml.cs
menerapkan atribut [TempData]
ke properti Message
.
[TempData]
public string Message { get; set; }
Untuk informasi lebih lanjut, lihat TempData.
Beberapa penanganan per halaman
Halaman berikut menghasilkan markup untuk dua penanganan menggunakan Pembantu Tag 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>
Formulir dalam contoh sebelumnya memiliki dua tombol kirim, masing-masing menggunakan FormActionTagHelper
untuk mengirim ke URL yang berbeda. Atribut asp-page-handler
adalah pendamping asp-page
. asp-page-handler
menghasilkan URL yang dikirimkan ke setiap metode penanganan yang ditentukan oleh halaman. asp-page
tidak ditentukan karena sampel menautkan ke halaman saat ini.
Model halaman :
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();
}
}
}
Kode sebelumnya menggunakan metode penanganan bernama. Metode pengendali bernama dibuat dengan mengambil teks dalam nama setelah On<HTTP Verb>
dan sebelum Async
(jika ada). Dalam contoh sebelumnya, metode halaman adalah OnPostJoinListAsync dan OnPostJoinListUCAsync. Dengan OnPost dan Async dihapus, nama penangannya adalah JoinList
dan JoinListUC
.
<input type="submit" asp-page-handler="JoinList" value="Join" />
<input type="submit" asp-page-handler="JoinListUC" value="JOIN UC" />
Dengan menggunakan kode sebelumnya, jalur URL yang mengirimkan ke OnPostJoinListAsync
adalah https://localhost:5001/Customers/CreateFATH?handler=JoinList
. Jalur URL yang mengirimkan ke OnPostJoinListUCAsync
adalah https://localhost:5001/Customers/CreateFATH?handler=JoinListUC
.
Rute kustom
Gunakan arahan @page
untuk:
- Menentukan rute kustom ke halaman. Misalnya, rute ke halaman Tentang dapat diatur ke
/Some/Other/Path
dengan@page "/Some/Other/Path"
. - Menambahkan segmen ke rute default halaman. Misalnya, segmen "item" dapat ditambahkan ke rute default halaman dengan
@page "item"
. - Menambahkan parameter ke rute default halaman. Misalnya, parameter ID,
id
, dapat diperlukan untuk halaman dengan@page "{id}"
.
Jalur relatif akar yang ditunjuk oleh tilde (~
) di awal jalur didukung. Misalnya, @page "~/Some/Other/Path"
sama dengan @page "/Some/Other/Path"
.
Jika Anda tidak menyukai ?handler=JoinList
string kueri di URL, ubah rute untuk meletakkan nama penanganan di bagian jalur URL. Rute dapat dikustomisasi dengan menambahkan template rute yang diapit tanda kutip ganda setelah arahan @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>
Dengan menggunakan kode sebelumnya, jalur URL yang mengirimkan ke OnPostJoinListAsync
adalah https://localhost:5001/Customers/CreateFATH/JoinList
. Jalur URL yang mengirimkan ke OnPostJoinListUCAsync
adalah https://localhost:5001/Customers/CreateFATH/JoinListUC
.
?
setelah handler
berarti parameter rute adalah opsional.
Konfigurasi dan pengaturan tingkat lanjut
Konfigurasi dan pengaturan di bagian berikut tidak diperlukan oleh sebagian besar aplikasi.
Untuk mengonfigurasi opsi tingkat lanjut, gunakan overload AddRazorPages yang mengonfigurasi RazorPagesOptions:
public void ConfigureServices(IServiceCollection services)
{
services.AddRazorPages(options =>
{
options.RootDirectory = "/MyPages";
options.Conventions.AuthorizeFolder("/MyPages/Admin");
});
}
Gunakan RazorPagesOptions untuk mengatur direktori akar untuk halaman, atau menambahkan konvensi model aplikasi untuk halaman. Untuk informasi lebih lanjut tentang konvensi, lihat Konvensi otorisasi Razor Pages.
Untuk mengompilasi tampilan sebelumnya, lihat kompilasi tampilan Razor.
Menentukan bahwa Razor Pages berada di akar konten
Secara default, Razor Pages berakar di direktori /Pages. Tambahkan WithRazorPagesAtContentRoot untuk menentukan bahwa Razor Pages Anda berada di akar konten (ContentRootPath) aplikasi:
public void ConfigureServices(IServiceCollection services)
{
services.AddRazorPages(options =>
{
options.Conventions.AuthorizeFolder("/MyPages/Admin");
})
.WithRazorPagesAtContentRoot();
}
Menentukan bahwa Razor Pages berada di direktori akar kustom
Tambahkan WithRazorPagesRoot untuk menentukan bahwa Razor Pages berada di direktori akar kustom di aplikasi (berikan jalur relatif):
public void ConfigureServices(IServiceCollection services)
{
services.AddRazorPages(options =>
{
options.Conventions.AuthorizeFolder("/MyPages/Admin");
})
.WithRazorPagesRoot("/path/to/razor/pages");
}
Sumber Daya Tambahan:
- Lihat Mulai menggunakan Razor Pages, yang dibuat berdasarkan pengantar ini.
- Mengotorisasi atribut dan Razor Pages
- Mengunduh atau melihat sampel kode
- Gambaran umum ASP.NET Core
- Referensi sintaks Razor untuk ASP.NET Core
- Area di ASP.NET Core
- Tutorial: Mulai menggunakan Razor Pages di ASP.NET Core
- Konvensi otorisasi Razor Pages di ASP.NET Core
- Konvensi rute dan aplikasi Razor Pages di ASP.NET Core
- Pengujian unit Razor Pages di ASP.NET Core
- Tampilan parsial di ASP.NET Core
ASP.NET Core