Teil 5: Aktualisieren der generierten Seiten in einer ASP.NET Core-App
Hinweis
Dies ist nicht die neueste Version dieses Artikels. Informationen zum aktuellen Release finden Sie in der .NET 8-Version dieses Artikels.
Warnung
Diese Version von ASP.NET Core wird nicht mehr unterstützt. Weitere Informationen finden Sie in der Supportrichtlinie für .NET und .NET Core. Informationen zum aktuellen Release finden Sie in der .NET 8-Version dieses Artikels.
Wichtig
Diese Informationen beziehen sich auf ein Vorabversionsprodukt, das vor der kommerziellen Freigabe möglicherweise noch wesentlichen Änderungen unterliegt. Microsoft gibt keine Garantie, weder ausdrücklich noch impliziert, hinsichtlich der hier bereitgestellten Informationen.
Informationen zum aktuellen Release finden Sie in der .NET 8-Version dieses Artikels.
Für den Anfang ist die mit einem Gerüst erstellte Movie-App schon recht ansprechend, doch es gibt Raum für Verbesserungen. ReleaseDate sollte Release Date lauten (zwei Wörter).
Aktualisieren des Modells
Aktualisieren Sie Models/Movie.cs
mit dem folgenden hervorgehobenen 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; }
}
Im vorherigen Code:
- Mit der Datenanmerkung
[Column(TypeName = "decimal(18, 2)")]
kann Entity Framework CorePrice
ordnungsgemäß einer Währung in der Datenbank zuordnen. Weitere Informationen finden Sie unter Datentypen. - Das Attribut [Display] gibt den Anzeigenamen eines Felds an. Im Code oben ist dies
Release Date
anstelle vonReleaseDate
. - Das Attribut [DataType] gibt den Typ der Daten (
Date
) an. Die im Feld gespeicherten Zeitinformationen werden nicht angezeigt.
Datenanmerkungen werden im nächsten Tutorial behandelt.
Navigieren Sie zu Pages/Movies, und bewegen Sie den Mauszeiger über dem Link Bearbeiten, um die Ziel-URL anzuzeigen.
Die Links Bearbeiten, Details und Löschen werden mithilfe des Hilfsprogramms für Ankertags in der Datei Pages/Movies/Index.cshtml
generiert.
@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>
Taghilfsprogramme ermöglichen serverseitigem Code das Mitwirken am Erstellen und Rendern von HTML-Elementen in Razor-Dateien.
Im vorherige Code generiert das Hilfsprogramm für Ankertags dynamisch den Wert des HTML-Attributs href
auf der Razor Page (die Route ist relativ), das Element asp-page
und die Routen-ID (asp-route-id
). Weitere Informationen finden Sie unter URL-Generierung für Seiten.
Rufen Sie in einem Browser Quelltext anzeigen auf, um das generierte Markup zu untersuchen. Ein Teil des generierten HTML-Codes wird unten gezeigt:
<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>
Die dynamisch generierten Links übergeben die Film-ID mit einer Abfragezeichenfolge. Beispiel: ?id=1
in https://localhost:5001/Movies/Details?id=1
.
Hinzufügen der Routenvorlage
Aktualisieren Sie die Razor Pages „Edit“ (Bearbeiten), „Details“ und „Delete“ (Löschen) so, dass die Routenvorlage {id:int}
verwendet wird. Ändern Sie die „page“-Direktive für jede dieser Seiten aus @page
in @page "{id:int}"
. Führen Sie die App aus, und zeigen Sie dann den Quelltext an.
Der generierte HTML-Code fügt die ID dem Pfadteil der URL hinzu:
<td>
<a href="/Movies/Edit/1">Edit</a> |
<a href="/Movies/Details/1">Details</a> |
<a href="/Movies/Delete/1">Delete</a>
</td>
Eine Anforderung an die Seite mit der Routenvorlage {id:int}
, die nicht den Integer enthält, gibt den HTTP-Fehler 404 (Nicht gefunden) zurück. https://localhost:5001/Movies/Details
gibt beispielsweise den Fehler 404 zurück. Um die ID optional zu machen, fügen Sie ?
an die Routeneinschränkung an:
@page "{id:int?}"
Testen Sie das Verhalten von @page "{id:int?}"
:
- Legen Sie die Seitenanweisung in
Pages/Movies/Details.cshtml
auf@page "{id:int?}"
fest. - Legen Sie einen Breakpoint in
public async Task<IActionResult> OnGetAsync(int? id)
(inPages/Movies/Details.cshtml.cs
) fest. - Navigieren Sie zu
https://localhost:5001/Movies/Details/
.
Mit der @page "{id:int}"
-Direktive wird der Haltepunkt nie erreicht. Die Routing-Engine gibt den HTTP-Fehler 404 zurück. Bei Verwendung von @page "{id:int?}"
gibt die OnGetAsync
-Methode NotFound
zurück (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();
}
Überprüfen der Behandlung von Ausnahmen bei Parallelität
Überprüfen Sie die OnPostAsync
-Methode in der Datei Pages/Movies/Edit.cshtml.cs
:
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);
}
Der obige Code erkennt Parallelitätsausnahmen, wenn ein Client den Film löscht und der andere Client Änderungen am Film übermittelt.
So testen Sie den Block catch
- Legen Sie einen Haltepunkt bei
catch (DbUpdateConcurrencyException)
fest. - Wählen Sie Edit für einen Film aus, nehmen Sie Änderungen vor, aber geben Sie nicht Save ein.
- Klicken Sie in einem anderen Browserfenster auf den Link Delete für denselben Film, und löschen Sie dann den Film.
- Übermitteln Sie im vorherigen Browserfenster Änderungen am Film.
Der Produktionscode sollte Nebenläufigkeitskonflikte erkennen. Weitere Informationen finden Sie unter Verarbeiten von Nebenläufigkeitskonflikten.
Überprüfen der Bereitstellung und Bindung
Untersuchen Sie die Datei Pages/Movies/Edit.cshtml.cs
:
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);
}
Wenn eine HTTP GET-Anforderung an die Seite „Movies/Edit“ gerichtet wird (z. B. https://localhost:5001/Movies/Edit/3
):
- Die
OnGetAsync
-Methode ruft den Film aus der Datenbank ab und gibt diePage
-Methode zurück. - Die
Page
-Methode rendert die Razor-SeitePages/Movies/Edit.cshtml
. Die DateiPages/Movies/Edit.cshtml
enthält die Modellanweisung@model RazorPagesMovie.Pages.Movies.EditModel
, die das Filmmodell auf der Seite verfügbar macht. - Das Bearbeitungsformular wird mit den Werten aus dem Film angezeigt.
Wenn die Seite „Filme/Bearbeiten“ bereitgestellt wird:
Die Formularwerte auf der Seite sind an die
Movie
-Eigenschaft gebunden. Das[BindProperty]
-Attribut ermöglicht die Modellbindung.[BindProperty] public Movie Movie { get; set; }
Bei Fehlern beim Modellstatus (Beispiel:
ReleaseDate
kann nicht in ein Datum konvertiert werden) wird das Formular mit den übermittelten Werten erneut angezeigt.Wenn keine Modellfehler vorhanden sind, wird der Film gespeichert.
Die HTTP GET-Methoden auf den Razor Pages „Index“, „Create“ und „Delete“ folgen einem ähnlichen Muster. Die HTTP-POST-Methode OnPostAsync
auf der Razor Page „Create“ folgt einem ähnlichen Muster wie die OnPostAsync
-Methode auf der Razor Page „Edit“.
Nächste Schritte
Für den Anfang ist die mit einem Gerüst erstellte Movie-App schon recht ansprechend, doch es gibt Raum für Verbesserungen. ReleaseDate sollte Release Date lauten (zwei Wörter).
Aktualisieren des Modells
Aktualisieren Sie Models/Movie.cs
mit dem folgenden hervorgehobenen 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; }
}
Im vorherigen Code:
- Mit der Datenanmerkung
[Column(TypeName = "decimal(18, 2)")]
kann Entity Framework CorePrice
ordnungsgemäß einer Währung in der Datenbank zuordnen. Weitere Informationen finden Sie unter Datentypen. - Das Attribut [Display] gibt den Anzeigenamen eines Felds an. Im Code oben ist dies
Release Date
anstelle vonReleaseDate
. - Das Attribut [DataType] gibt den Typ der Daten (
Date
) an. Die im Feld gespeicherten Zeitinformationen werden nicht angezeigt.
Datenanmerkungen werden im nächsten Tutorial behandelt.
Navigieren Sie zu Pages/Movies, und bewegen Sie den Mauszeiger über dem Link Bearbeiten, um die Ziel-URL anzuzeigen.
Die Links Bearbeiten, Details und Löschen werden mithilfe des Hilfsprogramms für Ankertags in der Datei Pages/Movies/Index.cshtml
generiert.
@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>
Taghilfsprogramme ermöglichen serverseitigem Code das Mitwirken am Erstellen und Rendern von HTML-Elementen in Razor-Dateien.
Im vorherige Code generiert das Hilfsprogramm für Ankertags dynamisch den Wert des HTML-Attributs href
auf der Razor Page (die Route ist relativ), das Element asp-page
und die Routen-ID (asp-route-id
). Weitere Informationen finden Sie unter URL-Generierung für Seiten.
Rufen Sie in einem Browser Quelltext anzeigen auf, um das generierte Markup zu untersuchen. Ein Teil des generierten HTML-Codes wird unten gezeigt:
<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>
Die dynamisch generierten Links übergeben die Film-ID mit einer Abfragezeichenfolge. Beispiel: ?id=1
in https://localhost:5001/Movies/Details?id=1
.
Hinzufügen der Routenvorlage
Aktualisieren Sie die Razor Pages „Edit“ (Bearbeiten), „Details“ und „Delete“ (Löschen) so, dass die Routenvorlage {id:int}
verwendet wird. Ändern Sie die „page“-Direktive für jede dieser Seiten aus @page
in @page "{id:int}"
. Führen Sie die App aus, und zeigen Sie dann den Quelltext an.
Der generierte HTML-Code fügt die ID dem Pfadteil der URL hinzu:
<td>
<a href="/Movies/Edit/1">Edit</a> |
<a href="/Movies/Details/1">Details</a> |
<a href="/Movies/Delete/1">Delete</a>
</td>
Eine Anforderung an die Seite mit der Routenvorlage {id:int}
, die nicht den Integer enthält, gibt den HTTP-Fehler 404 (Nicht gefunden) zurück. https://localhost:5001/Movies/Details
gibt beispielsweise den Fehler 404 zurück. Um die ID optional zu machen, fügen Sie ?
an die Routeneinschränkung an:
@page "{id:int?}"
Testen Sie das Verhalten von @page "{id:int?}"
:
- Legen Sie die Seitenanweisung in
Pages/Movies/Details.cshtml
auf@page "{id:int?}"
fest. - Legen Sie einen Breakpoint in
public async Task<IActionResult> OnGetAsync(int? id)
(inPages/Movies/Details.cshtml.cs
) fest. - Navigieren Sie zu
https://localhost:5001/Movies/Details/
.
Mit der @page "{id:int}"
-Direktive wird der Haltepunkt nie erreicht. Die Routing-Engine gibt den HTTP-Fehler 404 zurück. Bei Verwendung von @page "{id:int?}"
gibt die OnGetAsync
-Methode NotFound
zurück (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();
}
Überprüfen der Behandlung von Ausnahmen bei Parallelität
Überprüfen Sie die OnPostAsync
-Methode in der Datei Pages/Movies/Edit.cshtml.cs
:
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);
}
Der obige Code erkennt Parallelitätsausnahmen, wenn ein Client den Film löscht und der andere Client Änderungen am Film übermittelt.
So testen Sie den Block catch
- Legen Sie einen Haltepunkt bei
catch (DbUpdateConcurrencyException)
fest. - Wählen Sie Edit für einen Film aus, nehmen Sie Änderungen vor, aber geben Sie nicht Save ein.
- Klicken Sie in einem anderen Browserfenster auf den Link Delete für denselben Film, und löschen Sie dann den Film.
- Übermitteln Sie im vorherigen Browserfenster Änderungen am Film.
Der Produktionscode sollte Nebenläufigkeitskonflikte erkennen. Weitere Informationen finden Sie unter Verarbeiten von Nebenläufigkeitskonflikten.
Überprüfen der Bereitstellung und Bindung
Untersuchen Sie die Datei Pages/Movies/Edit.cshtml.cs
:
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);
}
Wenn eine HTTP GET-Anforderung an die Seite „Movies/Edit“ gerichtet wird (z. B. https://localhost:5001/Movies/Edit/3
):
- Die
OnGetAsync
-Methode ruft den Film aus der Datenbank ab und gibt diePage
-Methode zurück. - Die
Page
-Methode rendert die Razor-SeitePages/Movies/Edit.cshtml
. Die DateiPages/Movies/Edit.cshtml
enthält die Modellanweisung@model RazorPagesMovie.Pages.Movies.EditModel
, die das Filmmodell auf der Seite verfügbar macht. - Das Bearbeitungsformular wird mit den Werten aus dem Film angezeigt.
Wenn die Seite „Filme/Bearbeiten“ bereitgestellt wird:
Die Formularwerte auf der Seite sind an die
Movie
-Eigenschaft gebunden. Das[BindProperty]
-Attribut ermöglicht die Modellbindung.[BindProperty] public Movie Movie { get; set; }
Bei Fehlern beim Modellstatus (Beispiel:
ReleaseDate
kann nicht in ein Datum konvertiert werden) wird das Formular mit den übermittelten Werten erneut angezeigt.Wenn keine Modellfehler vorhanden sind, wird der Film gespeichert.
Die HTTP GET-Methoden auf den Razor Pages „Index“, „Create“ und „Delete“ folgen einem ähnlichen Muster. Die HTTP-POST-Methode OnPostAsync
auf der Razor Page „Create“ folgt einem ähnlichen Muster wie die OnPostAsync
-Methode auf der Razor Page „Edit“.
Nächste Schritte
Für den Anfang ist die mit einem Gerüst erstellte Movie-App schon recht ansprechend, doch es gibt Raum für Verbesserungen. ReleaseDate sollte Release Date lauten (zwei Wörter).
Aktualisieren des Modells
Aktualisieren Sie Models/Movie.cs
mit dem folgenden hervorgehobenen 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; }
}
Im vorherigen Code:
- Mit der Datenanmerkung
[Column(TypeName = "decimal(18, 2)")]
kann Entity Framework CorePrice
ordnungsgemäß einer Währung in der Datenbank zuordnen. Weitere Informationen finden Sie unter Datentypen. - Das Attribut [Display] gibt den Anzeigenamen eines Felds an. Im Code oben ist dies
Release Date
anstelle vonReleaseDate
. - Das Attribut [DataType] gibt den Typ der Daten (
Date
) an. Die im Feld gespeicherten Zeitinformationen werden nicht angezeigt.
Datenanmerkungen werden im nächsten Tutorial behandelt.
Navigieren Sie zu Pages/Movies, und bewegen Sie den Mauszeiger über dem Link Bearbeiten, um die Ziel-URL anzuzeigen.
Die Links Bearbeiten, Details und Löschen werden mithilfe des Hilfsprogramms für Ankertags in der Datei Pages/Movies/Index.cshtml
generiert.
@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>
Taghilfsprogramme ermöglichen serverseitigem Code das Mitwirken am Erstellen und Rendern von HTML-Elementen in Razor-Dateien.
Im vorherige Code generiert das Hilfsprogramm für Ankertags dynamisch den Wert des HTML-Attributs href
auf der Razor Page (die Route ist relativ), das Element asp-page
und die Routen-ID (asp-route-id
). Weitere Informationen finden Sie unter URL-Generierung für Seiten.
Rufen Sie in einem Browser Quelltext anzeigen auf, um das generierte Markup zu untersuchen. Ein Teil des generierten HTML-Codes wird unten gezeigt:
<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>
Die dynamisch generierten Links übergeben die Film-ID mit einer Abfragezeichenfolge. Beispiel: ?id=1
in https://localhost:5001/Movies/Details?id=1
.
Hinzufügen der Routenvorlage
Aktualisieren Sie die Razor Pages „Edit“ (Bearbeiten), „Details“ und „Delete“ (Löschen) so, dass die Routenvorlage {id:int}
verwendet wird. Ändern Sie die „page“-Direktive für jede dieser Seiten aus @page
in @page "{id:int}"
. Führen Sie die App aus, und zeigen Sie dann den Quelltext an.
Der generierte HTML-Code fügt die ID dem Pfadteil der URL hinzu:
<td>
<a href="/Movies/Edit/1">Edit</a> |
<a href="/Movies/Details/1">Details</a> |
<a href="/Movies/Delete/1">Delete</a>
</td>
Eine Anforderung an die Seite mit der Routenvorlage {id:int}
, die nicht den Integer enthält, gibt den HTTP-Fehler 404 (Nicht gefunden) zurück. https://localhost:5001/Movies/Details
gibt beispielsweise den Fehler 404 zurück. Um die ID optional zu machen, fügen Sie ?
an die Routeneinschränkung an:
@page "{id:int?}"
Testen Sie das Verhalten von @page "{id:int?}"
:
- Legen Sie die Seitenanweisung in
Pages/Movies/Details.cshtml
auf@page "{id:int?}"
fest. - Legen Sie einen Breakpoint in
public async Task<IActionResult> OnGetAsync(int? id)
(inPages/Movies/Details.cshtml.cs
) fest. - Navigieren Sie zu
https://localhost:5001/Movies/Details/
.
Mit der @page "{id:int}"
-Direktive wird der Haltepunkt nie erreicht. Die Routing-Engine gibt den HTTP-Fehler 404 zurück. Bei Verwendung von @page "{id:int?}"
gibt die OnGetAsync
-Methode NotFound
zurück (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();
}
Überprüfen der Behandlung von Ausnahmen bei Parallelität
Überprüfen Sie die OnPostAsync
-Methode in der Datei Pages/Movies/Edit.cshtml.cs
:
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);
}
Der obige Code erkennt Parallelitätsausnahmen, wenn ein Client den Film löscht und der andere Client Änderungen am Film übermittelt.
So testen Sie den Block catch
- Legen Sie einen Haltepunkt bei
catch (DbUpdateConcurrencyException)
fest. - Wählen Sie Edit für einen Film aus, nehmen Sie Änderungen vor, aber geben Sie nicht Save ein.
- Klicken Sie in einem anderen Browserfenster auf den Link Delete für denselben Film, und löschen Sie dann den Film.
- Übermitteln Sie im vorherigen Browserfenster Änderungen am Film.
Der Produktionscode sollte Nebenläufigkeitskonflikte erkennen. Weitere Informationen finden Sie unter Verarbeiten von Nebenläufigkeitskonflikten.
Überprüfen der Bereitstellung und Bindung
Untersuchen Sie die Datei Pages/Movies/Edit.cshtml.cs
:
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);
}
Wenn eine HTTP GET-Anforderung an die Seite „Movies/Edit“ gerichtet wird (z. B. https://localhost:5001/Movies/Edit/3
):
- Die
OnGetAsync
-Methode ruft den Film aus der Datenbank ab und gibt diePage
-Methode zurück. - Die
Page
-Methode rendert die Razor-SeitePages/Movies/Edit.cshtml
. Die DateiPages/Movies/Edit.cshtml
enthält die Modellanweisung@model RazorPagesMovie.Pages.Movies.EditModel
, die das Filmmodell auf der Seite verfügbar macht. - Das Bearbeitungsformular wird mit den Werten aus dem Film angezeigt.
Wenn die Seite „Filme/Bearbeiten“ bereitgestellt wird:
Die Formularwerte auf der Seite sind an die
Movie
-Eigenschaft gebunden. Das[BindProperty]
-Attribut ermöglicht die Modellbindung.[BindProperty] public Movie Movie { get; set; }
Bei Fehlern beim Modellstatus (Beispiel:
ReleaseDate
kann nicht in ein Datum konvertiert werden) wird das Formular mit den übermittelten Werten erneut angezeigt.Wenn keine Modellfehler vorhanden sind, wird der Film gespeichert.
Die HTTP GET-Methoden auf den Razor Pages „Index“, „Create“ und „Delete“ folgen einem ähnlichen Muster. Die HTTP-POST-Methode OnPostAsync
auf der Razor Page „Create“ folgt einem ähnlichen Muster wie die OnPostAsync
-Methode auf der Razor Page „Edit“.
Nächste Schritte
Für den Anfang ist die mit einem Gerüst erstellte Movie-App schon recht ansprechend, doch es gibt Raum für Verbesserungen. ReleaseDate sollte Release Date lauten (zwei Wörter).
Aktualisieren des generierten Codes
Aktualisieren Sie Models/Movie.cs
mit dem folgenden hervorgehobenen 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; }
}
}
Im vorherigen Code:
- Mit der Datenanmerkung
[Column(TypeName = "decimal(18, 2)")]
kann Entity Framework CorePrice
ordnungsgemäß einer Währung in der Datenbank zuordnen. Weitere Informationen finden Sie unter Datentypen. - Das Attribut [Display] gibt den Anzeigenamen eines Felds an. Im vorherigen Code „Release Date“ anstelle von ReleaseDate.
- Das Attribut [DataType] gibt den Typ der Daten (
Date
) an. Die im Feld gespeicherten Zeitinformationen werden nicht angezeigt.
Datenanmerkungen werden im nächsten Tutorial behandelt.
Navigieren Sie zu Pages/Movies, und bewegen Sie den Mauszeiger über dem Link Bearbeiten, um die Ziel-URL anzuzeigen.
Die Links Bearbeiten, Details und Löschen werden mithilfe des Hilfsprogramms für Ankertags in der Datei Pages/Movies/Index.cshtml
generiert.
@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>
Taghilfsprogramme ermöglichen serverseitigem Code das Mitwirken am Erstellen und Rendern von HTML-Elementen in Razor-Dateien.
Im vorherige Code generiert das Hilfsprogramm für Ankertags dynamisch den Wert des HTML-Attributs href
auf der Razor Page (die Route ist relativ), das Element asp-page
und die Routen-ID (asp-route-id
). Weitere Informationen finden Sie unter URL-Generierung für Seiten.
Rufen Sie in einem Browser Quelltext anzeigen auf, um das generierte Markup zu untersuchen. Ein Teil des generierten HTML-Codes wird unten gezeigt:
<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>
Die dynamisch generierten Links übergeben die Film-ID mit einer Abfragezeichenfolge. Beispiel: ?id=1
in https://localhost:5001/Movies/Details?id=1
.
Hinzufügen der Routenvorlage
Aktualisieren Sie die Razor Pages „Edit“ (Bearbeiten), „Details“ und „Delete“ (Löschen) so, dass die Routenvorlage {id:int}
verwendet wird. Ändern Sie die „page“-Direktive für jede dieser Seiten aus @page
in @page "{id:int}"
. Führen Sie die App aus, und zeigen Sie dann den Quelltext an.
Der generierte HTML-Code fügt die ID dem Pfadteil der URL hinzu:
<td>
<a href="/Movies/Edit/1">Edit</a> |
<a href="/Movies/Details/1">Details</a> |
<a href="/Movies/Delete/1">Delete</a>
</td>
Eine Anforderung an die Seite mit der Routenvorlage {id:int}
, die nicht die ganze Zahl enthält, gibt den HTTP-Fehler 404 (Nicht gefunden) zurück. https://localhost:5001/Movies/Details
gibt beispielsweise den Fehler 404 zurück. Um die ID optional zu machen, fügen Sie ?
an die Routeneinschränkung an:
@page "{id:int?}"
Testen Sie das Verhalten von @page "{id:int?}"
:
- Legen Sie die Seitenanweisung in
Pages/Movies/Details.cshtml
auf@page "{id:int?}"
fest. - Legen Sie einen Breakpoint in
public async Task<IActionResult> OnGetAsync(int? id)
(inPages/Movies/Details.cshtml.cs
) fest. - Navigieren Sie zu
https://localhost:5001/Movies/Details/
.
Mit der @page "{id:int}"
-Direktive wird der Haltepunkt nie erreicht. Die Routing-Engine gibt den HTTP-Fehler 404 zurück. Bei Verwendung von @page "{id:int?}"
gibt die OnGetAsync
-Methode NotFound
zurück (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();
}
Überprüfen der Behandlung von Ausnahmen bei Parallelität
Überprüfen Sie die OnPostAsync
-Methode in der Datei Pages/Movies/Edit.cshtml.cs
:
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();
}
Der obige Code erkennt Parallelitätsausnahmen, wenn ein Client den Film löscht und der andere Client Änderungen am Film übermittelt. Der vorherige Code erkennt keine Konflikte, die auftreten, wenn zwei oder mehr Clients denselben Film gleichzeitig bearbeiten. In diesem Fall werden Bearbeitungen von mehreren Clients in der Reihenfolge angewandt, in der SaveChanges
aufgerufen wird. Dadurch können später angewandte Bearbeitungen frühere mit veralteten Werten überschreiben.
So testen Sie den Block catch
- Legen Sie einen Haltepunkt bei
catch (DbUpdateConcurrencyException)
fest. - Wählen Sie Edit für einen Film aus, nehmen Sie Änderungen vor, aber geben Sie nicht Save ein.
- Klicken Sie in einem anderen Browserfenster auf den Link Delete für denselben Film, und löschen Sie dann den Film.
- Übermitteln Sie im vorherigen Browserfenster Änderungen am Film.
Mit Produktionscode möchten Sie möglicherweise zusätzliche Nebenläufigkeitskonflikte erkennen, z. B. wenn mehrere Clients eine Entität gleichzeitig bearbeiten. Weitere Informationen finden Sie unter Verarbeiten von Nebenläufigkeitskonflikten.
Überprüfen der Bereitstellung und Bindung
Untersuchen Sie die Datei Pages/Movies/Edit.cshtml.cs
:
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();
}
Wenn eine HTTP GET-Anforderung an die Seite „Movies/Edit“ gerichtet wird (z. B. https://localhost:5001/Movies/Edit/3
):
- Die
OnGetAsync
-Methode ruft den Film aus der Datenbank ab und gibt diePage
-Methode zurück. - Die
Page
-Methode rendert die Razor-SeitePages/Movies/Edit.cshtml
. Die DateiPages/Movies/Edit.cshtml
enthält die Modellanweisung@model RazorPagesMovie.Pages.Movies.EditModel
, die das Filmmodell auf der Seite verfügbar macht. - Das Bearbeitungsformular wird mit den Werten aus dem Film angezeigt.
Wenn die Seite „Filme/Bearbeiten“ bereitgestellt wird:
Die Formularwerte auf der Seite sind an die
Movie
-Eigenschaft gebunden. Das[BindProperty]
-Attribut ermöglicht die Modellbindung.[BindProperty] public Movie Movie { get; set; }
Bei Fehlern beim Modellstatus (Beispiel:
ReleaseDate
kann nicht in ein Datum konvertiert werden) wird das Formular mit den übermittelten Werten erneut angezeigt.Wenn keine Modellfehler vorhanden sind, wird der Film gespeichert.
Die HTTP GET-Methoden auf den Razor Pages „Index“, „Create“ und „Delete“ folgen einem ähnlichen Muster. Die HTTP-POST-Methode OnPostAsync
auf der Razor Page „Create“ folgt einem ähnlichen Muster wie die OnPostAsync
-Methode auf der Razor Page „Edit“.
Nächste Schritte
Für den Anfang ist die mit einem Gerüst erstellte Movie-App schon recht ansprechend, doch es gibt Raum für Verbesserungen. ReleaseDate sollte Release Date lauten (zwei Wörter).
Aktualisieren des generierten Codes
Öffnen Sie die Datei Models/Movie.cs
, und fügen Sie die im folgenden Code gezeigten markierten Zeilen hinzu:
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; }
}
}
Im vorherigen Code:
- Mit der Datenanmerkung
[Column(TypeName = "decimal(18, 2)")]
kann Entity Framework CorePrice
ordnungsgemäß einer Währung in der Datenbank zuordnen. Weitere Informationen finden Sie unter Datentypen. - Das Attribut [Display] gibt den Anzeigenamen eines Felds an. Im vorherigen Code „Release Date“ anstelle von ReleaseDate.
- Das Attribut [DataType] gibt den Typ der Daten (
Date
) an. Die im Feld gespeicherten Zeitinformationen werden nicht angezeigt.
Datenanmerkungen werden im nächsten Tutorial behandelt.
Navigieren Sie zu Pages/Movies, und bewegen Sie den Mauszeiger über dem Link Bearbeiten, um die Ziel-URL anzuzeigen.
Die Links Bearbeiten, Details und Löschen werden mithilfe des Hilfsprogramms für Ankertags in der Datei Pages/Movies/Index.cshtml
generiert.
@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>
Taghilfsprogramme ermöglichen serverseitigem Code das Mitwirken am Erstellen und Rendern von HTML-Elementen in Razor-Dateien.
Im vorherige Code generiert das Hilfsprogramm für Ankertags dynamisch den Wert des HTML-Attributs href
auf der Razor Page (die Route ist relativ), das Element asp-page
und die Routen-ID (asp-route-id
). Weitere Informationen finden Sie unter URL-Generierung für Seiten.
Rufen Sie in einem Browser Quelltext anzeigen auf, um das generierte Markup zu untersuchen. Ein Teil des generierten HTML-Codes wird unten gezeigt:
<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>
Die dynamisch generierten Links übergeben die Film-ID mit einer Abfragezeichenfolge. Beispiel: ?id=1
in https://localhost:5001/Movies/Details?id=1
.
Hinzufügen der Routenvorlage
Aktualisieren Sie die Razor Pages „Edit“ (Bearbeiten), „Details“ und „Delete“ (Löschen) so, dass die Routenvorlage {id:int}
verwendet wird. Ändern Sie die „page“-Direktive für jede dieser Seiten aus @page
in @page "{id:int}"
. Führen Sie die App aus, und zeigen Sie dann den Quelltext an.
Der generierte HTML-Code fügt die ID dem Pfadteil der URL hinzu:
<td>
<a href="/Movies/Edit/1">Edit</a> |
<a href="/Movies/Details/1">Details</a> |
<a href="/Movies/Delete/1">Delete</a>
</td>
Eine Anforderung an die Seite mit der Routenvorlage {id:int}
, die nicht die ganze Zahl enthält, gibt den HTTP-Fehler 404 (Nicht gefunden) zurück. https://localhost:5001/Movies/Details
gibt beispielsweise den Fehler 404 zurück. Um die ID optional zu machen, fügen Sie ?
an die Routeneinschränkung an:
@page "{id:int?}"
Testen Sie das Verhalten von @page "{id:int?}"
:
- Legen Sie die Seitenanweisung in
Pages/Movies/Details.cshtml
auf@page "{id:int?}"
fest. - Legen Sie einen Breakpoint in
public async Task<IActionResult> OnGetAsync(int? id)
(inPages/Movies/Details.cshtml.cs
) fest. - Navigieren Sie zu
https://localhost:5001/Movies/Details/
.
Mit der @page "{id:int}"
-Direktive wird der Haltepunkt nie erreicht. Die Routing-Engine gibt den HTTP-Fehler 404 zurück. Bei Verwendung von @page "{id:int?}"
gibt die OnGetAsync
-Methode NotFound
zurück (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();
}
Überprüfen der Behandlung von Ausnahmen bei Parallelität
Überprüfen Sie die OnPostAsync
-Methode in der Datei Pages/Movies/Edit.cshtml.cs
:
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);
}
Der obige Code erkennt Parallelitätsausnahmen, wenn ein Client den Film löscht und der andere Client Änderungen am Film übermittelt.
So testen Sie den Block catch
- Legen Sie einen Haltepunkt bei
catch (DbUpdateConcurrencyException)
fest. - Wählen Sie Edit für einen Film aus, nehmen Sie Änderungen vor, aber geben Sie nicht Save ein.
- Klicken Sie in einem anderen Browserfenster auf den Link Delete für denselben Film, und löschen Sie dann den Film.
- Übermitteln Sie im vorherigen Browserfenster Änderungen am Film.
Der Produktionscode sollte Nebenläufigkeitskonflikte erkennen. Weitere Informationen finden Sie unter Verarbeiten von Nebenläufigkeitskonflikten.
Überprüfen der Bereitstellung und Bindung
Untersuchen Sie die Datei Pages/Movies/Edit.cshtml.cs
:
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);
}
Wenn eine HTTP GET-Anforderung an die Seite „Movies/Edit“ gerichtet wird (z. B. https://localhost:5001/Movies/Edit/3
):
- Die
OnGetAsync
-Methode ruft den Film aus der Datenbank ab und gibt diePage
-Methode zurück. - Die
Page
-Methode rendert die Razor-SeitePages/Movies/Edit.cshtml
. Die DateiPages/Movies/Edit.cshtml
enthält die Modellanweisung@model RazorPagesMovie.Pages.Movies.EditModel
, die das Filmmodell auf der Seite verfügbar macht. - Das Bearbeitungsformular wird mit den Werten aus dem Film angezeigt.
Wenn die Seite „Filme/Bearbeiten“ bereitgestellt wird:
Die Formularwerte auf der Seite sind an die
Movie
-Eigenschaft gebunden. Das[BindProperty]
-Attribut ermöglicht die Modellbindung.[BindProperty] public Movie Movie { get; set; }
Bei Fehlern beim Modellstatus (Beispiel:
ReleaseDate
kann nicht in ein Datum konvertiert werden) wird das Formular mit den übermittelten Werten erneut angezeigt.Wenn keine Modellfehler vorhanden sind, wird der Film gespeichert.
Die HTTP GET-Methoden auf den Razor Pages „Index“, „Create“ und „Delete“ folgen einem ähnlichen Muster. Die HTTP-POST-Methode OnPostAsync
auf der Razor Page „Create“ folgt einem ähnlichen Muster wie die OnPostAsync
-Methode auf der Razor Page „Edit“.
Nächste Schritte
ASP.NET Core