Del 5, uppdatera de genererade sidorna i en ASP.NET Core-app

Anmärkning

Det här är inte den senaste versionen av den här artikeln. Den aktuella versionen finns i .NET 10-versionen av den här artikeln.

Varning

Den här versionen av ASP.NET Core stöds inte längre. Mer information finns i supportpolicyn för .NET och .NET Core. För den nuvarande utgåvan, se .NET 9-versionen av den här artikeln .

Den scaffolded filmappen har en bra start, men presentationen är inte idealisk. ReleaseDate ska vara två ord, Utgivningsdatum.

Filmprogram öppet i Chrome

Uppdatera modellen

Uppdatera Models/Movie.cs med följande markerade kod:

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; }
}

I föregående kod:

  • Med [Column(TypeName = "decimal(18, 2)")] dataanteckningen kan Entity Framework Core mappa Price till valuta i databasen på rätt sätt. Mer information finns i Datatyper.
  • Attributet [Display] anger visningsnamnet för ett fält. I den föregående koden, Release Date i stället för ReleaseDate.
  • Attributet [DataType] anger typen av data (Date). Tidsinformationen som lagras i fältet visas inte.

DataAnnotationer beskrivs i nästa handledning.

Bläddra till Sidor/Filmer och hovra över en Redigera-länk för att se mål-URL:en.

Webbläsarfönstret visas med muspekaren över länken Redigera och länken URL https://localhost:1234/Movies/Edit/5

Länkarna Redigera, Information och Ta bort genereras av fästpunktstagghjälpenPages/Movies/Index.cshtml i filen.

@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>

Tagghjälpare gör det möjligt för kod på serversidan att delta i skapandet och återgivningen av HTML-element i Razor filer.

I föregående kod genererar hjälpverktyget för fästpunkt dynamiskt HTML-attributvärdet href från Razor sidan (vägen är relativ), asp-page, och vägidentifieraren (asp-route-id). Mer information finns i URL-generering för sidor.

Använd Visa källa från en webbläsare för att undersöka den genererade markeringen. En del av den genererade HTML-koden visas nedan:

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

De dynamiskt genererade länkarna skickar film-ID:t med en frågesträng. Till exempel ?id=1 i https://localhost:5001/Movies/Details?id=1.

Lägg till routningsmall

Uppdatera redigera, information och ta bort Razor sidor för att använda routningsmallen {id:int} . Ändra siddirektivet för var och en av dessa sidor från @page till @page "{id:int}". Kör appen och visa sedan källan.

Den genererade HTML-koden lägger till ID:t i sökvägsdelen av URL:en:

<td>
  <a href="/Movies/Edit/1">Edit</a> |
  <a href="/Movies/Details/1">Details</a> |
  <a href="/Movies/Delete/1">Delete</a>
</td>

En begäran till sidan med {id:int} routemallen som inte innehåller heltal returnerar ett HTTP 404-fel (sidan kunde inte hittas). Returnerar https://localhost:5001/Movies/Details till exempel ett 404-fel. Om du vill göra ID:t valfritt lägger du till i routningsbegränsningen ? :

@page "{id:int?}"

Testa beteendet av @page "{id:int?}":

  1. Ange siddirektivet i Pages/Movies/Details.cshtml till @page "{id:int?}".
  2. Ange en brytpunkt i public async Task<IActionResult> OnGetAsync(int? id)i Pages/Movies/Details.cshtml.cs.
  3. Gå till https://localhost:5001/Movies/Details/.

Med direktivet @page "{id:int}" uppnås aldrig brytpunkten. Routningsmotorn returnerar HTTP 404. Metoden OnGetAsync returnerar NotFound med @page "{id:int?}" (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();
}

Granska hantering av samtidighetsfel

OnPostAsync Granska metoden i Pages/Movies/Edit.cshtml.cs filen:

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);
}

Den tidigare koden identifierar samtidighetsfel när en klient tar bort filmen och den andra klienten publicerar ändringar i filmen.

Så här testar du catch blocket:

  1. Ange en brytpunkt på catch (DbUpdateConcurrencyException).
  2. Välj Redigera för en film, gör ändringar, men ange inte Spara.
  3. I ett annat webbläsarfönster väljer du länken Ta bort för samma film och tar sedan bort filmen.
  4. I föregående webbläsarfönster publicerar du ändringar i filmen.

Produktionskoden kanske vill identifiera samtidighetskonflikter. Mer information finns i Hantera samtidighetskonflikter .

Granskning av publicering och koppling

Pages/Movies/Edit.cshtml.cs Granska filen:

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);
    }

När en HTTP GET-begäran görs till sidan Filmer/Redigera, https://localhost:5001/Movies/Edit/3till exempel :

  • Metoden OnGetAsync hämtar filmen från databasen och returnerar Page metoden.
  • Metoden Page renderar Pages/Movies/Edit.cshtmlRazor sidan. Filen Pages/Movies/Edit.cshtml innehåller modelldirektivet @model RazorPagesMovie.Pages.Movies.EditModel, vilket gör filmmodellen tillgänglig på sidan.
  • Formuläret Redigera visas med värdena från filmen.

När sidan Filmer/Redigera publiceras:

  • Formulärvärdena på sidan är bundna till egenskapen Movie . Attributet [BindProperty] aktiverar modellbindning.

    [BindProperty]
    public Movie Movie { get; set; }
    
  • Om det finns fel i modelltillståndet, till exempel om ReleaseDate inte kan konverteras till ett datum, visas formuläret igen med de skickade värdena.

  • Om det inte finns några modellfel sparas filmen.

HTTP GET-metoderna i sidorna Index, Skapa och Ta bort Razor följer ett liknande mönster. HTTP POST-metoden OnPostAsync i skapa-sidan Razor följer ett liknande mönster som OnPostAsync metoden i Redigera Razor sida.

Nästa steg

Den scaffolded filmappen har en bra start, men presentationen är inte idealisk. ReleaseDate ska vara två ord, Utgivningsdatum.

Filmprogram öppet i Chrome

Uppdatera modellen

Uppdatera Models/Movie.cs med följande markerade kod:

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; }
}

I föregående kod:

  • Med [Column(TypeName = "decimal(18, 2)")] dataanteckningen kan Entity Framework Core mappa Price till valuta i databasen på rätt sätt. Mer information finns i Datatyper.
  • Attributet [Display] anger visningsnamnet för ett fält. I den föregående koden, Release Date i stället för ReleaseDate.
  • Attributet [DataType] anger typen av data (Date). Tidsinformationen som lagras i fältet visas inte.

DataAnnotationer beskrivs i nästa handledning.

Bläddra till Sidor/Filmer och hovra över en Redigera-länk för att se mål-URL:en.

Webbläsarfönstret visas med muspekaren över länken Redigera och länken URL https://localhost:1234/Movies/Edit/5

Länkarna Redigera, Information och Ta bort genereras av fästpunktstagghjälpenPages/Movies/Index.cshtml i filen.

@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>

Tagghjälpare gör det möjligt för kod på serversidan att delta i skapandet och återgivningen av HTML-element i Razor filer.

I föregående kod genererar hjälpverktyget för fästpunkt dynamiskt HTML-attributvärdet href från Razor sidan (vägen är relativ), asp-page, och vägidentifieraren (asp-route-id). Mer information finns i URL-generering för sidor.

Använd Visa källa från en webbläsare för att undersöka den genererade markeringen. En del av den genererade HTML-koden visas nedan:

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

De dynamiskt genererade länkarna skickar film-ID:t med en frågesträng. Till exempel ?id=1 i https://localhost:5001/Movies/Details?id=1.

Lägg till routningsmall

Uppdatera redigera, information och ta bort Razor sidor för att använda routningsmallen {id:int} . Ändra siddirektivet för var och en av dessa sidor från @page till @page "{id:int}". Kör appen och visa sedan källan.

Den genererade HTML-koden lägger till ID:t i sökvägsdelen av URL:en:

<td>
  <a href="/Movies/Edit/1">Edit</a> |
  <a href="/Movies/Details/1">Details</a> |
  <a href="/Movies/Delete/1">Delete</a>
</td>

En begäran till sidan med {id:int} routemallen som inte innehåller heltal returnerar ett HTTP 404-fel (sidan kunde inte hittas). Returnerar https://localhost:5001/Movies/Details till exempel ett 404-fel. Om du vill göra ID:t valfritt lägger du till i routningsbegränsningen ? :

@page "{id:int?}"

Testa beteendet av @page "{id:int?}":

  1. Ange siddirektivet i Pages/Movies/Details.cshtml till @page "{id:int?}".
  2. Ange en brytpunkt i public async Task<IActionResult> OnGetAsync(int? id)i Pages/Movies/Details.cshtml.cs.
  3. Gå till https://localhost:5001/Movies/Details/.

Med direktivet @page "{id:int}" uppnås aldrig brytpunkten. Routningsmotorn returnerar HTTP 404. Metoden OnGetAsync returnerar NotFound med @page "{id:int?}" (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();
}

Granska hantering av samtidighetsfel

OnPostAsync Granska metoden i Pages/Movies/Edit.cshtml.cs filen:

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);
}

Den tidigare koden identifierar samtidighetsfel när en klient tar bort filmen och den andra klienten publicerar ändringar i filmen.

Så här testar du catch blocket:

  1. Ange en brytpunkt på catch (DbUpdateConcurrencyException).
  2. Välj Redigera för en film, gör ändringar, men ange inte Spara.
  3. I ett annat webbläsarfönster väljer du länken Ta bort för samma film och tar sedan bort filmen.
  4. I föregående webbläsarfönster publicerar du ändringar i filmen.

Produktionskoden kanske vill identifiera samtidighetskonflikter. Mer information finns i Hantera samtidighetskonflikter .

Granskning av publicering och koppling

Pages/Movies/Edit.cshtml.cs Granska filen:

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);
    }

När en HTTP GET-begäran görs till sidan Filmer/Redigera, https://localhost:5001/Movies/Edit/3till exempel :

  • Metoden OnGetAsync hämtar filmen från databasen och returnerar Page metoden.
  • Metoden Page renderar Pages/Movies/Edit.cshtmlRazor sidan. Filen Pages/Movies/Edit.cshtml innehåller modelldirektivet @model RazorPagesMovie.Pages.Movies.EditModel, vilket gör filmmodellen tillgänglig på sidan.
  • Formuläret Redigera visas med värdena från filmen.

När sidan Filmer/Redigera publiceras:

  • Formulärvärdena på sidan är bundna till egenskapen Movie . Attributet [BindProperty] aktiverar modellbindning.

    [BindProperty]
    public Movie Movie { get; set; }
    
  • Om det finns fel i modelltillståndet, till exempel om ReleaseDate inte kan konverteras till ett datum, visas formuläret igen med de skickade värdena.

  • Om det inte finns några modellfel sparas filmen.

HTTP GET-metoderna i sidorna Index, Skapa och Ta bort Razor följer ett liknande mönster. HTTP POST-metoden OnPostAsync i skapa-sidan Razor följer ett liknande mönster som OnPostAsync metoden i Redigera Razor sida.

Nästa steg

Den scaffolded filmappen har en bra start, men presentationen är inte idealisk. ReleaseDate ska vara två ord, Utgivningsdatum.

Filmprogram öppet i Chrome

Uppdatera modellen

Uppdatera Models/Movie.cs med följande markerade kod:

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; }
}

I föregående kod:

  • Med [Column(TypeName = "decimal(18, 2)")] dataanteckningen kan Entity Framework Core mappa Price till valuta i databasen på rätt sätt. Mer information finns i Datatyper.
  • Attributet [Display] anger visningsnamnet för ett fält. I den föregående koden, Release Date i stället för ReleaseDate.
  • Attributet [DataType] anger typen av data (Date). Tidsinformationen som lagras i fältet visas inte.

DataAnnotationer beskrivs i nästa handledning.

Bläddra till Sidor/Filmer och hovra över en Redigera-länk för att se mål-URL:en.

Webbläsarfönstret visas med muspekaren över länken Redigera och länken URL https://localhost:1234/Movies/Edit/5

Länkarna Redigera, Information och Ta bort genereras av fästpunktstagghjälpenPages/Movies/Index.cshtml i filen.

@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>

Tagghjälpare gör det möjligt för kod på serversidan att delta i skapandet och återgivningen av HTML-element i Razor filer.

I föregående kod genererar hjälpverktyget för fästpunkt dynamiskt HTML-attributvärdet href från Razor sidan (vägen är relativ), asp-page, och vägidentifieraren (asp-route-id). Mer information finns i URL-generering för sidor.

Använd Visa källa från en webbläsare för att undersöka den genererade markeringen. En del av den genererade HTML-koden visas nedan:

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

De dynamiskt genererade länkarna skickar film-ID:t med en frågesträng. Till exempel ?id=1 i https://localhost:5001/Movies/Details?id=1.

Lägg till routningsmall

Uppdatera redigera, information och ta bort Razor sidor för att använda routningsmallen {id:int} . Ändra siddirektivet för var och en av dessa sidor från @page till @page "{id:int}". Kör appen och visa sedan källan.

Den genererade HTML-koden lägger till ID:t i sökvägsdelen av URL:en:

<td>
  <a href="/Movies/Edit/1">Edit</a> |
  <a href="/Movies/Details/1">Details</a> |
  <a href="/Movies/Delete/1">Delete</a>
</td>

En begäran till sidan med {id:int} routemallen som inte innehåller heltal returnerar ett HTTP 404-fel (sidan kunde inte hittas). Returnerar https://localhost:5001/Movies/Details till exempel ett 404-fel. Om du vill göra ID:t valfritt lägger du till i routningsbegränsningen ? :

@page "{id:int?}"

Testa beteendet av @page "{id:int?}":

  1. Ange siddirektivet i Pages/Movies/Details.cshtml till @page "{id:int?}".
  2. Ange en brytpunkt i public async Task<IActionResult> OnGetAsync(int? id)i Pages/Movies/Details.cshtml.cs.
  3. Gå till https://localhost:5001/Movies/Details/.

Med direktivet @page "{id:int}" uppnås aldrig brytpunkten. Routningsmotorn returnerar HTTP 404. Metoden OnGetAsync returnerar NotFound med @page "{id:int?}" (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();
}

Granska hantering av samtidighetsfel

OnPostAsync Granska metoden i Pages/Movies/Edit.cshtml.cs filen:

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);
}

Den tidigare koden identifierar samtidighetsfel när en klient tar bort filmen och den andra klienten publicerar ändringar i filmen.

Så här testar du catch blocket:

  1. Ange en brytpunkt på catch (DbUpdateConcurrencyException).
  2. Välj Redigera för en film, gör ändringar, men ange inte Spara.
  3. I ett annat webbläsarfönster väljer du länken Ta bort för samma film och tar sedan bort filmen.
  4. I föregående webbläsarfönster publicerar du ändringar i filmen.

Produktionskoden kanske vill identifiera samtidighetskonflikter. Mer information finns i Hantera samtidighetskonflikter .

Granskning av publicering och koppling

Pages/Movies/Edit.cshtml.cs Granska filen:

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);
    }

När en HTTP GET-begäran görs till sidan Filmer/Redigera, https://localhost:5001/Movies/Edit/3till exempel :

  • Metoden OnGetAsync hämtar filmen från databasen och returnerar Page metoden.
  • Metoden Page renderar Pages/Movies/Edit.cshtmlRazor sidan. Filen Pages/Movies/Edit.cshtml innehåller modelldirektivet @model RazorPagesMovie.Pages.Movies.EditModel, vilket gör filmmodellen tillgänglig på sidan.
  • Formuläret Redigera visas med värdena från filmen.

När sidan Filmer/Redigera publiceras:

  • Formulärvärdena på sidan är bundna till egenskapen Movie . Attributet [BindProperty] aktiverar modellbindning.

    [BindProperty]
    public Movie Movie { get; set; }
    
  • Om det finns fel i modelltillståndet, till exempel om ReleaseDate inte kan konverteras till ett datum, visas formuläret igen med de skickade värdena.

  • Om det inte finns några modellfel sparas filmen.

HTTP GET-metoderna i sidorna Index, Skapa och Ta bort Razor följer ett liknande mönster. HTTP POST-metoden OnPostAsync i skapa-sidan Razor följer ett liknande mönster som OnPostAsync metoden i Redigera Razor sida.

Nästa steg

Den scaffolded filmappen har en bra start, men presentationen är inte idealisk. ReleaseDate ska vara två ord, Utgivningsdatum.

Filmprogram öppet i Chrome

Uppdatera den genererade koden

Uppdatera Models/Movie.cs med följande markerade kod:

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; }
    }
}

I föregående kod:

  • Med [Column(TypeName = "decimal(18, 2)")] dataanteckningen kan Entity Framework Core mappa Price till valuta i databasen på rätt sätt. Mer information finns i Datatyper.
  • Attributet [Display] anger visningsnamnet för ett fält. I föregående kod, "Utgivningsdatum" i stället för "ReleaseDate".
  • Attributet [DataType] anger typen av data (Date). Tidsinformationen som lagras i fältet visas inte.

DataAnnotationer beskrivs i nästa handledning.

Bläddra till Sidor/Filmer och hovra över en Redigera-länk för att se mål-URL:en.

Webbläsarfönstret visas med muspekaren över länken Redigera och länken URL https://localhost:1234/Movies/Edit/5

Länkarna Redigera, Information och Ta bort genereras av fästpunktstagghjälpenPages/Movies/Index.cshtml i filen.

@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>

Tagghjälpare gör det möjligt för kod på serversidan att delta i skapandet och återgivningen av HTML-element i Razor filer.

I föregående kod genererar hjälpverktyget för fästpunkt dynamiskt HTML-attributvärdet href från Razor sidan (vägen är relativ), asp-page, och vägidentifieraren (asp-route-id). Mer information finns i URL-generering för sidor.

Använd Visa källa från en webbläsare för att undersöka den genererade markeringen. En del av den genererade HTML-koden visas nedan:

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

De dynamiskt genererade länkarna skickar film-ID:t med en frågesträng. Till exempel ?id=1 i https://localhost:5001/Movies/Details?id=1.

Lägg till routningsmall

Uppdatera redigera, information och ta bort Razor sidor för att använda routningsmallen {id:int} . Ändra siddirektivet för var och en av dessa sidor från @page till @page "{id:int}". Kör appen och visa sedan källan.

Den genererade HTML-koden lägger till ID:t i sökvägsdelen av URL:en:

<td>
  <a href="/Movies/Edit/1">Edit</a> |
  <a href="/Movies/Details/1">Details</a> |
  <a href="/Movies/Delete/1">Delete</a>
</td>

En begäran till sidan med {id:int} routningsmallen som inte innehåller heltalet returnerar ett HTTP 404-fel (hittades inte). Till exempel https://localhost:5001/Movies/Details returnerar ett 404-fel. Om du vill göra ID:t valfritt lägger du till i routningsbegränsningen ? :

@page "{id:int?}"

Testa beteendet av @page "{id:int?}":

  1. Ange siddirektivet i Pages/Movies/Details.cshtml till @page "{id:int?}".
  2. Ange en brytpunkt i public async Task<IActionResult> OnGetAsync(int? id)i Pages/Movies/Details.cshtml.cs.
  3. Gå till https://localhost:5001/Movies/Details/.

Med direktivet @page "{id:int}" uppnås aldrig brytpunkten. Routningsmotorn returnerar HTTP 404. Med @page "{id:int?}"-metoden returnerar OnGetAsyncNotFound (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();
}

Granska hantering av samtidighetsfel

OnPostAsync Granska metoden i Pages/Movies/Edit.cshtml.cs filen:

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

Den tidigare koden identifierar samtidighetsfel när en klient tar bort filmen och den andra klienten publicerar ändringar i filmen. Den tidigare koden identifierar inte konflikter som uppstår på grund av att två eller flera klienter redigerar samma film samtidigt. I det här fallet tillämpas redigeringar av flera klienter i den ordning som SaveChanges anropas och redigeringar som tillämpas senare kan skriva över tidigare redigeringar med inaktuella värden.

Så här testar du catch blocket:

  1. Ange en brytpunkt på catch (DbUpdateConcurrencyException).
  2. Välj Redigera för en film, gör ändringar, men ange inte Spara.
  3. I ett annat webbläsarfönster väljer du länken Ta bort för samma film och tar sedan bort filmen.
  4. I föregående webbläsarfönster publicerar du ändringar i filmen.

Produktionskoden kanske vill identifiera ytterligare samtidighetskonflikter, till exempel flera klienter som redigerar en entitet samtidigt. Mer information finns i Hantera samtidighetskonflikter .

Granskning av publicering och sammanbindning

Pages/Movies/Edit.cshtml.cs Granska filen:

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

När en HTTP GET-begäran görs till sidan Filmer/Redigera, https://localhost:5001/Movies/Edit/3till exempel :

  • Metoden OnGetAsync hämtar filmen från databasen och returnerar Page metoden.
  • Metoden Page renderar Pages/Movies/Edit.cshtmlRazor sidan. Filen Pages/Movies/Edit.cshtml innehåller modelldirektivet @model RazorPagesMovie.Pages.Movies.EditModel, vilket gör filmmodellen tillgänglig på sidan.
  • Formuläret Redigera visas med värdena från filmen.

När sidan Filmer/Redigera publiceras:

  • Formulärvärdena på sidan är bundna till egenskapen Movie . Attributet [BindProperty] aktiverar modellbindning.

    [BindProperty]
    public Movie Movie { get; set; }
    
  • Om det finns fel i modelltillståndet, till exempel om ReleaseDate inte kan konverteras till ett datum, visas formuläret igen med de skickade värdena.

  • Om det inte finns några modellfel sparas filmen.

HTTP GET-metoderna i sidorna Index, Skapa och Ta bort Razor följer ett liknande mönster. HTTP POST-metoden OnPostAsync i skapa-sidan Razor följer ett liknande mönster som OnPostAsync metoden i Redigera Razor sida.

Nästa steg

Den ramverkbaserade filmapplikationen har en bra start, men presentationen är inte optimal. ReleaseDate ska vara två ord, Utgivningsdatum.

Filmprogram öppet i Chrome

Uppdatera den genererade koden

Models/Movie.cs Öppna filen och lägg till de markerade raderna som visas i följande kod:

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; }
    }
}

I föregående kod:

  • Med [Column(TypeName = "decimal(18, 2)")] dataanteckningen kan Entity Framework Core mappa Price till valuta i databasen på rätt sätt. Mer information finns i Datatyper.
  • Attributet [Display] anger visningsnamnet för ett fält. I föregående kod, "Utgivningsdatum" i stället för "ReleaseDate".
  • Attributet [DataType] anger typen av data (Date). Tidsinformationen som lagras i fältet visas inte.

Dataanalyser behandlas i nästa handledning.

Bläddra till Sidor/Filmer och hovra över en Redigera-länk för att se mål-URL:en.

Webbläsarfönstret visas med muspekaren över Redigera-länken och en länk-URL https://localhost:1234/Movies/Edit/5

Länkarna Redigera, Information och Ta bort genereras av fästpunktstagghjälpenPages/Movies/Index.cshtml i filen.

@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>

Tagghjälpare gör det möjligt för kod på serversidan att delta i skapandet och återgivningen av HTML-element i Razor filer.

I föregående kod genererar hjälpverktyget för fästpunkt dynamiskt HTML-attributvärdet href från Razor sidan (vägen är relativ), asp-page, och vägidentifieraren (asp-route-id). Mer information finns i URL-generering för sidor.

Använd Visa källa från en webbläsare för att undersöka den genererade markeringen. En del av den genererade HTML-koden visas nedan:

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

De dynamiskt genererade länkarna skickar film-ID:t med en frågesträng. Till exempel ?id=1 i https://localhost:5001/Movies/Details?id=1.

Lägg till routningsmall

Uppdatera redigera, information och ta bort Razor sidor för att använda routningsmallen {id:int} . Ändra siddirektivet för var och en av dessa sidor från @page till @page "{id:int}". Kör appen och visa sedan källan.

Den genererade HTML-koden lägger till ID:t i sökvägsdelen av URL:en:

<td>
  <a href="/Movies/Edit/1">Edit</a> |
  <a href="/Movies/Details/1">Details</a> |
  <a href="/Movies/Delete/1">Delete</a>
</td>

En begäran till sidan med {id:int} routningsmallen som inte innehåller heltalet returnerar ett HTTP 404-fel (hittades inte). Till exempel https://localhost:5001/Movies/Details returnerar ett 404-fel. Om du vill göra ID:t valfritt lägger du till i routningsbegränsningen ? :

@page "{id:int?}"

Testa beteendet för @page "{id:int?}":

  1. Ange siddirektivet i Pages/Movies/Details.cshtml till @page "{id:int?}".
  2. Ange en brytpunkt i public async Task<IActionResult> OnGetAsync(int? id)i Pages/Movies/Details.cshtml.cs.
  3. Gå till https://localhost:5001/Movies/Details/.

Med direktivet @page "{id:int}" uppnås aldrig brytpunkten. Routningsmotorn returnerar HTTP 404. Metoden OnGetAsync returnerar NotFound med @page "{id:int?}" (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();
}

Granska hantering av samtidighetsfel

OnPostAsync Granska metoden i Pages/Movies/Edit.cshtml.cs filen:

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);
}

Den tidigare koden identifierar samtidighetsfel när en klient tar bort filmen och den andra klienten publicerar ändringar i filmen.

Så här testar du catch blocket:

  1. Ange en brytpunkt på catch (DbUpdateConcurrencyException).
  2. Välj Redigera för en film, gör ändringar, men ange inte Spara.
  3. I ett annat webbläsarfönster väljer du länken Ta bort för samma film och tar sedan bort filmen.
  4. I föregående webbläsarfönster publicerar du ändringar i filmen.

Produktionskoden kanske vill identifiera samtidighetskonflikter. Mer information finns i Hantera samtidighetskonflikter .

Granskning av publicering och koppling

Pages/Movies/Edit.cshtml.cs Granska filen:

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);
    }

När en HTTP GET-begäran görs till sidan Filmer/Redigera, https://localhost:5001/Movies/Edit/3till exempel :

  • Metoden OnGetAsync hämtar filmen från databasen och returnerar Page metoden.
  • Metoden Page renderar Pages/Movies/Edit.cshtmlRazor sidan. Filen Pages/Movies/Edit.cshtml innehåller modelldirektivet @model RazorPagesMovie.Pages.Movies.EditModel, vilket gör filmmodellen tillgänglig på sidan.
  • Formuläret Redigera visas med värdena från filmen.

När sidan Filmer/Redigera publiceras:

  • Formulärvärdena på sidan är bundna till egenskapen Movie . Attributet [BindProperty] aktiverar modellbindning.

    [BindProperty]
    public Movie Movie { get; set; }
    
  • Om det finns fel i modelltillståndet, till exempel, ReleaseDate inte kan konverteras till ett datum, visas formuläret igen med de skickade värdena.

  • Om det inte finns några modellfel sparas filmen.

HTTP GET-metoderna i sidorna Index, Skapa och Ta bort Razor följer ett liknande mönster. HTTP POST-metoden OnPostAsync i skapa-sidan Razor följer ett liknande mönster som OnPostAsync metoden i Redigera Razor sida.

Nästa steg