Delen via


Deel 5: de gegenereerde pagina's bijwerken in een ASP.NET Core-app

Opmerking

Dit is niet de nieuwste versie van dit artikel. Zie de .NET 10-versie van dit artikel voor de huidige release.

Waarschuwing

Deze versie van ASP.NET Core wordt niet meer ondersteund. Zie het .NET- en .NET Core-ondersteuningsbeleid voor meer informatie. Zie de .NET 10-versie van dit artikel voor de huidige release.

De scaffolded film-app is een goed begin, maar de presentatie is niet ideaal. ReleaseDatum moet twee woorden zijn: Releasedatum.

De filmtoepassing is geopend in Chrome.

Het model bijwerken

Werk Models/Movie.cs bij met de volgende gemarkeerde code:

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

In de vorige code:

  • Met de [Column(TypeName = "decimal(18, 2)")] gegevensaantekening kan Entity Framework Core Price correct toewijzen aan valuta in de database. Zie gegevenstypenvoor meer informatie.
  • Het kenmerk [Weergave] geeft de weergavenaam van een veld op. In de voorgaande code, Release Date in plaats van ReleaseDate.
  • Het kenmerk [DataType] geeft het type van de gegevens (Date). De tijdgegevens die in het veld zijn opgeslagen, worden niet weergegeven.

DataAnnotations wordt behandeld in de volgende zelfstudie.

Blader naar Pagina's/Films en beweeg de muisaanwijzer over een koppeling Bewerken om de doel-URL te bekijken.

Browservenster met de muis over de koppeling Bewerken en er wordt een koppelings-URL https://localhost:1234/Movies/Edit/5 weergegeven.

De koppelingen Bewerken, Details en Verwijderen worden gegenereerd door de Anchor Tag Helper in het Pages/Movies/Index.cshtml bestand.

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

Tag Helpers zorgen ervoor dat code aan de serverzijde kan deelnemen aan het maken en weergeven van HTML-elementen in Razor bestanden.

In de voorgaande code genereert de Anchor Tag Helper dynamisch de HTML-kenmerkwaarde href van de Razor pagina (de route is relatief), de asp-pageen de route-id (asp-route-id). Zie URL-generatie voor pagina's voor meer informatie.

Gebruik De weergavebron vanuit een browser om de gegenereerde markeringen te onderzoeken. Hieronder ziet u een deel van de gegenereerde HTML:

<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 dynamisch gegenereerde koppelingen geven de film-id door aan een queryreeks. Bijvoorbeeld de ?id=1 in https://localhost:7247/Movies/Details?id=1.

Routesjabloon toevoegen

Pas de pagina's Bewerken, Details en Verwijderen Razor aan om de {id:int} routesjabloon te gebruiken. Wijzig de pagina-instructie voor elk van deze pagina's van @page in @page "{id:int}". Voer de app uit en bekijk vervolgens de bron.

De gegenereerde HTML voegt de ID toe aan het padgedeelte van de URL.

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

Een aanvraag voor de pagina met de {id:int} routesjabloon die niet het gehele getal bevat, retourneert een HTTP 404-fout (niet gevonden). Retourneert bijvoorbeeld https://localhost:7247/Movies/Details een 404-fout. Als u de id optioneel wilt maken, voegt u deze toe aan ? de routebeperking:

@page "{id:int?}"

Test het gedrag van @page "{id:int?}":

  1. Stel de pagina-richtlijn in Pages/Movies/Details.cshtml op @page "{id:int?}".
  2. Stel een onderbrekingspunt in public async Task<IActionResult> OnGetAsync(int? id), in Pages/Movies/Details.cshtml.cs.
  3. Navigeer naar https://localhost:7247/Movies/Details/.

Met de @page "{id:int}" richtlijn wordt het onderbrekingspunt nooit bereikt. De routeringsengine retourneert HTTP 404. @page "{id:int?}" De OnGetAsyncmethode retourneert NotFound (HTTP 404):

public async Task<IActionResult> OnGetAsync(int? id)
{
    if (id == null)
    {
        return NotFound();
    }

    var movie = await _context.Movie.FirstOrDefaultAsync(m => m.Id == id);
    if (movie == null)
    {
        return NotFound();
    }
    else
    {
        Movie = movie;
    }
    return Page();
}

Afhandeling van gelijktijdigheidsonderzondering controleren

Controleer de OnPostAsync methode in het Pages/Movies/Edit.cshtml.cs bestand:

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

Met de vorige code worden gelijktijdigheidsonderingen gedetecteerd wanneer de ene client de film verwijdert en de andere client wijzigingen in de film plaatst.

Het catch-blok testen:

  1. Stel een onderbrekingspunt in op catch (DbUpdateConcurrencyException).
  2. Selecteer Bewerken voor een film, breng wijzigingen aan, maar selecteer Opslaan niet.
  3. Selecteer in een ander browservenster de koppeling Verwijderen voor dezelfde film en verwijder de film.
  4. In het vorige browservenster plaatst u wijzigingen in de film.

Productiecode zou gelijktijdigheidsconflicten kunnen detecteren. Voor meer informatie, zie Gelijktijdigheidsconflicten afhandelen.

Boekings- en bindingsbeoordeling

Bekijk het Pages/Movies/Edit.cshtml.cs bestand:

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

Wanneer u een HTTP GET-aanvraag naar de Movies/Edit pagina maakt, https://localhost:7247/Movies/Edit/3bijvoorbeeld:

  • De OnGetAsync methode haalt de film op uit de database en retourneert de Page methode.
  • De Page methode geeft de Pages/Movies/Edit.cshtmlRazor pagina weer. Het Pages/Movies/Edit.cshtml bestand bevat de modelrichtlijn @model RazorPagesMovie.Pages.Movies.EditModel, waardoor het filmmodel beschikbaar is op de pagina.
  • In het formulier Bewerken worden de waarden uit de film weergegeven.

Wanneer u de Movies/Edit pagina plaatst:

  • De formulierwaarden op de pagina binden aan de Movie eigenschap. Het [BindProperty] kenmerk maakt modelbinding mogelijk.

    [BindProperty]
    public Movie Movie { get; set; }
    
  • Als er bijvoorbeeld fouten in de modelstatus optreden, zoals dat ReleaseDate niet kan worden omgezet naar een datum, wordt het formulier opnieuw getoond met de ingediende waarden.

  • Als er geen modelfouten zijn, wordt de film opgeslagen.

De HTTP GET-methoden in de pagina's Index, Maken en Verwijderen Razor volgen een vergelijkbaar patroon. De HTTP POST-methode OnPostAsync in de create Razor page volgt een vergelijkbaar patroon als de OnPostAsync methode in de bewerkingspagina Razor .

Volgende stappen

De opgebouwde filmapplicatie heeft een goed begin, maar de presentatie is niet ideaal. ReleaseDatum moet twee woorden zijn: Releasedatum.

Filmtoepassing geopend in Chrome

Het model bijwerken

Werk Models/Movie.cs bij met de volgende gemarkeerde code:

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

In de vorige code:

  • Met de [Column(TypeName = "decimal(18, 2)")] gegevensaantekening kan Entity Framework Core Price correct toewijzen aan valuta in de database. Zie gegevenstypenvoor meer informatie.
  • Het kenmerk [Weergave] geeft de weergavenaam van een veld op. In de voorgaande code, Release Date in plaats van ReleaseDate.
  • Het kenmerk [DataType] geeft het type van de gegevens (Date). De tijdgegevens die in het veld zijn opgeslagen, worden niet weergegeven.

DataAnnotations wordt behandeld in de volgende zelfstudie.

Blader naar Pagina's/Films en beweeg de muisaanwijzer over een koppeling Bewerken om de doel-URL te bekijken.

Een browservenster wordt weergegeven waarin de muis boven de koppeling Bewerken zweeft en een koppelings-URL https://localhost:1234/Movies/Edit/5 wordt getoond

De koppelingen Bewerken, Details en Verwijderen worden gegenereerd door de Anchor Tag Helper in het Pages/Movies/Index.cshtml bestand.

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

Tag Helpers zorgen ervoor dat code aan de serverzijde kan deelnemen aan het maken en weergeven van HTML-elementen in Razor bestanden.

In de voorgaande code genereert de Anchor Tag Helper dynamisch de HTML-kenmerkwaarde href van de Razor pagina (de route is relatief), de asp-pageen de route-id (asp-route-id). Zie URL-generatie voor pagina's voor meer informatie.

Gebruik De weergavebron vanuit een browser om de gegenereerde markeringen te onderzoeken. Hieronder ziet u een deel van de gegenereerde HTML:

<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 dynamisch gegenereerde koppelingen geven de film-id door aan een queryreeks. Bijvoorbeeld de ?id=1 in https://localhost:5001/Movies/Details?id=1.

Routesjabloon toevoegen

Pas de pagina's Bewerken, Details en Verwijderen Razor aan om de {id:int} routesjabloon te gebruiken. Wijzig de pagina-instructie voor elk van deze pagina's van @page in @page "{id:int}". Voer de app uit en bekijk vervolgens de bron.

De gegenereerde HTML voegt de ID toe aan het padgedeelte van de URL.

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

Een aanvraag naar de pagina met de {id:int} routesjabloon die niet het gehele getal bevat, retourneert een HTTP 404-fout (niet gevonden). Retourneert bijvoorbeeld https://localhost:5001/Movies/Details een 404-fout. Als u de id optioneel wilt maken, voegt u deze toe aan ? de routebeperking:

@page "{id:int?}"

Test het gedrag van @page "{id:int?}":

  1. Stel de pagina-richtlijn in Pages/Movies/Details.cshtml op @page "{id:int?}".
  2. Stel een onderbrekingspunt in public async Task<IActionResult> OnGetAsync(int? id), in Pages/Movies/Details.cshtml.cs.
  3. Navigeer naar https://localhost:5001/Movies/Details/.

Met de @page "{id:int}" richtlijn wordt het onderbrekingspunt nooit bereikt. De routeringsengine retourneert HTTP 404. @page "{id:int?}" De OnGetAsyncmethode retourneert NotFound (HTTP 404):

public async Task<IActionResult> OnGetAsync(int? id)
{
    if (id == null)
    {
        return NotFound();
    }

    var movie = await _context.Movie.FirstOrDefaultAsync(m => m.Id == id);
    if (movie == null)
    {
        return NotFound();
    }
    else
    {
        Movie = movie;
    }
    return Page();
}

Afhandeling van gelijktijdigheidsonderzondering controleren

Controleer de OnPostAsync methode in het Pages/Movies/Edit.cshtml.cs bestand:

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

Met de vorige code worden gelijktijdigheidsonderingen gedetecteerd wanneer de ene client de film verwijdert en de andere client wijzigingen in de film plaatst.

Het catch-blok testen:

  1. Stel een onderbrekingspunt in op catch (DbUpdateConcurrencyException).
  2. Selecteer Bewerken voor een film, breng wijzigingen aan, maar voer Opslaan niet in.
  3. Selecteer in een ander browservenster de koppeling Verwijderen voor dezelfde film en verwijder de film.
  4. In het vorige browservenster plaatst u wijzigingen in de film.

Productiecode zou gelijktijdigheidsconflicten kunnen detecteren. Raadpleeg Gelijktijdigheidsconflicten afhandelen voor meer informatie.

Boekings- en bindingsbeoordeling

Bekijk het Pages/Movies/Edit.cshtml.cs bestand:

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

Wanneer een HTTP GET-aanvraag wordt ingediend op de pagina Films/Bewerken, https://localhost:5001/Movies/Edit/3bijvoorbeeld:

  • De OnGetAsync methode haalt de film op uit de database en retourneert de Page methode.
  • De Page methode geeft de Pages/Movies/Edit.cshtmlRazor pagina weer. Het Pages/Movies/Edit.cshtml bestand bevat de modelrichtlijn @model RazorPagesMovie.Pages.Movies.EditModel, waardoor het filmmodel beschikbaar is op de pagina.
  • Het formulier Bewerken wordt weergegeven met de waarden uit de film.

Wanneer de pagina Films/Bewerken wordt geplaatst:

  • De formulierwaarden op de pagina zijn gebonden aan de Movie eigenschap. Het [BindProperty] kenmerk maakt modelbinding mogelijk.

    [BindProperty]
    public Movie Movie { get; set; }
    
  • Als er fouten zijn in de modelstatus, bijvoorbeeld, ReleaseDate kan niet worden omgezet in een datum, wordt het formulier opnieuw weergegeven met de ingediende waarden.

  • Als er geen modelfouten zijn, wordt de film opgeslagen.

De HTTP GET-methoden in de pagina's Index, Maken en Verwijderen Razor volgen een vergelijkbaar patroon. De HTTP POST-methode OnPostAsync in de create Razor page volgt een vergelijkbaar patroon als de OnPostAsync methode in de bewerkingspagina Razor .

Volgende stappen

De opgebouwde filmapplicatie heeft een goed begin, maar de presentatie is niet ideaal. ReleaseDatum moet twee woorden zijn: Releasedatum.

Filmtoepassing geopend in Chrome

Het model bijwerken

Werk Models/Movie.cs bij met de volgende gemarkeerde code:

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

In de vorige code:

  • Met de [Column(TypeName = "decimal(18, 2)")] gegevensaantekening kan Entity Framework Core Price correct toewijzen aan valuta in de database. Zie gegevenstypenvoor meer informatie.
  • Het kenmerk [Weergave] geeft de weergavenaam van een veld op. In de voorgaande code, Release Date in plaats van ReleaseDate.
  • Het kenmerk [DataType] geeft het type van de gegevens (Date). De tijdgegevens die in het veld zijn opgeslagen, worden niet weergegeven.

DataAnnotations wordt behandeld in de volgende zelfstudie.

Blader naar Pagina's/Films en beweeg de muisaanwijzer over een koppeling Bewerken om de doel-URL te bekijken.

Een browservenster wordt weergegeven waarin de muis boven de koppeling Bewerken zweeft en een koppelings-URL https://localhost:1234/Movies/Edit/5 wordt getoond

De koppelingen Bewerken, Details en Verwijderen worden gegenereerd door de Anchor Tag Helper in het Pages/Movies/Index.cshtml bestand.

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

Tag Helpers zorgen ervoor dat code aan de serverzijde kan deelnemen aan het maken en weergeven van HTML-elementen in Razor bestanden.

In de voorgaande code genereert de Anchor Tag Helper dynamisch de HTML-kenmerkwaarde href van de Razor pagina (de route is relatief), de asp-pageen de route-id (asp-route-id). Zie URL-generatie voor pagina's voor meer informatie.

Gebruik De weergavebron vanuit een browser om de gegenereerde markeringen te onderzoeken. Hieronder ziet u een deel van de gegenereerde HTML:

<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 dynamisch gegenereerde koppelingen geven de film-id door aan een queryreeks. Bijvoorbeeld de ?id=1 in https://localhost:5001/Movies/Details?id=1.

Routesjabloon toevoegen

Pas de pagina's Bewerken, Details en Verwijderen Razor aan om de {id:int} routesjabloon te gebruiken. Wijzig de pagina-instructie voor elk van deze pagina's van @page in @page "{id:int}". Voer de app uit en bekijk vervolgens de bron.

De gegenereerde HTML voegt de ID toe aan het padgedeelte van de URL.

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

Een aanvraag naar de pagina met de {id:int} routesjabloon die niet het gehele getal bevat, retourneert een HTTP 404-fout (niet gevonden). Retourneert bijvoorbeeld https://localhost:5001/Movies/Details een 404-fout. Als u de id optioneel wilt maken, voegt u deze toe aan ? de routebeperking:

@page "{id:int?}"

Test het gedrag van @page "{id:int?}":

  1. Stel de pagina-richtlijn in Pages/Movies/Details.cshtml op @page "{id:int?}".
  2. Stel een onderbrekingspunt in public async Task<IActionResult> OnGetAsync(int? id), in Pages/Movies/Details.cshtml.cs.
  3. Navigeer naar https://localhost:5001/Movies/Details/.

Met de @page "{id:int}" richtlijn wordt het onderbrekingspunt nooit bereikt. De routeringsengine retourneert HTTP 404. @page "{id:int?}" De OnGetAsyncmethode retourneert 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();
}

Afhandeling van gelijktijdigheidsonderzondering controleren

Controleer de OnPostAsync methode in het Pages/Movies/Edit.cshtml.cs bestand:

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

Met de vorige code worden gelijktijdigheidsonderingen gedetecteerd wanneer de ene client de film verwijdert en de andere client wijzigingen in de film plaatst.

Het catch-blok testen:

  1. Stel een onderbrekingspunt in op catch (DbUpdateConcurrencyException).
  2. Selecteer Bewerken voor een film, breng wijzigingen aan, maar voer Opslaan niet in.
  3. Selecteer in een ander browservenster de koppeling Verwijderen voor dezelfde film en verwijder de film.
  4. In het vorige browservenster plaatst u wijzigingen in de film.

Productiecode zou gelijktijdigheidsconflicten kunnen detecteren. Raadpleeg Gelijktijdigheidsconflicten afhandelen voor meer informatie.

Boekings- en bindingsbeoordeling

Bekijk het Pages/Movies/Edit.cshtml.cs bestand:

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

Wanneer een HTTP GET-aanvraag wordt ingediend op de pagina Films/Bewerken, https://localhost:5001/Movies/Edit/3bijvoorbeeld:

  • De OnGetAsync methode haalt de film op uit de database en retourneert de Page methode.
  • De Page methode geeft de Pages/Movies/Edit.cshtmlRazor pagina weer. Het Pages/Movies/Edit.cshtml bestand bevat de modelrichtlijn @model RazorPagesMovie.Pages.Movies.EditModel, waardoor het filmmodel beschikbaar is op de pagina.
  • Het formulier Bewerken wordt weergegeven met de waarden uit de film.

Wanneer de pagina Films/Bewerken wordt geplaatst:

  • De formulierwaarden op de pagina zijn gebonden aan de Movie eigenschap. Het [BindProperty] kenmerk maakt modelbinding mogelijk.

    [BindProperty]
    public Movie Movie { get; set; }
    
  • Als er fouten zijn in de modelstatus, bijvoorbeeld, ReleaseDate kan niet worden omgezet in een datum, wordt het formulier opnieuw weergegeven met de ingediende waarden.

  • Als er geen modelfouten zijn, wordt de film opgeslagen.

De HTTP GET-methoden in de pagina's Index, Maken en Verwijderen Razor volgen een vergelijkbaar patroon. De HTTP POST-methode OnPostAsync in de create Razor page volgt een vergelijkbaar patroon als de OnPostAsync methode in de bewerkingspagina Razor .

Volgende stappen

De opgebouwde filmapplicatie heeft een goed begin, maar de presentatie is niet ideaal. ReleaseDatum moet twee woorden zijn: Releasedatum.

Filmtoepassing geopend in Chrome

Het model bijwerken

Werk Models/Movie.cs bij met de volgende gemarkeerde code:

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

In de vorige code:

  • Met de [Column(TypeName = "decimal(18, 2)")] gegevensaantekening kan Entity Framework Core Price correct toewijzen aan valuta in de database. Zie gegevenstypenvoor meer informatie.
  • Het kenmerk [Weergave] geeft de weergavenaam van een veld op. In de voorgaande code, Release Date in plaats van ReleaseDate.
  • Het kenmerk [DataType] geeft het type van de gegevens (Date). De tijdgegevens die in het veld zijn opgeslagen, worden niet weergegeven.

DataAnnotations wordt behandeld in de volgende zelfstudie.

Blader naar Pagina's/Films en beweeg de muisaanwijzer over een koppeling Bewerken om de doel-URL te bekijken.

Een browservenster wordt weergegeven waarin de muis boven de koppeling Bewerken zweeft en een koppelings-URL https://localhost:1234/Movies/Edit/5 wordt getoond

De koppelingen Bewerken, Details en Verwijderen worden gegenereerd door de Anchor Tag Helper in het Pages/Movies/Index.cshtml bestand.

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

Tag Helpers zorgen ervoor dat code aan de serverzijde kan deelnemen aan het maken en weergeven van HTML-elementen in Razor bestanden.

In de voorgaande code genereert de Anchor Tag Helper dynamisch de HTML-kenmerkwaarde href van de Razor pagina (de route is relatief), de asp-pageen de route-id (asp-route-id). Zie URL-generatie voor pagina's voor meer informatie.

Gebruik De weergavebron vanuit een browser om de gegenereerde markeringen te onderzoeken. Hieronder ziet u een deel van de gegenereerde HTML:

<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 dynamisch gegenereerde koppelingen geven de film-id door aan een queryreeks. Bijvoorbeeld de ?id=1 in https://localhost:5001/Movies/Details?id=1.

Routesjabloon toevoegen

Pas de pagina's Bewerken, Details en Verwijderen Razor aan om de {id:int} routesjabloon te gebruiken. Wijzig de pagina-instructie voor elk van deze pagina's van @page in @page "{id:int}". Voer de app uit en bekijk vervolgens de bron.

De gegenereerde HTML voegt de ID toe aan het padgedeelte van de URL.

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

Een aanvraag naar de pagina met de {id:int} routesjabloon die niet het gehele getal bevat, retourneert een HTTP 404-fout (niet gevonden). Retourneert bijvoorbeeld https://localhost:5001/Movies/Details een 404-fout. Als u de id optioneel wilt maken, voegt u deze toe aan ? de routebeperking:

@page "{id:int?}"

Test het gedrag van @page "{id:int?}":

  1. Stel de pagina-richtlijn in Pages/Movies/Details.cshtml op @page "{id:int?}".
  2. Stel een onderbrekingspunt in public async Task<IActionResult> OnGetAsync(int? id), in Pages/Movies/Details.cshtml.cs.
  3. Navigeer naar https://localhost:5001/Movies/Details/.

Met de @page "{id:int}" richtlijn wordt het onderbrekingspunt nooit bereikt. De routeringsengine retourneert HTTP 404. @page "{id:int?}" De OnGetAsyncmethode retourneert 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();
}

Afhandeling van gelijktijdigheidsonderzondering controleren

Controleer de OnPostAsync methode in het Pages/Movies/Edit.cshtml.cs bestand:

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

Met de vorige code worden gelijktijdigheidsonderingen gedetecteerd wanneer de ene client de film verwijdert en de andere client wijzigingen in de film plaatst.

Het catch-blok testen:

  1. Stel een onderbrekingspunt in op catch (DbUpdateConcurrencyException).
  2. Selecteer Bewerken voor een film, breng wijzigingen aan, maar voer Opslaan niet in.
  3. Selecteer in een ander browservenster de koppeling Verwijderen voor dezelfde film en verwijder de film.
  4. In het vorige browservenster plaatst u wijzigingen in de film.

Productiecode zou gelijktijdigheidsconflicten kunnen detecteren. Raadpleeg Gelijktijdigheidsconflicten afhandelen voor meer informatie.

Boekings- en bindingsbeoordeling

Bekijk het Pages/Movies/Edit.cshtml.cs bestand:

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

Wanneer een HTTP GET-aanvraag wordt ingediend op de pagina Films/Bewerken, https://localhost:5001/Movies/Edit/3bijvoorbeeld:

  • De OnGetAsync methode haalt de film op uit de database en retourneert de Page methode.
  • De Page methode geeft de Pages/Movies/Edit.cshtmlRazor pagina weer. Het Pages/Movies/Edit.cshtml bestand bevat de modelrichtlijn @model RazorPagesMovie.Pages.Movies.EditModel, waardoor het filmmodel beschikbaar is op de pagina.
  • Het formulier Bewerken wordt weergegeven met de waarden uit de film.

Wanneer de pagina Films/Bewerken wordt geplaatst:

  • De formulierwaarden op de pagina zijn gebonden aan de Movie eigenschap. Het [BindProperty] kenmerk maakt modelbinding mogelijk.

    [BindProperty]
    public Movie Movie { get; set; }
    
  • Als er fouten zijn in de modelstatus, bijvoorbeeld, ReleaseDate kan niet worden omgezet in een datum, wordt het formulier opnieuw weergegeven met de ingediende waarden.

  • Als er geen modelfouten zijn, wordt de film opgeslagen.

De HTTP GET-methoden in de pagina's Index, Maken en Verwijderen Razor volgen een vergelijkbaar patroon. De HTTP POST-methode OnPostAsync in de create Razor page volgt een vergelijkbaar patroon als de OnPostAsync methode in de bewerkingspagina Razor .

Volgende stappen

De opgebouwde filmapplicatie heeft een goed begin, maar de presentatie is niet ideaal. ReleaseDatum moet twee woorden zijn: Releasedatum.

Filmtoepassing geopend in Chrome

De gegenereerde code bijwerken

Werk Models/Movie.cs bij met de volgende gemarkeerde code:

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

In de vorige code:

  • Met de [Column(TypeName = "decimal(18, 2)")] gegevensaantekening kan Entity Framework Core Price correct toewijzen aan valuta in de database. Zie gegevenstypenvoor meer informatie.
  • Het kenmerk [Weergave] geeft de weergavenaam van een veld op. In de voorgaande code, 'ReleaseDatum' in plaats van 'ReleaseDate'.
  • Het kenmerk [DataType] geeft het type van de gegevens (Date). De tijdgegevens die in het veld zijn opgeslagen, worden niet weergegeven.

DataAnnotations wordt behandeld in de volgende zelfstudie.

Blader naar Pagina's/Films en beweeg de muisaanwijzer over een koppeling Bewerken om de doel-URL te bekijken.

Een browservenster wordt weergegeven waarin de muis boven de koppeling Bewerken zweeft en een koppelings-URL https://localhost:1234/Movies/Edit/5 wordt getoond

De koppelingen Bewerken, Details en Verwijderen worden gegenereerd door de Anchor Tag Helper in het Pages/Movies/Index.cshtml bestand.

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

Tag Helpers zorgen ervoor dat code aan de serverzijde kan deelnemen aan het maken en weergeven van HTML-elementen in Razor bestanden.

In de voorgaande code genereert de Anchor Tag Helper dynamisch de HTML-kenmerkwaarde href van de Razor pagina (de route is relatief), de asp-pageen de route-id (asp-route-id). Zie URL-generatie voor pagina's voor meer informatie.

Gebruik De weergavebron vanuit een browser om de gegenereerde markeringen te onderzoeken. Hieronder ziet u een deel van de gegenereerde HTML:

<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 dynamisch gegenereerde koppelingen geven de film-id door aan een queryreeks. Bijvoorbeeld de ?id=1 in https://localhost:5001/Movies/Details?id=1.

Routesjabloon toevoegen

Pas de pagina's Bewerken, Details en Verwijderen Razor aan om de {id:int} routesjabloon te gebruiken. Wijzig de pagina-instructie voor elk van deze pagina's van @page in @page "{id:int}". Voer de app uit en bekijk vervolgens de bron.

De gegenereerde HTML voegt de ID toe aan het padgedeelte van de URL.

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

Een aanvraag naar de pagina met de {id:int} routesjabloon die niet het gehele getal bevat, retourneert een HTTP 404-fout (niet gevonden). Retourneert bijvoorbeeld https://localhost:5001/Movies/Details een 404-fout. Als u de id optioneel wilt maken, voegt u deze toe aan ? de routebeperking:

@page "{id:int?}"

Test het gedrag van @page "{id:int?}":

  1. Stel de pagina-richtlijn in Pages/Movies/Details.cshtml op @page "{id:int?}".
  2. Stel een onderbrekingspunt in public async Task<IActionResult> OnGetAsync(int? id), in Pages/Movies/Details.cshtml.cs.
  3. Navigeer naar https://localhost:5001/Movies/Details/.

Met de @page "{id:int}" richtlijn wordt het onderbrekingspunt nooit bereikt. De routeringsengine retourneert HTTP 404. @page "{id:int?}" De OnGetAsyncmethode retourneert 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();
}

Afhandeling van gelijktijdigheidsonderzondering controleren

Controleer de OnPostAsync methode in het Pages/Movies/Edit.cshtml.cs bestand:

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

Met de vorige code worden gelijktijdigheidsonderingen gedetecteerd wanneer de ene client de film verwijdert en de andere client wijzigingen in de film plaatst. De vorige code detecteert geen conflicten die optreden vanwege twee of meer clients die dezelfde film gelijktijdig bewerken. In dit geval worden bewerkingen door meerdere clients toegepast in de volgorde waarin SaveChanges wordt aangeroepen, en bewerkingen die later worden toegepast, kunnen eerdere bewerkingen met verouderde waarden overschrijven.

Het catch-blok testen:

  1. Stel een onderbrekingspunt in op catch (DbUpdateConcurrencyException).
  2. Selecteer Bewerken voor een film, breng wijzigingen aan, maar voer Opslaan niet in.
  3. Selecteer in een ander browservenster de koppeling Verwijderen voor dezelfde film en verwijder de film.
  4. In het vorige browservenster plaatst u wijzigingen in de film.

Productiecode kan extra gelijktijdigheidsconflicten detecteren, zoals meerdere clients die tegelijkertijd een entiteit bewerken. Raadpleeg Gelijktijdigheidsconflicten afhandelen voor meer informatie.

Boekings- en bindingsbeoordeling

Bekijk het Pages/Movies/Edit.cshtml.cs bestand:

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

Wanneer een HTTP GET-aanvraag wordt ingediend op de pagina Films/Bewerken, https://localhost:5001/Movies/Edit/3bijvoorbeeld:

  • De OnGetAsync methode haalt de film op uit de database en retourneert de Page methode.
  • De Page methode geeft de Pages/Movies/Edit.cshtmlRazor pagina weer. Het Pages/Movies/Edit.cshtml bestand bevat de modelrichtlijn @model RazorPagesMovie.Pages.Movies.EditModel, waardoor het filmmodel beschikbaar is op de pagina.
  • Het formulier Bewerken wordt weergegeven met de waarden uit de film.

Wanneer de pagina Films/Bewerken wordt geplaatst:

  • De formulierwaarden op de pagina zijn gebonden aan de Movie eigenschap. Het [BindProperty] kenmerk maakt modelbinding mogelijk.

    [BindProperty]
    public Movie Movie { get; set; }
    
  • Als er fouten zijn in de modelstatus, bijvoorbeeld, ReleaseDate kan niet worden omgezet in een datum, wordt het formulier opnieuw weergegeven met de ingediende waarden.

  • Als er geen modelfouten zijn, wordt de film opgeslagen.

De HTTP GET-methoden in de pagina's Index, Maken en Verwijderen Razor volgen een vergelijkbaar patroon. De HTTP POST-methode OnPostAsync in de create Razor page volgt een vergelijkbaar patroon als de OnPostAsync methode in de bewerkingspagina Razor .

Volgende stappen

De opgebouwde filmapplicatie heeft een goed begin, maar de presentatie is niet ideaal. ReleaseDatum moet twee woorden zijn: Releasedatum.

Filmtoepassing geopend in Chrome

De gegenereerde code bijwerken

Open het Models/Movie.cs bestand en voeg de gemarkeerde regels toe die worden weergegeven in de volgende code:

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

In de vorige code:

  • Met de [Column(TypeName = "decimal(18, 2)")] gegevensaantekening kan Entity Framework Core Price correct toewijzen aan valuta in de database. Zie gegevenstypenvoor meer informatie.
  • Het kenmerk [Weergave] geeft de weergavenaam van een veld op. In de voorgaande code, 'ReleaseDatum' in plaats van 'ReleaseDate'.
  • Het kenmerk [DataType] geeft het type van de gegevens (Date). De tijdgegevens die in het veld zijn opgeslagen, worden niet weergegeven.

DataAnnotations wordt behandeld in de volgende zelfstudie.

Blader naar Pagina's/Films en beweeg de muisaanwijzer over een koppeling Bewerken om de doel-URL te bekijken.

Een browservenster wordt weergegeven waarin de muis boven de koppeling Bewerken zweeft en een koppelings-URL https://localhost:1234/Movies/Edit/5 wordt getoond

De koppelingen Bewerken, Details en Verwijderen worden gegenereerd door de Anchor Tag Helper in het Pages/Movies/Index.cshtml bestand.

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

Tag Helpers zorgen ervoor dat code aan de serverzijde kan deelnemen aan het maken en weergeven van HTML-elementen in Razor bestanden.

In de voorgaande code genereert de Anchor Tag Helper dynamisch de HTML-kenmerkwaarde href van de Razor pagina (de route is relatief), de asp-pageen de route-id (asp-route-id). Zie URL-generatie voor pagina's voor meer informatie.

Gebruik De weergavebron vanuit een browser om de gegenereerde markeringen te onderzoeken. Hieronder ziet u een deel van de gegenereerde HTML:

<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 dynamisch gegenereerde koppelingen geven de film-id door aan een queryreeks. Bijvoorbeeld de ?id=1 in https://localhost:5001/Movies/Details?id=1.

Routesjabloon toevoegen

Pas de pagina's Bewerken, Details en Verwijderen Razor aan om de {id:int} routesjabloon te gebruiken. Wijzig de pagina-instructie voor elk van deze pagina's van @page in @page "{id:int}". Voer de app uit en bekijk vervolgens de bron.

De gegenereerde HTML voegt de ID toe aan het padgedeelte van de URL.

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

Een aanvraag naar de pagina met de {id:int} routesjabloon die niet het gehele getal bevat, retourneert een HTTP 404-fout (niet gevonden). Retourneert bijvoorbeeld https://localhost:5001/Movies/Details een 404-fout. Als u de id optioneel wilt maken, voegt u deze toe aan ? de routebeperking:

@page "{id:int?}"

Test het gedrag van @page "{id:int?}":

  1. Stel de pagina-richtlijn in Pages/Movies/Details.cshtml op @page "{id:int?}".
  2. Stel een onderbrekingspunt in public async Task<IActionResult> OnGetAsync(int? id), in Pages/Movies/Details.cshtml.cs.
  3. Navigeer naar https://localhost:5001/Movies/Details/.

Met de @page "{id:int}" richtlijn wordt het onderbrekingspunt nooit bereikt. De routeringsengine retourneert HTTP 404. @page "{id:int?}" De OnGetAsyncmethode retourneert 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();
}

Afhandeling van gelijktijdigheidsonderzondering controleren

Controleer de OnPostAsync methode in het Pages/Movies/Edit.cshtml.cs bestand:

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

Met de vorige code worden gelijktijdigheidsonderingen gedetecteerd wanneer de ene client de film verwijdert en de andere client wijzigingen in de film plaatst.

Het catch-blok testen:

  1. Stel een onderbrekingspunt in op catch (DbUpdateConcurrencyException).
  2. Selecteer Bewerken voor een film, breng wijzigingen aan, maar voer Opslaan niet in.
  3. Selecteer in een ander browservenster de koppeling Verwijderen voor dezelfde film en verwijder de film.
  4. In het vorige browservenster plaatst u wijzigingen in de film.

Productiecode zou gelijktijdigheidsconflicten kunnen detecteren. Raadpleeg Gelijktijdigheidsconflicten afhandelen voor meer informatie.

Boekings- en bindingsbeoordeling

Bekijk het Pages/Movies/Edit.cshtml.cs bestand:

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

Wanneer een HTTP GET-aanvraag wordt ingediend op de pagina Films/Bewerken, https://localhost:5001/Movies/Edit/3bijvoorbeeld:

  • De OnGetAsync methode haalt de film op uit de database en retourneert de Page methode.
  • De Page methode geeft de Pages/Movies/Edit.cshtmlRazor pagina weer. Het Pages/Movies/Edit.cshtml bestand bevat de modelrichtlijn @model RazorPagesMovie.Pages.Movies.EditModel, waardoor het filmmodel beschikbaar is op de pagina.
  • Het formulier Bewerken wordt weergegeven met de waarden uit de film.

Wanneer de pagina Films/Bewerken wordt geplaatst:

  • De formulierwaarden op de pagina zijn gebonden aan de Movie eigenschap. Het [BindProperty] kenmerk maakt modelbinding mogelijk.

    [BindProperty]
    public Movie Movie { get; set; }
    
  • Als er fouten zijn in de modelstatus, bijvoorbeeld, ReleaseDate kan niet worden omgezet in een datum, wordt het formulier opnieuw weergegeven met de ingediende waarden.

  • Als er geen modelfouten zijn, wordt de film opgeslagen.

De HTTP GET-methoden in de pagina's Index, Maken en Verwijderen Razor volgen een vergelijkbaar patroon. De HTTP POST-methode OnPostAsync in de create Razor page volgt een vergelijkbaar patroon als de OnPostAsync methode in de bewerkingspagina Razor .

Volgende stappen