5. Bölüm, ASP.NET Core uygulamasında oluşturulan sayfaları güncelleştirme

Not

Bu, bu makalenin en son sürümü değildir. Geçerli sürüm için bu makalenin .NET 8 sürümüne bakın.

Önemli

Bu bilgiler, ticari olarak piyasaya sürülmeden önce önemli ölçüde değiştirilebilen bir yayın öncesi ürünle ilgilidir. Burada verilen bilgilerle ilgili olarak Microsoft açık veya zımni hiçbir garanti vermez.

Geçerli sürüm için bu makalenin .NET 8 sürümüne bakın.

İ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.

Chrome'da açık film uygulaması

Modeli güncelleştirme

Aşağıdaki vurgulanmış kodla güncelleştirin Models/Movie.cs :

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 birimine doğru şekilde eşlenebir Price . Daha fazla bilgi için bkz . Veri Türleri.
  • [Display] özniteliği bir alanın görünen adını belirtir. Yukarıdaki kodda yerine Release DateReleaseDate.
  • [DataType] özniteliği verilerin türünü (Date ) belirtir. Alanda depolanan zaman bilgileri görüntülenmez.

DataAnnotations , sonraki öğreticide ele alınmıştır.

Sayfalar/Filmler'egöz atın ve hedef URL'yi görmek için düzenle bağlantısının üzerine gelin.

Düzenle bağlantısının üzerinde fareyle tarayıcı penceresi ve bağlantı Url'si https://localhost:1234/Movies/Edit/5 gösterilir

Düzenle, Ayrıntılar ve Sil bağlantıları, dosyadaki Pages/Movies/Index.cshtml Tutturucu Etiketi 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ı, Razor dosyalarında HTML öğelerinin oluşturulmasına ve işlenmesine sunucu tarafı kodun katılmasını etkinleştirir.

Yukarıdaki kodda Yer Işareti Etiketi Yardımcısı, Html öznitelik değerini Sayfadan href (yol görelidir), asp-pageve 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

Rota şablonu ekleme

Yol ş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 şablonu içeren {id:int} sayfaya yapılan 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ı yapmak için yönlendirme kısıtlamasının sonuna ? ekleyin:

@page "{id:int?}"

davranışını test edin @page "{id:int?}":

  1. içindeki Pages/Movies/Details.cshtml sayfa yönergesini olarak @page "{id:int?}"ayarlayın.
  2. içinde Pages/Movies/Details.cshtml.csiçinde public async Task<IActionResult> OnGetAsync(int? id)bir kesme noktası ayarlayın.
  3. Şuraya gidin: https://localhost:5001/Movies/Details/

yönergesi @page "{id:int}" ile kesme noktası hiçbir zaman isabet etmez. Yönlendirme altyapısı HTTP 404 döndürür. OnGetAsync kullanarak @page "{id:int?}"yöntemi döndürür 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 OnPostAsyncPages/Movies/Edit.cshtml.cs yöntemini 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:

  1. üzerinde catch (DbUpdateConcurrencyException)bir kesme noktası ayarlayın.
  2. Film için Düzenle'yi seçin, değişiklikler yapın, ancak Kaydet'e girmeyin.
  3. Başka bir tarayıcı penceresinde, aynı film için Sil bağlantısını seçin ve ardından filmi silin.
  4. Ö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.

Deftere nakil 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; } = 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);
    }

Filmler/Düzenleme sayfasına bir HTTP GET isteği yapıldığında, örneğin: https://localhost:5001/Movies/Edit/3

  • yöntemi, OnGetAsync filmi veritabanından getirir ve yöntemini döndürür Page .
  • Page yöntemi Sayfayı Pages/Movies/Edit.cshtmlRazor işler. dosyası Pages/Movies/Edit.cshtml , film modelini sayfada kullanılabilir hale getiren model yönergesini @model RazorPagesMovie.Pages.Movies.EditModeliçerir.
  • Düzenleme 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. özniteliği Model [BindProperty] 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.

Dizin, Oluşturma ve Silme Razor sayfalarındaki HTTP GET yöntemleri benzer bir deseni izler. Oluşturma Razor Sayfasındaki HTTP POST OnPostAsync yöntemi, Düzenleme Sayfası'ndaki Razor yönteme OnPostAsync benzer bir desen izler.

Sonraki adımlar

İ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.

Chrome'da açık film uygulaması

Modeli güncelleştirme

Aşağıdaki vurgulanmış kodla güncelleştirin Models/Movie.cs :

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 birimine doğru şekilde eşlenebir Price . Daha fazla bilgi için bkz . Veri Türleri.
  • [Display] özniteliği bir alanın görünen adını belirtir. Yukarıdaki kodda yerine Release DateReleaseDate.
  • [DataType] özniteliği verilerin türünü (Date ) belirtir. Alanda depolanan zaman bilgileri görüntülenmez.

DataAnnotations , sonraki öğreticide ele alınmıştır.

Sayfalar/Filmler'egöz atın ve hedef URL'yi görmek için düzenle bağlantısının üzerine gelin.

Düzenle bağlantısının üzerinde fareyle tarayıcı penceresi ve bağlantı Url'si https://localhost:1234/Movies/Edit/5 gösterilir

Düzenle, Ayrıntılar ve Sil bağlantıları, dosyadaki Pages/Movies/Index.cshtml Tutturucu Etiketi 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ı, Razor dosyalarında HTML öğelerinin oluşturulmasına ve işlenmesine sunucu tarafı kodun katılmasını etkinleştirir.

Yukarıdaki kodda Yer Işareti Etiketi Yardımcısı, Html öznitelik değerini Sayfadan href (yol görelidir), asp-pageve 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

Rota şablonu ekleme

Yol ş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 şablonu içeren {id:int} sayfaya yapılan 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ı yapmak için yönlendirme kısıtlamasının sonuna ? ekleyin:

@page "{id:int?}"

davranışını test edin @page "{id:int?}":

  1. içindeki Pages/Movies/Details.cshtml sayfa yönergesini olarak @page "{id:int?}"ayarlayın.
  2. içinde Pages/Movies/Details.cshtml.csiçinde public async Task<IActionResult> OnGetAsync(int? id)bir kesme noktası ayarlayın.
  3. Şuraya gidin: https://localhost:5001/Movies/Details/

yönergesi @page "{id:int}" ile kesme noktası hiçbir zaman isabet etmez. Yönlendirme altyapısı HTTP 404 döndürür. OnGetAsync kullanarak @page "{id:int?}"yöntemi döndürür 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 OnPostAsyncPages/Movies/Edit.cshtml.cs yöntemini 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:

  1. üzerinde catch (DbUpdateConcurrencyException)bir kesme noktası ayarlayın.
  2. Film için Düzenle'yi seçin, değişiklikler yapın, ancak Kaydet'e girmeyin.
  3. Başka bir tarayıcı penceresinde, aynı film için Sil bağlantısını seçin ve ardından filmi silin.
  4. Ö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.

Deftere nakil 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; } = 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);
    }

Filmler/Düzenleme sayfasına bir HTTP GET isteği yapıldığında, örneğin: https://localhost:5001/Movies/Edit/3

  • yöntemi, OnGetAsync filmi veritabanından getirir ve yöntemini döndürür Page .
  • Page yöntemi Sayfayı Pages/Movies/Edit.cshtmlRazor işler. dosyası Pages/Movies/Edit.cshtml , film modelini sayfada kullanılabilir hale getiren model yönergesini @model RazorPagesMovie.Pages.Movies.EditModeliçerir.
  • Düzenleme 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. özniteliği Model [BindProperty] 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.

Dizin, Oluşturma ve Silme Razor sayfalarındaki HTTP GET yöntemleri benzer bir deseni izler. Oluşturma Razor Sayfasındaki HTTP POST OnPostAsync yöntemi, Düzenleme Sayfası'ndaki Razor yönteme OnPostAsync benzer bir desen izler.

Sonraki adımlar

İ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.

Chrome'da açık film uygulaması

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 birimine doğru şekilde eşlenebir Price . 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" (Sürüm Tarihi) ifadesi kullanılır.
  • [DataType] özniteliği verilerin türünü (Date ) belirtir. Alanda depolanan zaman bilgileri görüntülenmez.

DataAnnotations , sonraki öğreticide ele alınmıştır.

Sayfalar/Filmler'egöz atın ve hedef URL'yi görmek için düzenle bağlantısının üzerine gelin.

Düzenle bağlantısının üzerinde fareyle tarayıcı penceresi ve bağlantı Url'si https://localhost:1234/Movies/Edit/5 gösterilir

Düzenle, Ayrıntılar ve Sil bağlantıları, dosyadaki Pages/Movies/Index.cshtml Tutturucu Etiketi 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ı, Razor dosyalarında HTML öğelerinin oluşturulmasına ve işlenmesine sunucu tarafı kodun katılmasını etkinleştirir.

Yukarıdaki kodda Yer Işareti Etiketi Yardımcısı, Html öznitelik değerini Sayfadan href (yol görelidir), asp-pageve 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

Rota şablonu ekleme

Yol ş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} yapılan istekte HTTP 404 (bulunamadı) hatası döndürülecektir. Örneğin, https://localhost:5001/Movies/Details bir 404 hatası döndürür. Kimliği isteğe bağlı yapmak için yönlendirme kısıtlamasının sonuna ? ekleyin:

@page "{id:int?}"

davranışını test edin @page "{id:int?}":

  1. içindeki Pages/Movies/Details.cshtml sayfa yönergesini olarak @page "{id:int?}"ayarlayın.
  2. içinde Pages/Movies/Details.cshtml.csiçinde public async Task<IActionResult> OnGetAsync(int? id)bir kesme noktası ayarlayın.
  3. Şuraya gidin: https://localhost:5001/Movies/Details/

yönergesi @page "{id:int}" ile kesme noktası hiçbir zaman isabet etmez. Yönlendirme altyapısı HTTP 404 döndürür. OnGetAsync kullanarak @page "{id:int?}"yöntemi döndürür 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 OnPostAsyncPages/Movies/Edit.cshtml.cs yöntemini 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)).GetValueOrDefault();
}

Ö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. Önceki kod, aynı filmi eşzamanlı olarak düzenleyen iki veya daha fazla istemci nedeniyle oluşan çakışmaları algılamaz. Bu durumda, birden çok istemci tarafından yapılan düzenlemeler çağrılan sırayla SaveChanges uygulanır ve daha sonra uygulanan düzenlemeler eski değerlerle önceki düzenlemelerin üzerine yazabilir.

Bloğu test etmek catch için:

  1. üzerinde catch (DbUpdateConcurrencyException)bir kesme noktası ayarlayın.
  2. Film için Düzenle'yi seçin, değişiklikler yapın, ancak Kaydet'e girmeyin.
  3. Başka bir tarayıcı penceresinde, aynı film için Sil bağlantısını seçin ve ardından filmi silin.
  4. Önceki tarayıcı penceresinde, değişiklikleri filme gönderin.

Üretim kodu, bir varlığı aynı anda birden çok istemcinin düzenlemesi gibi ek 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.

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

Filmler/Düzenleme sayfasına bir HTTP GET isteği yapıldığında, örneğin: https://localhost:5001/Movies/Edit/3

  • yöntemi, OnGetAsync filmi veritabanından getirir ve yöntemini döndürür Page .
  • Page yöntemi Sayfayı Pages/Movies/Edit.cshtmlRazor işler. dosyası Pages/Movies/Edit.cshtml , film modelini sayfada kullanılabilir hale getiren model yönergesini @model RazorPagesMovie.Pages.Movies.EditModeliçerir.
  • Düzenleme 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. özniteliği Model [BindProperty] 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.

Dizin, Oluşturma ve Silme Razor sayfalarındaki HTTP GET yöntemleri benzer bir deseni izler. Oluşturma Razor Sayfasındaki HTTP POST OnPostAsync yöntemi, Düzenleme Sayfası'ndaki Razor yönteme OnPostAsync benzer bir desen izler.

Sonraki adımlar

İ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.

Chrome'da açık film uygulaması

Oluşturulan kodu güncelleştirme

Models/Movie.cs Dosyayı açın ve aşağıdaki kodda gösterilen vurgulanmış 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 birimine doğru şekilde eşlenebir Price . 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" (Sürüm Tarihi) ifadesi kullanılır.
  • [DataType] özniteliği verilerin türünü (Date ) belirtir. Alanda depolanan zaman bilgileri görüntülenmez.

DataAnnotations , sonraki öğreticide ele alınmıştır.

Sayfalar/Filmler'egöz atın ve hedef URL'yi görmek için düzenle bağlantısının üzerine gelin.

Düzenle bağlantısının üzerinde fareyle tarayıcı penceresi ve bağlantı Url'si https://localhost:1234/Movies/Edit/5 gösterilir

Düzenle, Ayrıntılar ve Sil bağlantıları, dosyadaki Pages/Movies/Index.cshtml Tutturucu Etiketi 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ı, Razor dosyalarında HTML öğelerinin oluşturulmasına ve işlenmesine sunucu tarafı kodun katılmasını etkinleştirir.

Yukarıdaki kodda Yer Işareti Etiketi Yardımcısı, Html öznitelik değerini Sayfadan href (yol görelidir), asp-pageve 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

Rota şablonu ekleme

Yol ş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} yapılan istekte HTTP 404 (bulunamadı) hatası döndürülecektir. Örneğin, https://localhost:5001/Movies/Details bir 404 hatası döndürür. Kimliği isteğe bağlı yapmak için yönlendirme kısıtlamasının sonuna ? ekleyin:

@page "{id:int?}"

davranışını test edin @page "{id:int?}":

  1. içindeki Pages/Movies/Details.cshtml sayfa yönergesini olarak @page "{id:int?}"ayarlayın.
  2. içinde Pages/Movies/Details.cshtml.csiçinde public async Task<IActionResult> OnGetAsync(int? id)bir kesme noktası ayarlayın.
  3. Şuraya gidin: https://localhost:5001/Movies/Details/

yönergesi @page "{id:int}" ile kesme noktası hiçbir zaman isabet etmez. Yönlendirme altyapısı HTTP 404 döndürür. OnGetAsync kullanarak @page "{id:int?}"yöntemi döndürür 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 OnPostAsyncPages/Movies/Edit.cshtml.cs yöntemini 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:

  1. üzerinde catch (DbUpdateConcurrencyException)bir kesme noktası ayarlayın.
  2. Film için Düzenle'yi seçin, değişiklikler yapın, ancak Kaydet'e girmeyin.
  3. Başka bir tarayıcı penceresinde, aynı film için Sil bağlantısını seçin ve ardından filmi silin.
  4. Ö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.

Deftere nakil 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

  • yöntemi, OnGetAsync filmi veritabanından getirir ve yöntemini döndürür Page .
  • Page yöntemi Sayfayı Pages/Movies/Edit.cshtmlRazor işler. dosyası Pages/Movies/Edit.cshtml , film modelini sayfada kullanılabilir hale getiren model yönergesini @model RazorPagesMovie.Pages.Movies.EditModeliçerir.
  • Düzenleme 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. özniteliği Model [BindProperty] 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.

Dizin, Oluşturma ve Silme Razor sayfalarındaki HTTP GET yöntemleri benzer bir deseni izler. Oluşturma Razor Sayfasındaki HTTP POST OnPostAsync yöntemi, Düzenleme Sayfası'ndaki Razor yönteme OnPostAsync benzer bir desen izler.

Sonraki adımlar