Parte 5, aggiornare le pagine generate in un'app ASP.NET Core
Nota
Questa non è la versione più recente di questo articolo. Per la versione corrente, vedere la versione .NET 9 di questo articolo.
Avviso
Questa versione di ASP.NET Core non è più supportata. Per altre informazioni, vedere i criteri di supporto di .NET e .NET Core. Per la versione corrente, vedere la versione .NET 9 di questo articolo.
Importante
Queste informazioni si riferiscono a un prodotto non definitive che può essere modificato in modo sostanziale prima che venga rilasciato commercialmente. Microsoft non riconosce alcuna garanzia, espressa o implicita, in merito alle informazioni qui fornite.
Per la versione corrente, vedere la versione .NET 9 di questo articolo.
Le operazioni iniziali con l'app per i film creata con scaffolding sono state efficaci, ma la presentazione non è ottimale. ReleaseDate deve essere di due parole, data di rilascio.
Aggiornare il modello
Eseguire l'aggiornamento Models/Movie.cs
con il codice evidenziato seguente:
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; }
}
Nel codice precedente:
- L'annotazione dei dati
[Column(TypeName = "decimal(18, 2)")]
consente a Entity Framework Core di eseguire correttamente il mapping diPrice
nella valuta del database. Per altre informazioni, vedere Tipi di dati. - L'attributo [Display] specifica il nome visualizzato di un campo. Nel codice precedente,
Release Date
anzichéReleaseDate
. - L'attributo [DataType] specifica il tipo dei dati (
Date
). Le informazioni sull'ora archiviate nel campo non vengono visualizzate.
L'attributo DataAnnotations viene esaminato nell'esercitazione successiva.
Passare a Pagine/Film e passare il puntatore del mouse su un collegamento Modifica per visualizzare l'URL di destinazione.
I collegamenti Modifica, Dettagli ed Elimina vengono generati dall'helper tag di ancoraggio nel Pages/Movies/Index.cshtml
file.
@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>
Gli helper tag consentono al codice lato server di partecipare alla creazione e al rendering di elementi HTML nei file Razor.
Nel codice precedente, l'helper tag di ancoraggio genera dinamicamente il valore dell'attributo HTML href
dalla Razor pagina (la route è relativa), l'identificatore asp-page
e l'identificatore di route (asp-route-id
). Per altre informazioni, vedere Generazione di URL per Le pagine.
Usare Visualizza origine da un browser per esaminare il markup generato. Di seguito è riportata una parte del codice HTML generato:
<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>
I collegamenti generati dinamicamente passano l'ID filmato con una stringa di query. Ad esempio, in ?id=1
https://localhost:5001/Movies/Details?id=1
.
Aggiungere un modello di route
Aggiornare le pagine Modifica, Dettagli ed Elimina Razor per usare il {id:int}
modello di route. Modificare la direttiva page per ognuna di queste pagine da @page
a @page "{id:int}"
. Eseguire l'app e quindi visualizzare l'origine.
Il codice HTML generato aggiunge l'ID alla parte di percorso dell'URL:
<td>
<a href="/Movies/Edit/1">Edit</a> |
<a href="/Movies/Details/1">Details</a> |
<a href="/Movies/Delete/1">Delete</a>
</td>
Una richiesta alla pagina con il {id:int}
modello di route che non include l'intero restituisce un errore HTTP 404 (non trovato). Ad esempio, https://localhost:5001/Movies/Details
restituisce un errore 404. Per rendere l'ID facoltativo, aggiungere ?
al vincolo di route:
@page "{id:int?}"
Testare il comportamento di @page "{id:int?}"
:
- Impostare la direttiva page in su
Pages/Movies/Details.cshtml
@page "{id:int?}"
. - Impostare un punto di interruzione in
public async Task<IActionResult> OnGetAsync(int? id)
, inPages/Movies/Details.cshtml.cs
. - Accedere a
https://localhost:5001/Movies/Details/
.
Con l'istruzione @page "{id:int}"
, il punto di interruzione non viene mai raggiunto. Il motore di routing restituisce HTTP 404. Usando @page "{id:int?}"
, il OnGetAsync
metodo restituisce 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();
}
Verificare la gestione delle eccezioni di concorrenza
Esaminare il OnPostAsync
metodo nel Pages/Movies/Edit.cshtml.cs
file:
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);
}
Il codice precedente rileva eccezioni di concorrenza quando un client elimina il filmato e l'altro client pubblica modifiche al film.
Per testare il blocco catch
:
- Impostare un punto di interruzione su
catch (DbUpdateConcurrencyException)
. - Selezionare Edit (Modifica) per un film, apportare modifiche, ma non immettere Save (Salva).
- In un'altra finestra del browser, selezionare il collegamento Delete (Elimina) per lo stesso film e quindi eliminare il film.
- Nella finestra del browser precedente inviare le modifiche al film.
In alcuni casi, il codice utilizzabile in ambienti di produzione potrebbe voler rilevare i conflitti di concorrenza. Per altre informazioni, vedere Gestire i conflitti di concorrenza.
Invio di post e analisi delle associazioni
Esaminare il Pages/Movies/Edit.cshtml.cs
file:
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);
}
Quando viene effettuata una richiesta HTTP GET alla pagina Film/Modifica, ad esempio : https://localhost:5001/Movies/Edit/3
- Il metodo
OnGetAsync
recupera il film dal database e restituisce il metodoPage
. - Il
Page
metodo esegue il rendering diPages/Movies/Edit.cshtml
Razor Page. IlPages/Movies/Edit.cshtml
file contiene la direttiva@model RazorPagesMovie.Pages.Movies.EditModel
model , che rende disponibile il modello di film nella pagina. - Il modulo Edit (Modifica) viene visualizzato con i valori dal film.
Quando viene inviata la pagina Movies/Edit (Film/Modifica):
I valori del modulo nella pagina vengono associati alla proprietà
Movie
. L'attributo[BindProperty]
abilita l'associazione di modelli.[BindProperty] public Movie Movie { get; set; }
Se si verificano errori nello stato del modello, ad esempio,
ReleaseDate
non può essere convertito in una data, il modulo viene riprodotto con i valori inviati.Se non sono presenti errori del modello, il film viene salvato.
I metodi HTTP GET nelle pagine Index, Create e Delete Razor seguono un modello simile. Il metodo HTTP POST OnPostAsync
nella pagina Crea Razor segue un modello simile al OnPostAsync
metodo nella pagina Di modifica Razor .
Passaggi successivi
Le operazioni iniziali con l'app per i film creata con scaffolding sono state efficaci, ma la presentazione non è ottimale. ReleaseDate deve essere di due parole, data di rilascio.
Aggiornare il modello
Eseguire l'aggiornamento Models/Movie.cs
con il codice evidenziato seguente:
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; }
}
Nel codice precedente:
- L'annotazione dei dati
[Column(TypeName = "decimal(18, 2)")]
consente a Entity Framework Core di eseguire correttamente il mapping diPrice
nella valuta del database. Per altre informazioni, vedere Tipi di dati. - L'attributo [Display] specifica il nome visualizzato di un campo. Nel codice precedente,
Release Date
anzichéReleaseDate
. - L'attributo [DataType] specifica il tipo dei dati (
Date
). Le informazioni sull'ora archiviate nel campo non vengono visualizzate.
L'attributo DataAnnotations viene esaminato nell'esercitazione successiva.
Passare a Pagine/Film e passare il puntatore del mouse su un collegamento Modifica per visualizzare l'URL di destinazione.
I collegamenti Modifica, Dettagli ed Elimina vengono generati dall'helper tag di ancoraggio nel Pages/Movies/Index.cshtml
file.
@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>
Gli helper tag consentono al codice lato server di partecipare alla creazione e al rendering di elementi HTML nei file Razor.
Nel codice precedente, l'helper tag di ancoraggio genera dinamicamente il valore dell'attributo HTML href
dalla Razor pagina (la route è relativa), l'identificatore asp-page
e l'identificatore di route (asp-route-id
). Per altre informazioni, vedere Generazione di URL per Le pagine.
Usare Visualizza origine da un browser per esaminare il markup generato. Di seguito è riportata una parte del codice HTML generato:
<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>
I collegamenti generati dinamicamente passano l'ID filmato con una stringa di query. Ad esempio, in ?id=1
https://localhost:5001/Movies/Details?id=1
.
Aggiungere un modello di route
Aggiornare le pagine Modifica, Dettagli ed Elimina Razor per usare il {id:int}
modello di route. Modificare la direttiva page per ognuna di queste pagine da @page
a @page "{id:int}"
. Eseguire l'app e quindi visualizzare l'origine.
Il codice HTML generato aggiunge l'ID alla parte di percorso dell'URL:
<td>
<a href="/Movies/Edit/1">Edit</a> |
<a href="/Movies/Details/1">Details</a> |
<a href="/Movies/Delete/1">Delete</a>
</td>
Una richiesta alla pagina con il {id:int}
modello di route che non include l'intero restituisce un errore HTTP 404 (non trovato). Ad esempio, https://localhost:5001/Movies/Details
restituisce un errore 404. Per rendere l'ID facoltativo, aggiungere ?
al vincolo di route:
@page "{id:int?}"
Testare il comportamento di @page "{id:int?}"
:
- Impostare la direttiva page in su
Pages/Movies/Details.cshtml
@page "{id:int?}"
. - Impostare un punto di interruzione in
public async Task<IActionResult> OnGetAsync(int? id)
, inPages/Movies/Details.cshtml.cs
. - Accedere a
https://localhost:5001/Movies/Details/
.
Con l'istruzione @page "{id:int}"
, il punto di interruzione non viene mai raggiunto. Il motore di routing restituisce HTTP 404. Usando @page "{id:int?}"
, il OnGetAsync
metodo restituisce 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();
}
Verificare la gestione delle eccezioni di concorrenza
Esaminare il OnPostAsync
metodo nel Pages/Movies/Edit.cshtml.cs
file:
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);
}
Il codice precedente rileva eccezioni di concorrenza quando un client elimina il filmato e l'altro client pubblica modifiche al film.
Per testare il blocco catch
:
- Impostare un punto di interruzione su
catch (DbUpdateConcurrencyException)
. - Selezionare Edit (Modifica) per un film, apportare modifiche, ma non immettere Save (Salva).
- In un'altra finestra del browser, selezionare il collegamento Delete (Elimina) per lo stesso film e quindi eliminare il film.
- Nella finestra del browser precedente inviare le modifiche al film.
In alcuni casi, il codice utilizzabile in ambienti di produzione potrebbe voler rilevare i conflitti di concorrenza. Per altre informazioni, vedere Gestire i conflitti di concorrenza.
Invio di post e analisi delle associazioni
Esaminare il Pages/Movies/Edit.cshtml.cs
file:
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);
}
Quando viene effettuata una richiesta HTTP GET alla pagina Film/Modifica, ad esempio : https://localhost:5001/Movies/Edit/3
- Il metodo
OnGetAsync
recupera il film dal database e restituisce il metodoPage
. - Il
Page
metodo esegue il rendering diPages/Movies/Edit.cshtml
Razor Page. IlPages/Movies/Edit.cshtml
file contiene la direttiva@model RazorPagesMovie.Pages.Movies.EditModel
model , che rende disponibile il modello di film nella pagina. - Il modulo Edit (Modifica) viene visualizzato con i valori dal film.
Quando viene inviata la pagina Movies/Edit (Film/Modifica):
I valori del modulo nella pagina vengono associati alla proprietà
Movie
. L'attributo[BindProperty]
abilita l'associazione di modelli.[BindProperty] public Movie Movie { get; set; }
Se si verificano errori nello stato del modello, ad esempio,
ReleaseDate
non può essere convertito in una data, il modulo viene riprodotto con i valori inviati.Se non sono presenti errori del modello, il film viene salvato.
I metodi HTTP GET nelle pagine Index, Create e Delete Razor seguono un modello simile. Il metodo HTTP POST OnPostAsync
nella pagina Crea Razor segue un modello simile al OnPostAsync
metodo nella pagina Di modifica Razor .
Passaggi successivi
Le operazioni iniziali con l'app per i film creata con scaffolding sono state efficaci, ma la presentazione non è ottimale. ReleaseDate deve essere di due parole, data di rilascio.
Aggiornare il modello
Eseguire l'aggiornamento Models/Movie.cs
con il codice evidenziato seguente:
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; }
}
Nel codice precedente:
- L'annotazione dei dati
[Column(TypeName = "decimal(18, 2)")]
consente a Entity Framework Core di eseguire correttamente il mapping diPrice
nella valuta del database. Per altre informazioni, vedere Tipi di dati. - L'attributo [Display] specifica il nome visualizzato di un campo. Nel codice precedente,
Release Date
anzichéReleaseDate
. - L'attributo [DataType] specifica il tipo dei dati (
Date
). Le informazioni sull'ora archiviate nel campo non vengono visualizzate.
L'attributo DataAnnotations viene esaminato nell'esercitazione successiva.
Passare a Pagine/Film e passare il puntatore del mouse su un collegamento Modifica per visualizzare l'URL di destinazione.
I collegamenti Modifica, Dettagli ed Elimina vengono generati dall'helper tag di ancoraggio nel Pages/Movies/Index.cshtml
file.
@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>
Gli helper tag consentono al codice lato server di partecipare alla creazione e al rendering di elementi HTML nei file Razor.
Nel codice precedente, l'helper tag di ancoraggio genera dinamicamente il valore dell'attributo HTML href
dalla Razor pagina (la route è relativa), l'identificatore asp-page
e l'identificatore di route (asp-route-id
). Per altre informazioni, vedere Generazione di URL per Le pagine.
Usare Visualizza origine da un browser per esaminare il markup generato. Di seguito è riportata una parte del codice HTML generato:
<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>
I collegamenti generati dinamicamente passano l'ID filmato con una stringa di query. Ad esempio, in ?id=1
https://localhost:5001/Movies/Details?id=1
.
Aggiungere un modello di route
Aggiornare le pagine Modifica, Dettagli ed Elimina Razor per usare il {id:int}
modello di route. Modificare la direttiva page per ognuna di queste pagine da @page
a @page "{id:int}"
. Eseguire l'app e quindi visualizzare l'origine.
Il codice HTML generato aggiunge l'ID alla parte di percorso dell'URL:
<td>
<a href="/Movies/Edit/1">Edit</a> |
<a href="/Movies/Details/1">Details</a> |
<a href="/Movies/Delete/1">Delete</a>
</td>
Una richiesta alla pagina con il {id:int}
modello di route che non include l'intero restituisce un errore HTTP 404 (non trovato). Ad esempio, https://localhost:5001/Movies/Details
restituisce un errore 404. Per rendere l'ID facoltativo, aggiungere ?
al vincolo di route:
@page "{id:int?}"
Testare il comportamento di @page "{id:int?}"
:
- Impostare la direttiva page in su
Pages/Movies/Details.cshtml
@page "{id:int?}"
. - Impostare un punto di interruzione in
public async Task<IActionResult> OnGetAsync(int? id)
, inPages/Movies/Details.cshtml.cs
. - Accedere a
https://localhost:5001/Movies/Details/
.
Con l'istruzione @page "{id:int}"
, il punto di interruzione non viene mai raggiunto. Il motore di routing restituisce HTTP 404. Usando @page "{id:int?}"
, il OnGetAsync
metodo restituisce 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();
}
Verificare la gestione delle eccezioni di concorrenza
Esaminare il OnPostAsync
metodo nel Pages/Movies/Edit.cshtml.cs
file:
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);
}
Il codice precedente rileva eccezioni di concorrenza quando un client elimina il filmato e l'altro client pubblica modifiche al film.
Per testare il blocco catch
:
- Impostare un punto di interruzione su
catch (DbUpdateConcurrencyException)
. - Selezionare Edit (Modifica) per un film, apportare modifiche, ma non immettere Save (Salva).
- In un'altra finestra del browser, selezionare il collegamento Delete (Elimina) per lo stesso film e quindi eliminare il film.
- Nella finestra del browser precedente inviare le modifiche al film.
In alcuni casi, il codice utilizzabile in ambienti di produzione potrebbe voler rilevare i conflitti di concorrenza. Per altre informazioni, vedere Gestire i conflitti di concorrenza.
Invio di post e analisi delle associazioni
Esaminare il Pages/Movies/Edit.cshtml.cs
file:
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);
}
Quando viene effettuata una richiesta HTTP GET alla pagina Film/Modifica, ad esempio : https://localhost:5001/Movies/Edit/3
- Il metodo
OnGetAsync
recupera il film dal database e restituisce il metodoPage
. - Il
Page
metodo esegue il rendering diPages/Movies/Edit.cshtml
Razor Page. IlPages/Movies/Edit.cshtml
file contiene la direttiva@model RazorPagesMovie.Pages.Movies.EditModel
model , che rende disponibile il modello di film nella pagina. - Il modulo Edit (Modifica) viene visualizzato con i valori dal film.
Quando viene inviata la pagina Movies/Edit (Film/Modifica):
I valori del modulo nella pagina vengono associati alla proprietà
Movie
. L'attributo[BindProperty]
abilita l'associazione di modelli.[BindProperty] public Movie Movie { get; set; }
Se si verificano errori nello stato del modello, ad esempio,
ReleaseDate
non può essere convertito in una data, il modulo viene riprodotto con i valori inviati.Se non sono presenti errori del modello, il film viene salvato.
I metodi HTTP GET nelle pagine Index, Create e Delete Razor seguono un modello simile. Il metodo HTTP POST OnPostAsync
nella pagina Crea Razor segue un modello simile al OnPostAsync
metodo nella pagina Di modifica Razor .
Passaggi successivi
Le operazioni iniziali con l'app per i film creata con scaffolding sono state efficaci, ma la presentazione non è ottimale. ReleaseDate deve essere di due parole, data di rilascio.
Aggiornare il codice generato
Eseguire l'aggiornamento Models/Movie.cs
con il codice evidenziato seguente:
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; }
}
}
Nel codice precedente:
- L'annotazione dei dati
[Column(TypeName = "decimal(18, 2)")]
consente a Entity Framework Core di eseguire correttamente il mapping diPrice
nella valuta del database. Per altre informazioni, vedere Tipi di dati. - L'attributo [Display] specifica il nome visualizzato di un campo. Nel codice precedente" "Data di rilascio" anziché "ReleaseDate".
- L'attributo [DataType] specifica il tipo dei dati (
Date
). Le informazioni sull'ora archiviate nel campo non vengono visualizzate.
L'attributo DataAnnotations viene esaminato nell'esercitazione successiva.
Passare a Pagine/Film e passare il puntatore del mouse su un collegamento Modifica per visualizzare l'URL di destinazione.
I collegamenti Modifica, Dettagli ed Elimina vengono generati dall'helper tag di ancoraggio nel Pages/Movies/Index.cshtml
file.
@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>
Gli helper tag consentono al codice lato server di partecipare alla creazione e al rendering di elementi HTML nei file Razor.
Nel codice precedente, l'helper tag di ancoraggio genera dinamicamente il valore dell'attributo HTML href
dalla Razor pagina (la route è relativa), l'identificatore asp-page
e l'identificatore di route (asp-route-id
). Per altre informazioni, vedere Generazione di URL per Le pagine.
Usare Visualizza origine da un browser per esaminare il markup generato. Di seguito è riportata una parte del codice HTML generato:
<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>
I collegamenti generati dinamicamente passano l'ID filmato con una stringa di query. Ad esempio, in ?id=1
https://localhost:5001/Movies/Details?id=1
.
Aggiungere un modello di route
Aggiornare le pagine Modifica, Dettagli ed Elimina Razor per usare il {id:int}
modello di route. Modificare la direttiva page per ognuna di queste pagine da @page
a @page "{id:int}"
. Eseguire l'app e quindi visualizzare l'origine.
Il codice HTML generato aggiunge l'ID alla parte di percorso dell'URL:
<td>
<a href="/Movies/Edit/1">Edit</a> |
<a href="/Movies/Details/1">Details</a> |
<a href="/Movies/Delete/1">Delete</a>
</td>
Una richiesta alla pagina con il {id:int}
modello di route che non include l'intero restituirà un errore HTTP 404 (non trovato). Ad esempio, https://localhost:5001/Movies/Details
restituirà un errore 404. Per rendere l'ID facoltativo, aggiungere ?
al vincolo di route:
@page "{id:int?}"
Testare il comportamento di @page "{id:int?}"
:
- Impostare la direttiva page in su
Pages/Movies/Details.cshtml
@page "{id:int?}"
. - Impostare un punto di interruzione in
public async Task<IActionResult> OnGetAsync(int? id)
, inPages/Movies/Details.cshtml.cs
. - Accedere a
https://localhost:5001/Movies/Details/
.
Con l'istruzione @page "{id:int}"
, il punto di interruzione non viene mai raggiunto. Il motore di routing restituisce HTTP 404. Usando @page "{id:int?}"
, il OnGetAsync
metodo restituisce 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();
}
Verificare la gestione delle eccezioni di concorrenza
Esaminare il OnPostAsync
metodo nel Pages/Movies/Edit.cshtml.cs
file:
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();
}
Il codice precedente rileva eccezioni di concorrenza quando un client elimina il filmato e l'altro client pubblica modifiche al film. Il codice precedente non rileva conflitti che si verificano a causa di due o più client che modificano lo stesso film contemporaneamente. In questo caso, le modifiche apportate da più client vengono applicate nell'ordine SaveChanges
chiamato e le modifiche applicate in un secondo momento possono sovrascrivere le modifiche precedenti con valori non aggiornati.
Per testare il blocco catch
:
- Impostare un punto di interruzione su
catch (DbUpdateConcurrencyException)
. - Selezionare Edit (Modifica) per un film, apportare modifiche, ma non immettere Save (Salva).
- In un'altra finestra del browser, selezionare il collegamento Delete (Elimina) per lo stesso film e quindi eliminare il film.
- Nella finestra del browser precedente inviare le modifiche al film.
Il codice di produzione può voler rilevare conflitti di concorrenza aggiuntivi, ad esempio più client che modificano un'entità contemporaneamente. Per altre informazioni, vedere Gestire i conflitti di concorrenza.
Invio di post e analisi delle associazioni
Esaminare il Pages/Movies/Edit.cshtml.cs
file:
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();
}
Quando viene effettuata una richiesta HTTP GET alla pagina Film/Modifica, ad esempio : https://localhost:5001/Movies/Edit/3
- Il metodo
OnGetAsync
recupera il film dal database e restituisce il metodoPage
. - Il
Page
metodo esegue il rendering diPages/Movies/Edit.cshtml
Razor Page. IlPages/Movies/Edit.cshtml
file contiene la direttiva@model RazorPagesMovie.Pages.Movies.EditModel
model , che rende disponibile il modello di film nella pagina. - Il modulo Edit (Modifica) viene visualizzato con i valori dal film.
Quando viene inviata la pagina Movies/Edit (Film/Modifica):
I valori del modulo nella pagina vengono associati alla proprietà
Movie
. L'attributo[BindProperty]
abilita l'associazione di modelli.[BindProperty] public Movie Movie { get; set; }
Se si verificano errori nello stato del modello, ad esempio,
ReleaseDate
non può essere convertito in una data, il modulo viene riprodotto con i valori inviati.Se non sono presenti errori del modello, il film viene salvato.
I metodi HTTP GET nelle pagine Index, Create e Delete Razor seguono un modello simile. Il metodo HTTP POST OnPostAsync
nella pagina Crea Razor segue un modello simile al OnPostAsync
metodo nella pagina Di modifica Razor .
Passaggi successivi
Le operazioni iniziali con l'app per i film creata con scaffolding sono state efficaci, ma la presentazione non è ottimale. ReleaseDate deve essere di due parole, data di rilascio.
Aggiornare il codice generato
Aprire il Models/Movie.cs
file e aggiungere le righe evidenziate illustrate nel codice seguente:
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; }
}
}
Nel codice precedente:
- L'annotazione dei dati
[Column(TypeName = "decimal(18, 2)")]
consente a Entity Framework Core di eseguire correttamente il mapping diPrice
nella valuta del database. Per altre informazioni, vedere Tipi di dati. - L'attributo [Display] specifica il nome visualizzato di un campo. Nel codice precedente" "Data di rilascio" anziché "ReleaseDate".
- L'attributo [DataType] specifica il tipo dei dati (
Date
). Le informazioni sull'ora archiviate nel campo non vengono visualizzate.
L'attributo DataAnnotations viene esaminato nell'esercitazione successiva.
Passare a Pagine/Film e passare il puntatore del mouse su un collegamento Modifica per visualizzare l'URL di destinazione.
I collegamenti Modifica, Dettagli ed Elimina vengono generati dall'helper tag di ancoraggio nel Pages/Movies/Index.cshtml
file.
@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>
Gli helper tag consentono al codice lato server di partecipare alla creazione e al rendering di elementi HTML nei file Razor.
Nel codice precedente, l'helper tag di ancoraggio genera dinamicamente il valore dell'attributo HTML href
dalla Razor pagina (la route è relativa), l'identificatore asp-page
e l'identificatore di route (asp-route-id
). Per altre informazioni, vedere Generazione di URL per Le pagine.
Usare Visualizza origine da un browser per esaminare il markup generato. Di seguito è riportata una parte del codice HTML generato:
<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>
I collegamenti generati dinamicamente passano l'ID filmato con una stringa di query. Ad esempio, in ?id=1
https://localhost:5001/Movies/Details?id=1
.
Aggiungere un modello di route
Aggiornare le pagine Modifica, Dettagli ed Elimina Razor per usare il {id:int}
modello di route. Modificare la direttiva page per ognuna di queste pagine da @page
a @page "{id:int}"
. Eseguire l'app e quindi visualizzare l'origine.
Il codice HTML generato aggiunge l'ID alla parte di percorso dell'URL:
<td>
<a href="/Movies/Edit/1">Edit</a> |
<a href="/Movies/Details/1">Details</a> |
<a href="/Movies/Delete/1">Delete</a>
</td>
Una richiesta alla pagina con il {id:int}
modello di route che non include l'intero restituirà un errore HTTP 404 (non trovato). Ad esempio, https://localhost:5001/Movies/Details
restituirà un errore 404. Per rendere l'ID facoltativo, aggiungere ?
al vincolo di route:
@page "{id:int?}"
Testare il comportamento di @page "{id:int?}"
:
- Impostare la direttiva page in su
Pages/Movies/Details.cshtml
@page "{id:int?}"
. - Impostare un punto di interruzione in
public async Task<IActionResult> OnGetAsync(int? id)
, inPages/Movies/Details.cshtml.cs
. - Accedere a
https://localhost:5001/Movies/Details/
.
Con l'istruzione @page "{id:int}"
, il punto di interruzione non viene mai raggiunto. Il motore di routing restituisce HTTP 404. Usando @page "{id:int?}"
, il OnGetAsync
metodo restituisce 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();
}
Verificare la gestione delle eccezioni di concorrenza
Esaminare il OnPostAsync
metodo nel Pages/Movies/Edit.cshtml.cs
file:
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);
}
Il codice precedente rileva eccezioni di concorrenza quando un client elimina il filmato e l'altro client pubblica modifiche al film.
Per testare il blocco catch
:
- Impostare un punto di interruzione su
catch (DbUpdateConcurrencyException)
. - Selezionare Edit (Modifica) per un film, apportare modifiche, ma non immettere Save (Salva).
- In un'altra finestra del browser, selezionare il collegamento Delete (Elimina) per lo stesso film e quindi eliminare il film.
- Nella finestra del browser precedente inviare le modifiche al film.
In alcuni casi, il codice utilizzabile in ambienti di produzione potrebbe voler rilevare i conflitti di concorrenza. Per altre informazioni, vedere Gestire i conflitti di concorrenza.
Invio di post e analisi delle associazioni
Esaminare il Pages/Movies/Edit.cshtml.cs
file:
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);
}
Quando viene effettuata una richiesta HTTP GET alla pagina Film/Modifica, ad esempio : https://localhost:5001/Movies/Edit/3
- Il metodo
OnGetAsync
recupera il film dal database e restituisce il metodoPage
. - Il
Page
metodo esegue il rendering diPages/Movies/Edit.cshtml
Razor Page. IlPages/Movies/Edit.cshtml
file contiene la direttiva@model RazorPagesMovie.Pages.Movies.EditModel
model , che rende disponibile il modello di film nella pagina. - Il modulo Edit (Modifica) viene visualizzato con i valori dal film.
Quando viene inviata la pagina Movies/Edit (Film/Modifica):
I valori del modulo nella pagina vengono associati alla proprietà
Movie
. L'attributo[BindProperty]
abilita l'associazione di modelli.[BindProperty] public Movie Movie { get; set; }
Se si verificano errori nello stato del modello, ad esempio,
ReleaseDate
non può essere convertito in una data, il modulo viene riprodotto con i valori inviati.Se non sono presenti errori del modello, il film viene salvato.
I metodi HTTP GET nelle pagine Index, Create e Delete Razor seguono un modello simile. Il metodo HTTP POST OnPostAsync
nella pagina Crea Razor segue un modello simile al OnPostAsync
metodo nella pagina Di modifica Razor .