Bagian 5, perbarui halaman yang dihasilkan di aplikasi ASP.NET Core
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.
Aplikasi film perancah memiliki awal yang baik, tetapi presentasinya tidak ideal. ReleaseDate harus dua kata, Tanggal Rilis.
Memperbarui model
Perbarui Models/Movie.cs
dengan kode yang disorot berikut:
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace RazorPagesMovie.Models;
public class Movie
{
public int Id { get; set; }
public string Title { get; set; } = string.Empty;
[Display(Name = "Release Date")]
[DataType(DataType.Date)]
public DateTime ReleaseDate { get; set; }
public string Genre { get; set; } = string.Empty;
[Column(TypeName = "decimal(18, 2)")]
public decimal Price { get; set; }
}
Dalam kode sebelumnya:
- Anotasi
[Column(TypeName = "decimal(18, 2)")]
data memungkinkan Entity Framework Core memetakanPrice
mata uang dengan benar dalam database. Untuk informasi selengkapnya, lihat Jenis Data. - Atribut [Display] menentukan nama tampilan bidang. Dalam kode sebelumnya,
Release Date
alih-alihReleaseDate
. - Atribut [DataType] menentukan jenis data (
Date
). Informasi waktu yang disimpan di bidang tidak ditampilkan.
DataAnnotations dibahas dalam tutorial berikutnya.
Telusuri ke Halaman/Film dan arahkan mouse ke atas tautan Edit untuk melihat URL target.
Tautan Edit, Detail, dan Hapus dihasilkan oleh Pembantu Tag Jangkar dalam Pages/Movies/Index.cshtml
file.
@foreach (var item in Model.Movie) {
<tr>
<td>
@Html.DisplayFor(modelItem => item.Title)
</td>
<td>
@Html.DisplayFor(modelItem => item.ReleaseDate)
</td>
<td>
@Html.DisplayFor(modelItem => item.Genre)
</td>
<td>
@Html.DisplayFor(modelItem => item.Price)
</td>
<td>
<a asp-page="./Edit" asp-route-id="@item.Id">Edit</a> |
<a asp-page="./Details" asp-route-id="@item.Id">Details</a> |
<a asp-page="./Delete" asp-route-id="@item.Id">Delete</a>
</td>
</tr>
}
</tbody>
</table>
Pembantu Tag mengaktifkan kode sisi server untuk berpartisipasi dalam membuat dan merender elemen HTML dalam file Razor.
Dalam kode sebelumnya, Pembantu Tag Jangkar secara dinamis menghasilkan nilai atribut HTML href
dari Razor Halaman (rute relatif), asp-page
, dan pengidentifikasi rute (asp-route-id
). Untuk informasi selengkapnya, lihat Pembuatan URL untuk Halaman.
Gunakan Tampilkan Sumber dari browser untuk memeriksa markup yang dihasilkan. Sebagian HTML yang dihasilkan ditunjukkan di bawah ini:
<td>
<a href="/Movies/Edit?id=1">Edit</a> |
<a href="/Movies/Details?id=1">Details</a> |
<a href="/Movies/Delete?id=1">Delete</a>
</td>
Tautan yang dihasilkan secara dinamis meneruskan ID film dengan string kueri. Misalnya, dalam ?id=1
https://localhost:5001/Movies/Details?id=1
.
Menambahkan templat rute
Perbarui Edit, Detail, dan Hapus Razor Halaman untuk menggunakan {id:int}
templat rute. Ubah arahan halaman untuk setiap halaman ini dari @page
ke @page "{id:int}"
. Jalankan aplikasi lalu lihat sumber.
HTML yang dihasilkan menambahkan ID ke bagian jalur URL:
<td>
<a href="/Movies/Edit/1">Edit</a> |
<a href="/Movies/Details/1">Details</a> |
<a href="/Movies/Delete/1">Delete</a>
</td>
Permintaan ke halaman dengan {id:int}
templat rute yang tidak menyertakan bilangan bulat mengembalikan kesalahan HTTP 404 (tidak ditemukan). Misalnya, https://localhost:5001/Movies/Details
mengembalikan kesalahan 404. Untuk menjadikan ID bersifat opsional, tambahkan ?
ke batasan rute:
@page "{id:int?}"
Uji perilaku @page "{id:int?}"
:
- Atur direktif
Pages/Movies/Details.cshtml
halaman ke@page "{id:int?}"
. - Atur titik henti di
public async Task<IActionResult> OnGetAsync(int? id)
, diPages/Movies/Details.cshtml.cs
. - Buka
https://localhost:5001/Movies/Details/
.
Dengan direktif @page "{id:int}"
, titik henti tidak pernah tertembak. Mesin perutean mengembalikan HTTP 404. Menggunakan @page "{id:int?}"
, OnGetAsync
metode mengembalikan NotFound
(HTTP 404):
public async Task<IActionResult> OnGetAsync(int? id)
{
if (id == null)
{
return NotFound();
}
var movie = await _context.Movie.FirstOrDefaultAsync(m => m.Id == id);
if (movie == null)
{
return NotFound();
}
else
{
Movie = movie;
}
return Page();
}
Meninjau penanganan pengecualian konkurensi
OnPostAsync
Tinjau metode dalam Pages/Movies/Edit.cshtml.cs
file:
public async Task<IActionResult> OnPostAsync()
{
if (!ModelState.IsValid)
{
return Page();
}
_context.Attach(Movie).State = EntityState.Modified;
try
{
await _context.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException)
{
if (!MovieExists(Movie.Id))
{
return NotFound();
}
else
{
throw;
}
}
return RedirectToPage("./Index");
}
private bool MovieExists(int id)
{
return _context.Movie.Any(e => e.Id == id);
}
Kode sebelumnya mendeteksi pengecualian konkurensi ketika satu klien menghapus film dan klien lain memposting perubahan pada film.
Untuk menguji catch
blok:
- Atur titik henti pada
catch (DbUpdateConcurrencyException)
. - Pilih Edit untuk film, buat perubahan, tetapi jangan masukkan Simpan.
- Di jendela browser lain, pilih tautan Hapus untuk film yang sama, lalu hapus film.
- Di jendela browser sebelumnya, posting perubahan pada film.
Kode produksi mungkin ingin mendeteksi konflik konkurensi. Lihat Menangani konflik konkurensi untuk informasi selengkapnya.
Memposting dan mengikat ulasan
Periksa Pages/Movies/Edit.cshtml.cs
file:
public class EditModel : PageModel
{
private readonly RazorPagesMovie.Data.RazorPagesMovieContext _context;
public EditModel(RazorPagesMovie.Data.RazorPagesMovieContext context)
{
_context = context;
}
[BindProperty]
public Movie Movie { get; set; } = default!;
public async Task<IActionResult> OnGetAsync(int? id)
{
if (id == null)
{
return NotFound();
}
var movie = await _context.Movie.FirstOrDefaultAsync(m => m.Id == id);
if (movie == null)
{
return NotFound();
}
Movie = movie;
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();
}
_context.Attach(Movie).State = EntityState.Modified;
try
{
await _context.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException)
{
if (!MovieExists(Movie.Id))
{
return NotFound();
}
else
{
throw;
}
}
return RedirectToPage("./Index");
}
private bool MovieExists(int id)
{
return _context.Movie.Any(e => e.Id == id);
}
Ketika permintaan HTTP GET dibuat ke halaman Film/Edit, misalnya, https://localhost:5001/Movies/Edit/3
:
- Metode
OnGetAsync
mengambil film dari database dan mengembalikanPage
metode . - Metode merender
Page
Pages/Movies/Edit.cshtml
Razor Halaman. FilePages/Movies/Edit.cshtml
berisi direktif@model RazorPagesMovie.Pages.Movies.EditModel
model , yang membuat model film tersedia di halaman. - Formulir Edit ditampilkan dengan nilai dari film.
Saat halaman Film/Edit diposting:
Nilai formulir pada halaman terikat ke
Movie
properti . Atribut[BindProperty]
mengaktifkan pengikatan Model.[BindProperty] public Movie Movie { get; set; }
Jika ada kesalahan dalam status model, misalnya,
ReleaseDate
tidak dapat dikonversi ke tanggal, formulir diputar ulang dengan nilai yang dikirimkan.Jika tidak ada kesalahan model, film disimpan.
Metode HTTP GET di halaman Indeks, Buat, dan Hapus Razor mengikuti pola serupa. Metode HTTP POST OnPostAsync
di Halaman Buat Razor mengikuti pola OnPostAsync
yang mirip dengan metode di Edit Razor Halaman.
Langkah berikutnya
Aplikasi film perancah memiliki awal yang baik, tetapi presentasinya tidak ideal. ReleaseDate harus dua kata, Tanggal Rilis.
Memperbarui model
Perbarui Models/Movie.cs
dengan kode yang disorot berikut:
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace RazorPagesMovie.Models;
public class Movie
{
public int Id { get; set; }
public string Title { get; set; } = string.Empty;
[Display(Name = "Release Date")]
[DataType(DataType.Date)]
public DateTime ReleaseDate { get; set; }
public string Genre { get; set; } = string.Empty;
[Column(TypeName = "decimal(18, 2)")]
public decimal Price { get; set; }
}
Dalam kode sebelumnya:
- Anotasi
[Column(TypeName = "decimal(18, 2)")]
data memungkinkan Entity Framework Core memetakanPrice
mata uang dengan benar dalam database. Untuk informasi selengkapnya, lihat Jenis Data. - Atribut [Display] menentukan nama tampilan bidang. Dalam kode sebelumnya,
Release Date
alih-alihReleaseDate
. - Atribut [DataType] menentukan jenis data (
Date
). Informasi waktu yang disimpan di bidang tidak ditampilkan.
DataAnnotations dibahas dalam tutorial berikutnya.
Telusuri ke Halaman/Film dan arahkan mouse ke atas tautan Edit untuk melihat URL target.
Tautan Edit, Detail, dan Hapus dihasilkan oleh Pembantu Tag Jangkar dalam Pages/Movies/Index.cshtml
file.
@foreach (var item in Model.Movie) {
<tr>
<td>
@Html.DisplayFor(modelItem => item.Title)
</td>
<td>
@Html.DisplayFor(modelItem => item.ReleaseDate)
</td>
<td>
@Html.DisplayFor(modelItem => item.Genre)
</td>
<td>
@Html.DisplayFor(modelItem => item.Price)
</td>
<td>
<a asp-page="./Edit" asp-route-id="@item.Id">Edit</a> |
<a asp-page="./Details" asp-route-id="@item.Id">Details</a> |
<a asp-page="./Delete" asp-route-id="@item.Id">Delete</a>
</td>
</tr>
}
</tbody>
</table>
Pembantu Tag mengaktifkan kode sisi server untuk berpartisipasi dalam membuat dan merender elemen HTML dalam file Razor.
Dalam kode sebelumnya, Pembantu Tag Jangkar secara dinamis menghasilkan nilai atribut HTML href
dari Razor Halaman (rute relatif), asp-page
, dan pengidentifikasi rute (asp-route-id
). Untuk informasi selengkapnya, lihat Pembuatan URL untuk Halaman.
Gunakan Tampilkan Sumber dari browser untuk memeriksa markup yang dihasilkan. Sebagian HTML yang dihasilkan ditunjukkan di bawah ini:
<td>
<a href="/Movies/Edit?id=1">Edit</a> |
<a href="/Movies/Details?id=1">Details</a> |
<a href="/Movies/Delete?id=1">Delete</a>
</td>
Tautan yang dihasilkan secara dinamis meneruskan ID film dengan string kueri. Misalnya, dalam ?id=1
https://localhost:5001/Movies/Details?id=1
.
Menambahkan templat rute
Perbarui Edit, Detail, dan Hapus Razor Halaman untuk menggunakan {id:int}
templat rute. Ubah arahan halaman untuk setiap halaman ini dari @page
ke @page "{id:int}"
. Jalankan aplikasi lalu lihat sumber.
HTML yang dihasilkan menambahkan ID ke bagian jalur URL:
<td>
<a href="/Movies/Edit/1">Edit</a> |
<a href="/Movies/Details/1">Details</a> |
<a href="/Movies/Delete/1">Delete</a>
</td>
Permintaan ke halaman dengan {id:int}
templat rute yang tidak menyertakan bilangan bulat mengembalikan kesalahan HTTP 404 (tidak ditemukan). Misalnya, https://localhost:5001/Movies/Details
mengembalikan kesalahan 404. Untuk menjadikan ID bersifat opsional, tambahkan ?
ke batasan rute:
@page "{id:int?}"
Uji perilaku @page "{id:int?}"
:
- Atur direktif
Pages/Movies/Details.cshtml
halaman ke@page "{id:int?}"
. - Atur titik henti di
public async Task<IActionResult> OnGetAsync(int? id)
, diPages/Movies/Details.cshtml.cs
. - Buka
https://localhost:5001/Movies/Details/
.
Dengan direktif @page "{id:int}"
, titik henti tidak pernah tertembak. Mesin perutean mengembalikan HTTP 404. Menggunakan @page "{id:int?}"
, OnGetAsync
metode mengembalikan NotFound
(HTTP 404):
public async Task<IActionResult> OnGetAsync(int? id)
{
if (id == null)
{
return NotFound();
}
Movie = await _context.Movie.FirstOrDefaultAsync(m => m.ID == id);
if (Movie == null)
{
return NotFound();
}
return Page();
}
Meninjau penanganan pengecualian konkurensi
OnPostAsync
Tinjau metode dalam Pages/Movies/Edit.cshtml.cs
file:
public async Task<IActionResult> OnPostAsync()
{
if (!ModelState.IsValid)
{
return Page();
}
_context.Attach(Movie).State = EntityState.Modified;
try
{
await _context.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException)
{
if (!MovieExists(Movie.Id))
{
return NotFound();
}
else
{
throw;
}
}
return RedirectToPage("./Index");
}
private bool MovieExists(int id)
{
return _context.Movie.Any(e => e.Id == id);
}
Kode sebelumnya mendeteksi pengecualian konkurensi ketika satu klien menghapus film dan klien lain memposting perubahan pada film.
Untuk menguji catch
blok:
- Atur titik henti pada
catch (DbUpdateConcurrencyException)
. - Pilih Edit untuk film, buat perubahan, tetapi jangan masukkan Simpan.
- Di jendela browser lain, pilih tautan Hapus untuk film yang sama, lalu hapus film.
- Di jendela browser sebelumnya, posting perubahan pada film.
Kode produksi mungkin ingin mendeteksi konflik konkurensi. Lihat Menangani konflik konkurensi untuk informasi selengkapnya.
Memposting dan mengikat ulasan
Periksa Pages/Movies/Edit.cshtml.cs
file:
public class EditModel : PageModel
{
private readonly RazorPagesMovie.Data.RazorPagesMovieContext _context;
public EditModel(RazorPagesMovie.Data.RazorPagesMovieContext context)
{
_context = context;
}
[BindProperty]
public Movie Movie { get; set; } = default!;
public async Task<IActionResult> OnGetAsync(int? id)
{
if (id == null || _context.Movie == null)
{
return NotFound();
}
var movie = await _context.Movie.FirstOrDefaultAsync(m => m.Id == id);
if (movie == null)
{
return NotFound();
}
Movie = movie;
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();
}
_context.Attach(Movie).State = EntityState.Modified;
try
{
await _context.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException)
{
if (!MovieExists(Movie.Id))
{
return NotFound();
}
else
{
throw;
}
}
return RedirectToPage("./Index");
}
private bool MovieExists(int id)
{
return _context.Movie.Any(e => e.Id == id);
}
Ketika permintaan HTTP GET dibuat ke halaman Film/Edit, misalnya, https://localhost:5001/Movies/Edit/3
:
- Metode
OnGetAsync
mengambil film dari database dan mengembalikanPage
metode . - Metode merender
Page
Pages/Movies/Edit.cshtml
Razor Halaman. FilePages/Movies/Edit.cshtml
berisi direktif@model RazorPagesMovie.Pages.Movies.EditModel
model , yang membuat model film tersedia di halaman. - Formulir Edit ditampilkan dengan nilai dari film.
Saat halaman Film/Edit diposting:
Nilai formulir pada halaman terikat ke
Movie
properti . Atribut[BindProperty]
mengaktifkan pengikatan Model.[BindProperty] public Movie Movie { get; set; }
Jika ada kesalahan dalam status model, misalnya,
ReleaseDate
tidak dapat dikonversi ke tanggal, formulir diputar ulang dengan nilai yang dikirimkan.Jika tidak ada kesalahan model, film disimpan.
Metode HTTP GET di halaman Indeks, Buat, dan Hapus Razor mengikuti pola serupa. Metode HTTP POST OnPostAsync
di Halaman Buat Razor mengikuti pola OnPostAsync
yang mirip dengan metode di Edit Razor Halaman.
Langkah berikutnya
Aplikasi film perancah memiliki awal yang baik, tetapi presentasinya tidak ideal. ReleaseDate harus dua kata, Tanggal Rilis.
Memperbarui model
Perbarui Models/Movie.cs
dengan kode yang disorot berikut:
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace RazorPagesMovie.Models;
public class Movie
{
public int Id { get; set; }
public string Title { get; set; } = string.Empty;
[Display(Name = "Release Date")]
[DataType(DataType.Date)]
public DateTime ReleaseDate { get; set; }
public string Genre { get; set; } = string.Empty;
[Column(TypeName = "decimal(18, 2)")]
public decimal Price { get; set; }
}
Dalam kode sebelumnya:
- Anotasi
[Column(TypeName = "decimal(18, 2)")]
data memungkinkan Entity Framework Core memetakanPrice
mata uang dengan benar dalam database. Untuk informasi selengkapnya, lihat Jenis Data. - Atribut [Display] menentukan nama tampilan bidang. Dalam kode sebelumnya,
Release Date
alih-alihReleaseDate
. - Atribut [DataType] menentukan jenis data (
Date
). Informasi waktu yang disimpan di bidang tidak ditampilkan.
DataAnnotations dibahas dalam tutorial berikutnya.
Telusuri ke Halaman/Film dan arahkan mouse ke atas tautan Edit untuk melihat URL target.
Tautan Edit, Detail, dan Hapus dihasilkan oleh Pembantu Tag Jangkar dalam Pages/Movies/Index.cshtml
file.
@foreach (var item in Model.Movie) {
<tr>
<td>
@Html.DisplayFor(modelItem => item.Title)
</td>
<td>
@Html.DisplayFor(modelItem => item.ReleaseDate)
</td>
<td>
@Html.DisplayFor(modelItem => item.Genre)
</td>
<td>
@Html.DisplayFor(modelItem => item.Price)
</td>
<td>
<a asp-page="./Edit" asp-route-id="@item.Id">Edit</a> |
<a asp-page="./Details" asp-route-id="@item.Id">Details</a> |
<a asp-page="./Delete" asp-route-id="@item.Id">Delete</a>
</td>
</tr>
}
</tbody>
</table>
Pembantu Tag mengaktifkan kode sisi server untuk berpartisipasi dalam membuat dan merender elemen HTML dalam file Razor.
Dalam kode sebelumnya, Pembantu Tag Jangkar secara dinamis menghasilkan nilai atribut HTML href
dari Razor Halaman (rute relatif), asp-page
, dan pengidentifikasi rute (asp-route-id
). Untuk informasi selengkapnya, lihat Pembuatan URL untuk Halaman.
Gunakan Tampilkan Sumber dari browser untuk memeriksa markup yang dihasilkan. Sebagian HTML yang dihasilkan ditunjukkan di bawah ini:
<td>
<a href="/Movies/Edit?id=1">Edit</a> |
<a href="/Movies/Details?id=1">Details</a> |
<a href="/Movies/Delete?id=1">Delete</a>
</td>
Tautan yang dihasilkan secara dinamis meneruskan ID film dengan string kueri. Misalnya, dalam ?id=1
https://localhost:5001/Movies/Details?id=1
.
Menambahkan templat rute
Perbarui Edit, Detail, dan Hapus Razor Halaman untuk menggunakan {id:int}
templat rute. Ubah arahan halaman untuk setiap halaman ini dari @page
ke @page "{id:int}"
. Jalankan aplikasi lalu lihat sumber.
HTML yang dihasilkan menambahkan ID ke bagian jalur URL:
<td>
<a href="/Movies/Edit/1">Edit</a> |
<a href="/Movies/Details/1">Details</a> |
<a href="/Movies/Delete/1">Delete</a>
</td>
Permintaan ke halaman dengan {id:int}
templat rute yang tidak menyertakan bilangan bulat mengembalikan kesalahan HTTP 404 (tidak ditemukan). Misalnya, https://localhost:5001/Movies/Details
mengembalikan kesalahan 404. Untuk menjadikan ID bersifat opsional, tambahkan ?
ke batasan rute:
@page "{id:int?}"
Uji perilaku @page "{id:int?}"
:
- Atur direktif
Pages/Movies/Details.cshtml
halaman ke@page "{id:int?}"
. - Atur titik henti di
public async Task<IActionResult> OnGetAsync(int? id)
, diPages/Movies/Details.cshtml.cs
. - Buka
https://localhost:5001/Movies/Details/
.
Dengan direktif @page "{id:int}"
, titik henti tidak pernah tertembak. Mesin perutean mengembalikan HTTP 404. Menggunakan @page "{id:int?}"
, OnGetAsync
metode mengembalikan NotFound
(HTTP 404):
public async Task<IActionResult> OnGetAsync(int? id)
{
if (id == null)
{
return NotFound();
}
Movie = await _context.Movie.FirstOrDefaultAsync(m => m.ID == id);
if (Movie == null)
{
return NotFound();
}
return Page();
}
Meninjau penanganan pengecualian konkurensi
OnPostAsync
Tinjau metode dalam Pages/Movies/Edit.cshtml.cs
file:
public async Task<IActionResult> OnPostAsync()
{
if (!ModelState.IsValid)
{
return Page();
}
_context.Attach(Movie).State = EntityState.Modified;
try
{
await _context.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException)
{
if (!MovieExists(Movie.Id))
{
return NotFound();
}
else
{
throw;
}
}
return RedirectToPage("./Index");
}
private bool MovieExists(int id)
{
return _context.Movie.Any(e => e.Id == id);
}
Kode sebelumnya mendeteksi pengecualian konkurensi ketika satu klien menghapus film dan klien lain memposting perubahan pada film.
Untuk menguji catch
blok:
- Atur titik henti pada
catch (DbUpdateConcurrencyException)
. - Pilih Edit untuk film, buat perubahan, tetapi jangan masukkan Simpan.
- Di jendela browser lain, pilih tautan Hapus untuk film yang sama, lalu hapus film.
- Di jendela browser sebelumnya, posting perubahan pada film.
Kode produksi mungkin ingin mendeteksi konflik konkurensi. Lihat Menangani konflik konkurensi untuk informasi selengkapnya.
Memposting dan mengikat ulasan
Periksa Pages/Movies/Edit.cshtml.cs
file:
public class EditModel : PageModel
{
private readonly RazorPagesMovie.Data.RazorPagesMovieContext _context;
public EditModel(RazorPagesMovie.Data.RazorPagesMovieContext context)
{
_context = context;
}
[BindProperty]
public Movie Movie { get; set; } = default!;
public async Task<IActionResult> OnGetAsync(int? id)
{
if (id == null || _context.Movie == null)
{
return NotFound();
}
var movie = await _context.Movie.FirstOrDefaultAsync(m => m.Id == id);
if (movie == null)
{
return NotFound();
}
Movie = movie;
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();
}
_context.Attach(Movie).State = EntityState.Modified;
try
{
await _context.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException)
{
if (!MovieExists(Movie.Id))
{
return NotFound();
}
else
{
throw;
}
}
return RedirectToPage("./Index");
}
private bool MovieExists(int id)
{
return _context.Movie.Any(e => e.Id == id);
}
Ketika permintaan HTTP GET dibuat ke halaman Film/Edit, misalnya, https://localhost:5001/Movies/Edit/3
:
- Metode
OnGetAsync
mengambil film dari database dan mengembalikanPage
metode . - Metode merender
Page
Pages/Movies/Edit.cshtml
Razor Halaman. FilePages/Movies/Edit.cshtml
berisi direktif@model RazorPagesMovie.Pages.Movies.EditModel
model , yang membuat model film tersedia di halaman. - Formulir Edit ditampilkan dengan nilai dari film.
Saat halaman Film/Edit diposting:
Nilai formulir pada halaman terikat ke
Movie
properti . Atribut[BindProperty]
mengaktifkan pengikatan Model.[BindProperty] public Movie Movie { get; set; }
Jika ada kesalahan dalam status model, misalnya,
ReleaseDate
tidak dapat dikonversi ke tanggal, formulir diputar ulang dengan nilai yang dikirimkan.Jika tidak ada kesalahan model, film disimpan.
Metode HTTP GET di halaman Indeks, Buat, dan Hapus Razor mengikuti pola serupa. Metode HTTP POST OnPostAsync
di Halaman Buat Razor mengikuti pola OnPostAsync
yang mirip dengan metode di Edit Razor Halaman.
Langkah berikutnya
Aplikasi film perancah memiliki awal yang baik, tetapi presentasinya tidak ideal. ReleaseDate harus dua kata, Tanggal Rilis.
Memperbarui kode yang dihasilkan
Perbarui Models/Movie.cs
dengan kode yang disorot berikut:
using System;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace RazorPagesMovie.Models
{
public class Movie
{
public int ID { get; set; }
public string Title { get; set; } = string.Empty;
[Display(Name = "Release Date")]
[DataType(DataType.Date)]
public DateTime ReleaseDate { get; set; }
public string Genre { get; set; } = string.Empty;
[Column(TypeName = "decimal(18, 2)")]
public decimal Price { get; set; }
}
}
Dalam kode sebelumnya:
- Anotasi
[Column(TypeName = "decimal(18, 2)")]
data memungkinkan Entity Framework Core memetakanPrice
mata uang dengan benar dalam database. Untuk informasi selengkapnya, lihat Jenis Data. - Atribut [Display] menentukan nama tampilan bidang. Dalam kode sebelumnya, "Tanggal Rilis" alih-alih "ReleaseDate".
- Atribut [DataType] menentukan jenis data (
Date
). Informasi waktu yang disimpan di bidang tidak ditampilkan.
DataAnnotations dibahas dalam tutorial berikutnya.
Telusuri ke Halaman/Film dan arahkan mouse ke atas tautan Edit untuk melihat URL target.
Tautan Edit, Detail, dan Hapus dihasilkan oleh Pembantu Tag Jangkar dalam Pages/Movies/Index.cshtml
file.
@foreach (var item in Model.Movie) {
<tr>
<td>
@Html.DisplayFor(modelItem => item.Title)
</td>
<td>
@Html.DisplayFor(modelItem => item.ReleaseDate)
</td>
<td>
@Html.DisplayFor(modelItem => item.Genre)
</td>
<td>
@Html.DisplayFor(modelItem => item.Price)
</td>
<td>
<a asp-page="./Edit" asp-route-id="@item.Id">Edit</a> |
<a asp-page="./Details" asp-route-id="@item.Id">Details</a> |
<a asp-page="./Delete" asp-route-id="@item.Id">Delete</a>
</td>
</tr>
}
</tbody>
</table>
Pembantu Tag mengaktifkan kode sisi server untuk berpartisipasi dalam membuat dan merender elemen HTML dalam file Razor.
Dalam kode sebelumnya, Pembantu Tag Jangkar secara dinamis menghasilkan nilai atribut HTML href
dari Razor Halaman (rute relatif), asp-page
, dan pengidentifikasi rute (asp-route-id
). Untuk informasi selengkapnya, lihat Pembuatan URL untuk Halaman.
Gunakan Tampilkan Sumber dari browser untuk memeriksa markup yang dihasilkan. Sebagian HTML yang dihasilkan ditunjukkan di bawah ini:
<td>
<a href="/Movies/Edit?id=1">Edit</a> |
<a href="/Movies/Details?id=1">Details</a> |
<a href="/Movies/Delete?id=1">Delete</a>
</td>
Tautan yang dihasilkan secara dinamis meneruskan ID film dengan string kueri. Misalnya, dalam ?id=1
https://localhost:5001/Movies/Details?id=1
.
Menambahkan templat rute
Perbarui Edit, Detail, dan Hapus Razor Halaman untuk menggunakan {id:int}
templat rute. Ubah arahan halaman untuk setiap halaman ini dari @page
ke @page "{id:int}"
. Jalankan aplikasi lalu lihat sumber.
HTML yang dihasilkan menambahkan ID ke bagian jalur URL:
<td>
<a href="/Movies/Edit/1">Edit</a> |
<a href="/Movies/Details/1">Details</a> |
<a href="/Movies/Delete/1">Delete</a>
</td>
Permintaan ke halaman dengan {id:int}
templat rute yang tidak menyertakan bilangan bulat akan mengembalikan kesalahan HTTP 404 (tidak ditemukan). Misalnya, https://localhost:5001/Movies/Details
akan mengembalikan kesalahan 404. Untuk menjadikan ID bersifat opsional, tambahkan ?
ke batasan rute:
@page "{id:int?}"
Uji perilaku @page "{id:int?}"
:
- Atur direktif
Pages/Movies/Details.cshtml
halaman ke@page "{id:int?}"
. - Atur titik henti di
public async Task<IActionResult> OnGetAsync(int? id)
, diPages/Movies/Details.cshtml.cs
. - Buka
https://localhost:5001/Movies/Details/
.
Dengan direktif @page "{id:int}"
, titik henti tidak pernah tertembak. Mesin perutean mengembalikan HTTP 404. Menggunakan @page "{id:int?}"
, OnGetAsync
metode mengembalikan NotFound
(HTTP 404):
public async Task<IActionResult> OnGetAsync(int? id)
{
if (id == null)
{
return NotFound();
}
Movie = await _context.Movie.FirstOrDefaultAsync(m => m.ID == id);
if (Movie == null)
{
return NotFound();
}
return Page();
}
Meninjau penanganan pengecualian konkurensi
OnPostAsync
Tinjau metode dalam Pages/Movies/Edit.cshtml.cs
file:
public async Task<IActionResult> OnPostAsync()
{
if (!ModelState.IsValid)
{
return Page();
}
_context.Attach(Movie).State = EntityState.Modified;
try
{
await _context.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException)
{
if (!MovieExists(Movie.ID))
{
return NotFound();
}
else
{
throw;
}
}
return RedirectToPage("./Index");
}
private bool MovieExists(int id)
{
return (_context.Movie?.Any(e => e.ID == id)).GetValueOrDefault();
}
Kode sebelumnya mendeteksi pengecualian konkurensi ketika satu klien menghapus film dan klien lain memposting perubahan pada film. Kode sebelumnya tidak mendeteksi konflik yang terjadi karena dua klien atau lebih yang mengedit film yang sama secara bersamaan. Dalam hal ini pengeditan oleh beberapa klien diterapkan dalam urutan yang SaveChanges
dipanggil dan pengeditan yang diterapkan nanti dapat menimpa pengeditan sebelumnya dengan nilai basi.
Untuk menguji catch
blok:
- Atur titik henti pada
catch (DbUpdateConcurrencyException)
. - Pilih Edit untuk film, buat perubahan, tetapi jangan masukkan Simpan.
- Di jendela browser lain, pilih tautan Hapus untuk film yang sama, lalu hapus film.
- Di jendela browser sebelumnya, posting perubahan pada film.
Kode produksi mungkin ingin mendeteksi konflik konkurensi tambahan seperti beberapa klien yang mengedit entitas secara bersamaan. Lihat Menangani konflik konkurensi untuk informasi selengkapnya.
Memposting dan mengikat ulasan
Periksa Pages/Movies/Edit.cshtml.cs
file:
public class EditModel : PageModel
{
private readonly RazorPagesMovie.Data.RazorPagesMovieContext _context;
public EditModel(RazorPagesMovie.Data.RazorPagesMovieContext context)
{
_context = context;
}
[BindProperty]
public Movie Movie { get; set; } = default!;
public async Task<IActionResult> OnGetAsync(int? id)
{
if (id == null || _context.Movie == null)
{
return NotFound();
}
var movie = await _context.Movie.FirstOrDefaultAsync(m => m.ID == id);
if (movie == null)
{
return NotFound();
}
Movie = movie;
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();
}
_context.Attach(Movie).State = EntityState.Modified;
try
{
await _context.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException)
{
if (!MovieExists(Movie.ID))
{
return NotFound();
}
else
{
throw;
}
}
return RedirectToPage("./Index");
}
private bool MovieExists(int id)
{
return (_context.Movie?.Any(e => e.ID == id)).GetValueOrDefault();
}
Ketika permintaan HTTP GET dibuat ke halaman Film/Edit, misalnya, https://localhost:5001/Movies/Edit/3
:
- Metode
OnGetAsync
mengambil film dari database dan mengembalikanPage
metode . - Metode merender
Page
Pages/Movies/Edit.cshtml
Razor Halaman. FilePages/Movies/Edit.cshtml
berisi direktif@model RazorPagesMovie.Pages.Movies.EditModel
model , yang membuat model film tersedia di halaman. - Formulir Edit ditampilkan dengan nilai dari film.
Saat halaman Film/Edit diposting:
Nilai formulir pada halaman terikat ke
Movie
properti . Atribut[BindProperty]
mengaktifkan pengikatan Model.[BindProperty] public Movie Movie { get; set; }
Jika ada kesalahan dalam status model, misalnya,
ReleaseDate
tidak dapat dikonversi ke tanggal, formulir diputar ulang dengan nilai yang dikirimkan.Jika tidak ada kesalahan model, film disimpan.
Metode HTTP GET di halaman Indeks, Buat, dan Hapus Razor mengikuti pola serupa. Metode HTTP POST OnPostAsync
di Halaman Buat Razor mengikuti pola OnPostAsync
yang mirip dengan metode di Edit Razor Halaman.
Langkah berikutnya
Aplikasi film perancah memiliki awal yang baik, tetapi presentasinya tidak ideal. ReleaseDate harus dua kata, Tanggal Rilis.
Memperbarui kode yang dihasilkan
Models/Movie.cs
Buka file dan tambahkan baris yang disorot yang diperlihatkan dalam kode berikut:
using System;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace RazorPagesMovie.Models
{
public class Movie
{
public int ID { get; set; }
public string Title { get; set; }
[Display(Name = "Release Date")]
[DataType(DataType.Date)]
public DateTime ReleaseDate { get; set; }
public string Genre { get; set; }
[Column(TypeName = "decimal(18, 2)")]
public decimal Price { get; set; }
}
}
Dalam kode sebelumnya:
- Anotasi
[Column(TypeName = "decimal(18, 2)")]
data memungkinkan Entity Framework Core memetakanPrice
mata uang dengan benar dalam database. Untuk informasi selengkapnya, lihat Jenis Data. - Atribut [Display] menentukan nama tampilan bidang. Dalam kode sebelumnya, "Tanggal Rilis" alih-alih "ReleaseDate".
- Atribut [DataType] menentukan jenis data (
Date
). Informasi waktu yang disimpan di bidang tidak ditampilkan.
DataAnnotations dibahas dalam tutorial berikutnya.
Telusuri ke Halaman/Film dan arahkan mouse ke atas tautan Edit untuk melihat URL target.
Tautan Edit, Detail, dan Hapus dihasilkan oleh Pembantu Tag Jangkar dalam Pages/Movies/Index.cshtml
file.
@foreach (var item in Model.Movie) {
<tr>
<td>
@Html.DisplayFor(modelItem => item.Title)
</td>
<td>
@Html.DisplayFor(modelItem => item.ReleaseDate)
</td>
<td>
@Html.DisplayFor(modelItem => item.Genre)
</td>
<td>
@Html.DisplayFor(modelItem => item.Price)
</td>
<td>
<a asp-page="./Edit" asp-route-id="@item.Id">Edit</a> |
<a asp-page="./Details" asp-route-id="@item.Id">Details</a> |
<a asp-page="./Delete" asp-route-id="@item.Id">Delete</a>
</td>
</tr>
}
</tbody>
</table>
Pembantu Tag mengaktifkan kode sisi server untuk berpartisipasi dalam membuat dan merender elemen HTML dalam file Razor.
Dalam kode sebelumnya, Pembantu Tag Jangkar secara dinamis menghasilkan nilai atribut HTML href
dari Razor Halaman (rute relatif), asp-page
, dan pengidentifikasi rute (asp-route-id
). Untuk informasi selengkapnya, lihat Pembuatan URL untuk Halaman.
Gunakan Tampilkan Sumber dari browser untuk memeriksa markup yang dihasilkan. Sebagian HTML yang dihasilkan ditunjukkan di bawah ini:
<td>
<a href="/Movies/Edit?id=1">Edit</a> |
<a href="/Movies/Details?id=1">Details</a> |
<a href="/Movies/Delete?id=1">Delete</a>
</td>
Tautan yang dihasilkan secara dinamis meneruskan ID film dengan string kueri. Misalnya, dalam ?id=1
https://localhost:5001/Movies/Details?id=1
.
Menambahkan templat rute
Perbarui Edit, Detail, dan Hapus Razor Halaman untuk menggunakan {id:int}
templat rute. Ubah arahan halaman untuk setiap halaman ini dari @page
ke @page "{id:int}"
. Jalankan aplikasi lalu lihat sumber.
HTML yang dihasilkan menambahkan ID ke bagian jalur URL:
<td>
<a href="/Movies/Edit/1">Edit</a> |
<a href="/Movies/Details/1">Details</a> |
<a href="/Movies/Delete/1">Delete</a>
</td>
Permintaan ke halaman dengan {id:int}
templat rute yang tidak menyertakan bilangan bulat akan mengembalikan kesalahan HTTP 404 (tidak ditemukan). Misalnya, https://localhost:5001/Movies/Details
akan mengembalikan kesalahan 404. Untuk menjadikan ID bersifat opsional, tambahkan ?
ke batasan rute:
@page "{id:int?}"
Uji perilaku @page "{id:int?}"
:
- Atur direktif
Pages/Movies/Details.cshtml
halaman ke@page "{id:int?}"
. - Atur titik henti di
public async Task<IActionResult> OnGetAsync(int? id)
, diPages/Movies/Details.cshtml.cs
. - Buka
https://localhost:5001/Movies/Details/
.
Dengan direktif @page "{id:int}"
, titik henti tidak pernah tertembak. Mesin perutean mengembalikan HTTP 404. Menggunakan @page "{id:int?}"
, OnGetAsync
metode mengembalikan NotFound
(HTTP 404):
public async Task<IActionResult> OnGetAsync(int? id)
{
if (id == null)
{
return NotFound();
}
Movie = await _context.Movie.FirstOrDefaultAsync(m => m.ID == id);
if (Movie == null)
{
return NotFound();
}
return Page();
}
Meninjau penanganan pengecualian konkurensi
OnPostAsync
Tinjau metode dalam Pages/Movies/Edit.cshtml.cs
file:
public async Task<IActionResult> OnPostAsync()
{
if (!ModelState.IsValid)
{
return Page();
}
_context.Attach(Movie).State = EntityState.Modified;
try
{
await _context.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException)
{
if (!MovieExists(Movie.ID))
{
return NotFound();
}
else
{
throw;
}
}
return RedirectToPage("./Index");
}
private bool MovieExists(int id)
{
return _context.Movie.Any(e => e.ID == id);
}
Kode sebelumnya mendeteksi pengecualian konkurensi ketika satu klien menghapus film dan klien lain memposting perubahan pada film.
Untuk menguji catch
blok:
- Atur titik henti pada
catch (DbUpdateConcurrencyException)
. - Pilih Edit untuk film, buat perubahan, tetapi jangan masukkan Simpan.
- Di jendela browser lain, pilih tautan Hapus untuk film yang sama, lalu hapus film.
- Di jendela browser sebelumnya, posting perubahan pada film.
Kode produksi mungkin ingin mendeteksi konflik konkurensi. Lihat Menangani konflik konkurensi untuk informasi selengkapnya.
Memposting dan mengikat ulasan
Periksa Pages/Movies/Edit.cshtml.cs
file:
public class EditModel : PageModel
{
private readonly RazorPagesMovie.Data.RazorPagesMovieContext _context;
public EditModel(RazorPagesMovie.Data.RazorPagesMovieContext context)
{
_context = context;
}
[BindProperty]
public Movie Movie { get; set; }
public async Task<IActionResult> OnGetAsync(int? id)
{
if (id == null)
{
return NotFound();
}
Movie = await _context.Movie.FirstOrDefaultAsync(m => m.ID == id);
if (Movie == null)
{
return NotFound();
}
return Page();
}
public async Task<IActionResult> OnPostAsync()
{
if (!ModelState.IsValid)
{
return Page();
}
_context.Attach(Movie).State = EntityState.Modified;
try
{
await _context.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException)
{
if (!MovieExists(Movie.ID))
{
return NotFound();
}
else
{
throw;
}
}
return RedirectToPage("./Index");
}
private bool MovieExists(int id)
{
return _context.Movie.Any(e => e.ID == id);
}
Ketika permintaan HTTP GET dibuat ke halaman Film/Edit, misalnya, https://localhost:5001/Movies/Edit/3
:
- Metode
OnGetAsync
mengambil film dari database dan mengembalikanPage
metode . - Metode merender
Page
Pages/Movies/Edit.cshtml
Razor Halaman. FilePages/Movies/Edit.cshtml
berisi direktif@model RazorPagesMovie.Pages.Movies.EditModel
model , yang membuat model film tersedia di halaman. - Formulir Edit ditampilkan dengan nilai dari film.
Saat halaman Film/Edit diposting:
Nilai formulir pada halaman terikat ke
Movie
properti . Atribut[BindProperty]
mengaktifkan pengikatan Model.[BindProperty] public Movie Movie { get; set; }
Jika ada kesalahan dalam status model, misalnya,
ReleaseDate
tidak dapat dikonversi ke tanggal, formulir diputar ulang dengan nilai yang dikirimkan.Jika tidak ada kesalahan model, film disimpan.
Metode HTTP GET di halaman Indeks, Buat, dan Hapus Razor mengikuti pola serupa. Metode HTTP POST OnPostAsync
di Halaman Buat Razor mengikuti pola OnPostAsync
yang mirip dengan metode di Edit Razor Halaman.
Langkah berikutnya
ASP.NET Core