Bölüm 5, bir ASP.NET Core uygulamasında oluşturulan sayfaları güncelleştirme
Gönderen Rick Anderson
İskeleli film uygulamasının iyi bir başlangıcı vardır, ancak sunu ideal değildir. ReleaseDate iki sözcük olmalıdır: Yayın Tarihi.
Oluşturulan kodu güncelleştirme
Aşağıdaki vurgulanmış kodla güncelleştirin Models/Movie.cs
:
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; }
}
}
Önceki kodda:
- Veri
[Column(TypeName = "decimal(18, 2)")]
ek açıklaması, Entity Framework Core'un veritabanındaki para birimiyle doğru şekilde eşlenebilenPrice
olmasını sağlar. Daha fazla bilgi için bkz. Veri Türleri. - [Display] özniteliği bir alanın görünen adını belirtir. Yukarıdaki kodda ,"ReleaseDate" yerine "Release Date" (Yayın Tarihi).
- [DataType] özniteliği verilerin türünü belirtir (
Date
). Alanda depolanan zaman bilgileri görüntülenmez.
DataAnnotations , sonraki öğreticide ele alınmıştır.
Sayfalar/Filmler'e gidin ve hedef URL'yi görmek için Düzenle bağlantısının üzerine gelin.
Düzenle, Ayrıntılar ve Sil bağlantıları, dosyadaki Pages/Movies/Index.cshtml
Yer Işareti Yardımcısı tarafından oluşturulur.
@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>
Etiket Yardımcıları , sunucu tarafı kodunun dosyalarda HTML öğeleri Razor oluşturma ve işlemeye katılmasını sağlar.
Yukarıdaki kodda Yer Işareti Etiketi Yardımcısı, Html öznitelik değerini Sayfadan href
(yol görelidir), asp-page
ve yol tanımlayıcısından Razor (asp-route-id
) dinamik olarak oluşturur. Daha fazla bilgi için bkz. Sayfalar için URL oluşturma.
Oluşturulan işaretlemeyi incelemek için tarayıcıdan Kaynağı Görüntüle'yi kullanın. Oluşturulan HTML'nin bir bölümü aşağıda gösterilmiştir:
<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>
Dinamik olarak oluşturulan bağlantılar, film kimliğini bir sorgu dizesiyle geçirir. Örneğin, içindeki ?id=1
https://localhost:5001/Movies/Details?id=1
.
Yol şablonu ekleme
Rota şablonunu kullanmak için Sayfaları Düzenle, Ayrıntılar ve Sil'i Razor güncelleştirin {id:int}
. Bu sayfaların her biri için sayfa yönergesini olarak @page
@page "{id:int}"
değiştirin. Uygulamayı çalıştırın ve ardından kaynağı görüntüleyin.
Oluşturulan HTML, kimliği URL'nin yol bölümüne ekler:
<td>
<a href="/Movies/Edit/1">Edit</a> |
<a href="/Movies/Details/1">Details</a> |
<a href="/Movies/Delete/1">Delete</a>
</td>
Tamsayıyı içermeyen yol şablonunu içeren sayfaya {id:int}
yönelik bir istek HTTP 404 (bulunamadı) hatası döndürür. Örneğin, https://localhost:5001/Movies/Details
404 hatası döndürür. Kimliği isteğe bağlı hale getirmek için yol kısıtlamasına ekleyin ?
:
@page "{id:int?}"
davranışını @page "{id:int?}"
test edin:
- içindeki
Pages/Movies/Details.cshtml
sayfa yönergesini olarak@page "{id:int?}"
ayarlayın. - içinde içinde
public async Task<IActionResult> OnGetAsync(int? id)
Pages/Movies/Details.cshtml.cs
bir kesme noktası ayarlayın. https://localhost:5001/Movies/Details/
sayfasına gidin.
yönergesi @page "{id:int}"
ile kesme noktasına hiçbir zaman isabet etmez. Yönlendirme altyapısı HTTP 404 döndürür. @page "{id:int?}"
yöntemi kullanılarak OnGetAsync
(HTTP 404) döndürülüyor NotFound
:
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();
}
Eşzamanlılık özel durum işlemesini gözden geçirme
Dosyasındaki OnPostAsync
yöntemini Pages/Movies/Edit.cshtml.cs
gözden geçirin:
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);
}
Önceki kod, bir istemci filmi sildiğinde ve diğer istemci filme değişiklik gönderdiğinde eşzamanlılık özel durumlarını algılar.
Bloğu test etmek catch
için:
- üzerinde
catch (DbUpdateConcurrencyException)
bir kesme noktası ayarlayın. - Film için Düzenle'yi seçin, değişiklikler yapın, ancak Kaydet'e girmeyin.
- Başka bir tarayıcı penceresinde, aynı film için Sil bağlantısını seçin ve ardından filmi silin.
- Önceki tarayıcı penceresinde, değişiklikleri filme gönderin.
Üretim kodu eşzamanlılık çakışmalarını algılamak isteyebilir. Daha fazla bilgi için bkz. Eşzamanlılık çakışmalarını işleme .
Gönderme ve bağlama gözden geçirmesi
Pages/Movies/Edit.cshtml.cs
Dosyayı inceleyin:
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);
}
Filmler/Düzenleme sayfasına bir HTTP GET isteği yapıldığında, örneğin: https://localhost:5001/Movies/Edit/3
OnGetAsync
yöntemi, filmi veritabanından getirir ve yöntemini döndürürPage
.Page
yöntemi Page'iPages/Movies/Edit.cshtml
Razor işler. dosyasıPages/Movies/Edit.cshtml
, film modelini sayfada kullanılabilir hale getiren model yönergesini@model RazorPagesMovie.Pages.Movies.EditModel
içerir.- Düzenle formu filmdeki değerlerle birlikte görüntülenir.
Filmler/Düzenle sayfası gönderildiğinde:
Sayfadaki form değerleri özelliğine
Movie
bağlıdır.[BindProperty]
özniteliği Model bağlamayı etkinleştirir.[BindProperty] public Movie Movie { get; set; }
Örneğin
ReleaseDate
, model durumunda bir tarihe dönüştürülemeyen hatalar varsa, form gönderilen değerlerle yeniden görüntülenir.Model hatası yoksa film kaydedilir.
, Oluştur ve Sil Razor sayfalarındaki IndexHTTP GET yöntemleri de benzer bir desen izler. Oluşturma Razor Sayfasındaki HTTP POST OnPostAsync
yöntemi, Sayfayı Düzenle'deki Razor yönteme OnPostAsync
benzer bir desen izler.
Ek kaynaklar
İskeleli film uygulamasının iyi bir başlangıcı vardır, ancak sunu ideal değildir. ReleaseDate iki sözcük olmalıdır: Yayın Tarihi.
Oluşturulan kodu güncelleştirme
Models/Movie.cs
Dosyayı açın ve aşağıdaki kodda gösterilen vurgulanan satırları ekleyin:
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; }
}
}
Önceki kodda:
- Veri
[Column(TypeName = "decimal(18, 2)")]
ek açıklaması, Entity Framework Core'un veritabanındaki para birimiyle doğru şekilde eşlenebilenPrice
olmasını sağlar. Daha fazla bilgi için bkz. Veri Türleri. - [Display] özniteliği bir alanın görünen adını belirtir. Yukarıdaki kodda ,"ReleaseDate" yerine "Release Date" (Yayın Tarihi).
- [DataType] özniteliği verilerin türünü belirtir (
Date
). Alanda depolanan zaman bilgileri görüntülenmez.
DataAnnotations , sonraki öğreticide ele alınmıştır.
Sayfalar/Filmler'e gidin ve hedef URL'yi görmek için Düzenle bağlantısının üzerine gelin.
Düzenle, Ayrıntılar ve Sil bağlantıları, dosyadaki Pages/Movies/Index.cshtml
Yer Işareti Yardımcısı tarafından oluşturulur.
@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>
Etiket Yardımcıları , sunucu tarafı kodunun dosyalarda HTML öğeleri Razor oluşturma ve işlemeye katılmasını sağlar.
Yukarıdaki kodda Yer Işareti Etiketi Yardımcısı, Html öznitelik değerini Sayfadan href
(yol görelidir), asp-page
ve yol tanımlayıcısından Razor (asp-route-id
) dinamik olarak oluşturur. Daha fazla bilgi için bkz. Sayfalar için URL oluşturma.
Oluşturulan işaretlemeyi incelemek için tarayıcıdan Kaynağı Görüntüle'yi kullanın. Oluşturulan HTML'nin bir bölümü aşağıda gösterilmiştir:
<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>
Dinamik olarak oluşturulan bağlantılar, film kimliğini bir sorgu dizesiyle geçirir. Örneğin, içindeki ?id=1
https://localhost:5001/Movies/Details?id=1
.
Yol şablonu ekleme
Rota şablonunu kullanmak için Sayfaları Düzenle, Ayrıntılar ve Sil'i Razor güncelleştirin {id:int}
. Bu sayfaların her biri için sayfa yönergesini olarak @page
@page "{id:int}"
değiştirin. Uygulamayı çalıştırın ve ardından kaynağı görüntüleyin.
Oluşturulan HTML, kimliği URL'nin yol bölümüne ekler:
<td>
<a href="/Movies/Edit/1">Edit</a> |
<a href="/Movies/Details/1">Details</a> |
<a href="/Movies/Delete/1">Delete</a>
</td>
Tamsayıyı içermeyen yol şablonunu içeren sayfaya {id:int}
yönelik bir istek HTTP 404 (bulunamadı) hatası döndürür. Örneğin, https://localhost:5001/Movies/Details
404 hatası döndürür. Kimliği isteğe bağlı hale getirmek için yol kısıtlamasına ekleyin ?
:
@page "{id:int?}"
davranışını @page "{id:int?}"
test edin:
- içindeki
Pages/Movies/Details.cshtml
page yönergesini olarak@page "{id:int?}"
ayarlayın. - içinde içinde
public async Task<IActionResult> OnGetAsync(int? id)
Pages/Movies/Details.cshtml.cs
bir kesme noktası ayarlayın. https://localhost:5001/Movies/Details/
sayfasına gidin.
yönergesi @page "{id:int}"
ile kesme noktasına hiçbir zaman isabet olmaz. Yönlendirme altyapısı HTTP 404 döndürür. @page "{id:int?}"
OnGetAsync
yöntemi kullanılarak döndürülüyor 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();
}
Eşzamanlılık özel durum işlemesini gözden geçirme
Dosyasındaki OnPostAsync
yöntemini Pages/Movies/Edit.cshtml.cs
gözden geçirin:
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);
}
Önceki kod, bir istemci filmi sildiğinde ve diğer istemci de değişiklikleri filme gönderdiğinde eşzamanlılık özel durumlarını algılar.
Bloğu test etmek catch
için:
- üzerinde
catch (DbUpdateConcurrencyException)
bir kesme noktası ayarlayın. - Film için Düzenle'yi seçin, değişiklik yapın, ancak Kaydet'e girmeyin.
- Başka bir tarayıcı penceresinde, aynı film için Sil bağlantısını seçin ve ardından filmi silin.
- Önceki tarayıcı penceresinde, değişiklikleri filme gönderin.
Üretim kodu eşzamanlılık çakışmalarını algılamak isteyebilir. Daha fazla bilgi için bkz. Eşzamanlılık çakışmalarını işleme .
Gönderme ve bağlama gözden geçirmesi
Pages/Movies/Edit.cshtml.cs
Dosyayı inceleyin:
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);
}
Filmler/Düzenle sayfasına bir HTTP GET isteği yapıldığında, örneğin: https://localhost:5001/Movies/Edit/3
OnGetAsync
yöntemi, filmi veritabanından getirir ve yöntemini döndürürPage
.Page
yöntemi Page'iPages/Movies/Edit.cshtml
Razor işler.Pages/Movies/Edit.cshtml
dosyası, film modelini sayfada kullanılabilir hale getiren model yönergesini@model RazorPagesMovie.Pages.Movies.EditModel
içerir.- Düzenle formu filmdeki değerlerle birlikte görüntülenir.
Filmler/Düzenle sayfası gönderildiğinde:
Sayfadaki form değerleri özelliğine
Movie
bağlıdır.[BindProperty]
özniteliği Model bağlamayı etkinleştirir.[BindProperty] public Movie Movie { get; set; }
Örneğin model durumunda hatalar varsa,
ReleaseDate
tarihe dönüştürülemiyorsa form gönderilen değerlerle yeniden görüntülenir.Model hatası yoksa film kaydedilir.
, Create ve Delete Razor sayfalarındaki IndexHTTP GET yöntemleri de benzer bir desen izler. Oluşturma Razor Sayfasındaki HTTP POST OnPostAsync
yöntemi, Düzenleme Razor Sayfası'ndaki yönteme OnPostAsync
benzer bir desen izler.