Share via


Parte 6, metodi e visualizzazioni del controller in ASP.NET Core

Nota

Questa non è la versione più recente di questo articolo. Per la versione corrente, vedere la versione .NET 8 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 8 di questo articolo.

Di Rick Anderson

Le operazioni iniziali con l'app per i film sono state efficaci, ma la presentazione non è ottimale, ad esempio ReleaseDate dovrebbe essere scritto come due parole.

Vista Index: Release Date è un'unica parola (senza spazi) e la data di rilascio di ogni film indica l'ora nel formato 12 AM

Aprire il Models/Movie.cs file e aggiungere le righe evidenziate illustrate di seguito:

using System;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;

namespace MvcMovie.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; }
}

DataAnnotations sono spiegate nell'esercitazione successiva. L'attributo Display specifica il testo da visualizzare per il nome di un campo, in questo caso "Release Date" anziché "ReleaseDate". L'attributo DataType specifica il tipo di dati (Date) e quindi non vengono visualizzate le informazioni sull'ora archiviate nel campo.

L'annotazione dei dati [Column(TypeName = "decimal(18, 2)")] è necessaria per consentire a Entity Framework Core di eseguire correttamente il mapping di Price nella valuta del database. Per altre informazioni, vedere Tipi di dati.

Passare al controller Movies e posizionare il puntatore del mouse su un collegamento Edit (Modifica) per visualizzare l'URL di destinazione.

Finestra del browser con il passaggio del mouse sul collegamento Edit (Modifica) e un URL di collegamento di https://localhost:5001/Movies/Edit/5

I collegamenti Modifica, Dettagli ed Elimina vengono generati dall'helper tag di ancoraggio MVC principale nel Views/Movies/Index.cshtml file.

        <a asp-action="Edit" asp-route-id="@item.Id">Edit</a> |
        <a asp-action="Details" asp-route-id="@item.Id">Details</a> |
        <a asp-action="Delete" asp-route-id="@item.Id">Delete</a>
    </td>
</tr>

Gli helper tag consentono al codice lato server di partecipare alla creazione e al rendering di elementi HTML nei file Razor. Nel codice precedente, il valore dell'attributo AnchorTagHelper HTML href viene generato dinamicamente dal metodo di azione del controller e dall'ID di route. Usare Visualizza origine dal browser preferito o usare gli strumenti di sviluppo per esaminare il markup generato. Di seguito è riportata una parte del codice HTML generato:

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

Richiamare il formato per il routing impostato nel Program.cs file:

app.MapControllerRoute(
    name: "default",
    pattern: "{controller=Home}/{action=Index}/{id?}");

ASP.NET Core converte https://localhost:5001/Movies/Edit/4 in una richiesta al metodo di azione Edit del controller Movies con il parametro Id impostato su 4. I metodi del controller sono noti anche come metodi di azione.

Una delle nuove funzionalità più note di ASP.NET Core è rappresentata dagli helper tag. Per altre informazioni, vedere Risorse aggiuntive.

Aprire il controller Movies ed esaminare i due metodi di azione Edit. Il codice seguente illustra il HTTP GET Edit metodo , che recupera il filmato e popola il modulo di modifica generato dal Edit.cshtmlRazor file .

// GET: Movies/Edit/5
public async Task<IActionResult> Edit(int? id)
{
    if (id == null)
    {
        return NotFound();
    }

    var movie = await _context.Movie.FindAsync(id);
    if (movie == null)
    {
        return NotFound();
    }
    return View(movie);
}

Il codice seguente illustra il metodo HTTP POST Edit, che elabora i valori di film inviati:

// POST: Movies/Edit/5
// To protect from overposting attacks, enable the specific properties you want to bind to.
// For more details, see http://go.microsoft.com/fwlink/?LinkId=317598.
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Edit(int id, [Bind("Id,Title,ReleaseDate,Genre,Price,Rating")] Movie movie)
{
    if (id != movie.Id)
    {
        return NotFound();
    }

    if (ModelState.IsValid)
    {
        try
        {
            _context.Update(movie);
            await _context.SaveChangesAsync();
        }
        catch (DbUpdateConcurrencyException)
        {
            if (!MovieExists(movie.Id))
            {
                return NotFound();
            }
            else
            {
                throw;
            }
        }
        return RedirectToAction(nameof(Index));
    }
    return View(movie);
}

L'attributo [Bind] è un modo per proteggersi dall'overposting. È necessario includere solo le proprietà nell'attributo [Bind] che si vuole modificare. Per altre informazioni, vedere Proteggere il controller dall'overposting. ViewModel offre un approccio alternativo per evitare l'overposting.

Si noti che il secondo metodo di azione Edit è preceduto dall'attributo [HttpPost].

// POST: Movies/Edit/5
// To protect from overposting attacks, enable the specific properties you want to bind to.
// For more details, see http://go.microsoft.com/fwlink/?LinkId=317598.
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Edit(int id, [Bind("Id,Title,ReleaseDate,Genre,Price,Rating")] Movie movie)
{
    if (id != movie.Id)
    {
        return NotFound();
    }

    if (ModelState.IsValid)
    {
        try
        {
            _context.Update(movie);
            await _context.SaveChangesAsync();
        }
        catch (DbUpdateConcurrencyException)
        {
            if (!MovieExists(movie.Id))
            {
                return NotFound();
            }
            else
            {
                throw;
            }
        }
        return RedirectToAction(nameof(Index));
    }
    return View(movie);
}

L'attributo HttpPost specifica che questo metodo Edit può essere richiamato solo per le richieste POST. È possibile applicare l'attributo [HttpGet] al primo metodo di modifica, ma non è necessario perché l'impostazione predefinita è [HttpGet].

L'attributo ValidateAntiForgeryToken viene usato per impedire la falsificazione di una richiesta e viene associato a un token anti-falsità generato nel file di visualizzazione di modifica (Views/Movies/Edit.cshtml). Il file di vista di modifica genera il token antifalsificazione con l'helper tag di modulo.

<form asp-action="Edit">

L'helper tag genera un token antifalsificazione nascosto che deve corrispondere al token antifalsificazione generato [ValidateAntiForgeryToken] nel metodo Edit del controller di film. Per altre informazioni, vedere Prevenire attacchi tramite richieste intersito false (XSRF/CSRF) in ASP.NET Core.

Il metodo HttpGet Edit accetta il parametro ID, cerca il film tramite il metodo FindAsync Entity Framework e restituisce il film selezionato nella vista Edit. Se non vengono trovati film, viene restituito l'errore HTTP 404 NotFound.

// GET: Movies/Edit/5
public async Task<IActionResult> Edit(int? id)
{
    if (id == null)
    {
        return NotFound();
    }

    var movie = await _context.Movie.FindAsync(id);
    if (movie == null)
    {
        return NotFound();
    }
    return View(movie);
}

Quando il sistema di scaffolding ha creato la vista Edit, ha esaminato la classe Movie e il codice creato per eseguire il rendering degli elementi <label> e <input> per ogni proprietà della classe. L'esempio seguente illustra la vista Edit (Modifica) generata dal sistema di scaffolding di Visual Studio:

@model MvcMovie.Models.Movie

@{
    ViewData["Title"] = "Edit";
}

<h1>Edit</h1>

<h4>Movie</h4>
<hr />
<div class="row">
    <div class="col-md-4">
        <form asp-action="Edit">
            <div asp-validation-summary="ModelOnly" class="text-danger"></div>
            <input type="hidden" asp-for="Id" />
            <div class="form-group">
                <label asp-for="Title" class="control-label"></label>
                <input asp-for="Title" class="form-control" />
                <span asp-validation-for="Title" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="ReleaseDate" class="control-label"></label>
                <input asp-for="ReleaseDate" class="form-control" />
                <span asp-validation-for="ReleaseDate" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="Genre" class="control-label"></label>
                <input asp-for="Genre" class="form-control" />
                <span asp-validation-for="Genre" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="Price" class="control-label"></label>
                <input asp-for="Price" class="form-control" />
                <span asp-validation-for="Price" class="text-danger"></span>
            </div>
            <div class="form-group">
                <input type="submit" value="Save" class="btn btn-primary" />
            </div>
        </form>
    </div>
</div>

<div>
    <a asp-action="Index">Back to List</a>
</div>

@section Scripts {
    @{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}

Si noti come il modello di vista contiene un'istruzione @model MvcMovie.Models.Movie all'inizio del file. @model MvcMovie.Models.Movie specifica che il modelli previsto dalla vista per il modello di vista sia di tipo Movie.

Il codice di scaffolding usa diversi metodi helper tag per semplificare il markup HTML. L'helper tag etichetta visualizza il nome del campo ("Title", "ReleaseDate", "Genre" o "Price"). L'helper tag di input esegue il rendering di un elemento <input> HTML. L'helper tag di convalida visualizza eventuali messaggi di convalida associati a questa proprietà.

Eseguire l'applicazione e passare all'URL /Movies. Fare clic su un collegamento Edit (Modifica). Nel browser visualizzare l'origine per la pagina. Il codice HTML generato per l'elemento <form> è riportato di seguito.

<form action="/Movies/Edit/7" method="post">
    <div class="form-horizontal">
        <h4>Movie</h4>
        <hr />
        <div class="text-danger" />
        <input type="hidden" data-val="true" data-val-required="The ID field is required." id="ID" name="ID" value="7" />
        <div class="form-group">
            <label class="control-label col-md-2" for="Genre" />
            <div class="col-md-10">
                <input class="form-control" type="text" id="Genre" name="Genre" value="Western" />
                <span class="text-danger field-validation-valid" data-valmsg-for="Genre" data-valmsg-replace="true"></span>
            </div>
        </div>
        <div class="form-group">
            <label class="control-label col-md-2" for="Price" />
            <div class="col-md-10">
                <input class="form-control" type="text" data-val="true" data-val-number="The field Price must be a number." data-val-required="The Price field is required." id="Price" name="Price" value="3.99" />
                <span class="text-danger field-validation-valid" data-valmsg-for="Price" data-valmsg-replace="true"></span>
            </div>
        </div>
        <!-- Markup removed for brevity -->
        <div class="form-group">
            <div class="col-md-offset-2 col-md-10">
                <input type="submit" value="Save" class="btn btn-default" />
            </div>
        </div>
    </div>
    <input name="__RequestVerificationToken" type="hidden" value="CfDJ8Inyxgp63fRFqUePGvuI5jGZsloJu1L7X9le1gy7NCIlSduCRx9jDQClrV9pOTTmqUyXnJBXhmrjcUVDJyDUMm7-MF_9rK8aAZdRdlOri7FmKVkRe_2v5LIHGKFcTjPrWPYnc9AdSbomkiOSaTEg7RU" />
</form>

Gli elementi <input> si trovano in un elemento HTML <form> il cui attributo action è impostato per inviare all'URL /Movies/Edit/id. I dati del modulo verranno inviati al server quando si fa clic sul pulsante Save. L'ultima riga prima dell'elemento </form> di chiusura mostra il token XSRF nascosto generato dall'helper tag del modulo.

Elaborazione della richiesta POST

Nell'elenco seguente viene indicata la versione [HttpPost] del metodo di azione Edit.

// POST: Movies/Edit/5
// To protect from overposting attacks, enable the specific properties you want to bind to.
// For more details, see http://go.microsoft.com/fwlink/?LinkId=317598.
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Edit(int id, [Bind("Id,Title,ReleaseDate,Genre,Price,Rating")] Movie movie)
{
    if (id != movie.Id)
    {
        return NotFound();
    }

    if (ModelState.IsValid)
    {
        try
        {
            _context.Update(movie);
            await _context.SaveChangesAsync();
        }
        catch (DbUpdateConcurrencyException)
        {
            if (!MovieExists(movie.Id))
            {
                return NotFound();
            }
            else
            {
                throw;
            }
        }
        return RedirectToAction(nameof(Index));
    }
    return View(movie);
}

L'attributo [ValidateAntiForgeryToken] convalida il token XSRF nascosto generato dal generatore di token antifalsificazione nell'helper tag del modulo

Il sistema di associazione di modelli accetta i valori del modulo inseriti e crea un oggetto Movie passato come parametro movie. La ModelState.IsValid proprietà verifica che i dati inviati nel modulo possano essere utilizzati per modificare (modificare o aggiornare) un Movie oggetto . Se sono validi, i dati vengono salvati. I dati dei film aggiornati (modificati) vengono salvati nel database chiamando il metodo SaveChangesAsync del contesto di database. Dopo avere salvato i dati, il codice reindirizza l'utente al metodo di azione Index della classe MoviesController, che visualizza la raccolta di film, incluse le modifiche appena apportate.

Prima di inviare il modulo al server, la convalida sul lato client controlla tutte le regole di convalida nei campi. Se sono presenti errori di convalida, viene visualizzato un messaggio di errore e il modulo non viene inviato. Se JavaScript è disabilitato, non verrà eseguita la convalida sul lato client, ma il server rileverà i valori inviati non validi e i valori del modulo verranno visualizzati nuovamente con messaggi di errore. Più avanti in questa esercitazione la convalida del modello verrà esaminata in maggiore dettaglio. L'helper tag di convalida nel Views/Movies/Edit.cshtml modello di visualizzazione si occupa della visualizzazione dei messaggi di errore appropriati.

Modifica visualizzazione: eccezione per un valore di prezzo non corretto di abc indica che il campo Prezzo deve essere un numero. Eccezione per un valore di data di rilascio non corretto degli stati xyz Immettere una data valida.

Tutti i metodi HttpGet nel controller di film seguono un pattern simile. Ricevono un oggetto film (o un elenco di oggetti nel caso di Index) e passano l'oggetto (modello) alla vista. Il metodo Create passa un oggetto vuoto alla vista Create. Tutti i metodi che creano, modificano, eliminano o cambiano in altro modo i dati, eseguono questa operazione nell'overload [HttpPost] del metodo. La modifica dei dati in un metodo HTTP GET è un rischio per la sicurezza. La modifica dei dati in un HTTP GET metodo viola anche le procedure consigliate HTTP e il modello di architettura REST , che specifica che le richieste GET non devono modificare lo stato dell'applicazione. In altre parole, l'esecuzione di un'operazione GET deve essere sicura, senza effetti collaterali e non modificare dati persistenti.

Risorse aggiuntive

Le operazioni iniziali con l'app per i film sono state efficaci, ma la presentazione non è ottimale, ad esempio ReleaseDate dovrebbe essere scritto come due parole.

Vista Index: Release Date è un'unica parola (senza spazi) e la data di rilascio di ogni film indica l'ora nel formato 12 AM

Aprire il Models/Movie.cs file e aggiungere le righe evidenziate illustrate di seguito:

using System;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;

namespace MvcMovie.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; }
}

DataAnnotations sono spiegate nell'esercitazione successiva. L'attributo Display specifica il testo da visualizzare per il nome di un campo, in questo caso "Release Date" anziché "ReleaseDate". L'attributo DataType specifica il tipo di dati (Date) e quindi non vengono visualizzate le informazioni sull'ora archiviate nel campo.

L'annotazione dei dati [Column(TypeName = "decimal(18, 2)")] è necessaria per consentire a Entity Framework Core di eseguire correttamente il mapping di Price nella valuta del database. Per altre informazioni, vedere Tipi di dati.

Passare al controller Movies e posizionare il puntatore del mouse su un collegamento Edit (Modifica) per visualizzare l'URL di destinazione.

Finestra del browser con il passaggio del mouse sul collegamento Edit (Modifica) e un URL di collegamento di https://localhost:5001/Movies/Edit/5

I collegamenti Modifica, Dettagli ed Elimina vengono generati dall'helper tag di ancoraggio MVC principale nel Views/Movies/Index.cshtml file.

        <a asp-action="Edit" asp-route-id="@item.Id">Edit</a> |
        <a asp-action="Details" asp-route-id="@item.Id">Details</a> |
        <a asp-action="Delete" asp-route-id="@item.Id">Delete</a>
    </td>
</tr>

Gli helper tag consentono al codice lato server di partecipare alla creazione e al rendering di elementi HTML nei file Razor. Nel codice precedente, il valore dell'attributo AnchorTagHelper HTML href viene generato dinamicamente dal metodo di azione del controller e dall'ID di route. Usare Visualizza origine dal browser preferito o usare gli strumenti di sviluppo per esaminare il markup generato. Di seguito è riportata una parte del codice HTML generato:

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

Richiamare il formato per il routing impostato nel Program.cs file:

app.MapControllerRoute(
    name: "default",
    pattern: "{controller=Home}/{action=Index}/{id?}");

ASP.NET Core converte https://localhost:5001/Movies/Edit/4 in una richiesta al metodo di azione Edit del controller Movies con il parametro Id impostato su 4. I metodi del controller sono noti anche come metodi di azione.

Una delle nuove funzionalità più note di ASP.NET Core è rappresentata dagli helper tag. Per altre informazioni, vedere Risorse aggiuntive.

Aprire il controller Movies ed esaminare i due metodi di azione Edit. Il codice seguente illustra il HTTP GET Edit metodo , che recupera il filmato e popola il modulo di modifica generato dal Edit.cshtmlRazor file .

// GET: Movies/Edit/5
public async Task<IActionResult> Edit(int? id)
{
    if (id == null)
    {
        return NotFound();
    }

    var movie = await _context.Movie.FindAsync(id);
    if (movie == null)
    {
        return NotFound();
    }
    return View(movie);
}

Il codice seguente illustra il metodo HTTP POST Edit, che elabora i valori di film inviati:

// POST: Movies/Edit/5
// To protect from overposting attacks, enable the specific properties you want to bind to.
// For more details, see http://go.microsoft.com/fwlink/?LinkId=317598.
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Edit(int id, [Bind("Id,Title,ReleaseDate,Genre,Price,Rating")] Movie movie)
{
    if (id != movie.Id)
    {
        return NotFound();
    }

    if (ModelState.IsValid)
    {
        try
        {
            _context.Update(movie);
            await _context.SaveChangesAsync();
        }
        catch (DbUpdateConcurrencyException)
        {
            if (!MovieExists(movie.Id))
            {
                return NotFound();
            }
            else
            {
                throw;
            }
        }
        return RedirectToAction(nameof(Index));
    }
    return View(movie);
}

L'attributo [Bind] è un modo per proteggersi dall'overposting. È necessario includere solo le proprietà nell'attributo [Bind] che si vuole modificare. Per altre informazioni, vedere Proteggere il controller dall'overposting. ViewModel offre un approccio alternativo per evitare l'overposting.

Si noti che il secondo metodo di azione Edit è preceduto dall'attributo [HttpPost].

// POST: Movies/Edit/5
// To protect from overposting attacks, enable the specific properties you want to bind to.
// For more details, see http://go.microsoft.com/fwlink/?LinkId=317598.
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Edit(int id, [Bind("Id,Title,ReleaseDate,Genre,Price,Rating")] Movie movie)
{
    if (id != movie.Id)
    {
        return NotFound();
    }

    if (ModelState.IsValid)
    {
        try
        {
            _context.Update(movie);
            await _context.SaveChangesAsync();
        }
        catch (DbUpdateConcurrencyException)
        {
            if (!MovieExists(movie.Id))
            {
                return NotFound();
            }
            else
            {
                throw;
            }
        }
        return RedirectToAction(nameof(Index));
    }
    return View(movie);
}

L'attributo HttpPost specifica che questo metodo Edit può essere richiamato solo per le richieste POST. È possibile applicare l'attributo [HttpGet] al primo metodo di modifica, ma non è necessario perché l'impostazione predefinita è [HttpGet].

L'attributo ValidateAntiForgeryToken viene usato per impedire la falsificazione di una richiesta e viene associato a un token anti-falsità generato nel file di visualizzazione di modifica (Views/Movies/Edit.cshtml). Il file di vista di modifica genera il token antifalsificazione con l'helper tag di modulo.

<form asp-action="Edit">

L'helper tag genera un token antifalsificazione nascosto che deve corrispondere al token antifalsificazione generato [ValidateAntiForgeryToken] nel metodo Edit del controller di film. Per altre informazioni, vedere Prevenire attacchi tramite richieste intersito false (XSRF/CSRF) in ASP.NET Core.

Il metodo HttpGet Edit accetta il parametro ID, cerca il film tramite il metodo FindAsync Entity Framework e restituisce il film selezionato nella vista Edit. Se non vengono trovati film, viene restituito l'errore HTTP 404 NotFound.

// GET: Movies/Edit/5
public async Task<IActionResult> Edit(int? id)
{
    if (id == null)
    {
        return NotFound();
    }

    var movie = await _context.Movie.FindAsync(id);
    if (movie == null)
    {
        return NotFound();
    }
    return View(movie);
}

Quando il sistema di scaffolding ha creato la vista Edit, ha esaminato la classe Movie e il codice creato per eseguire il rendering degli elementi <label> e <input> per ogni proprietà della classe. L'esempio seguente illustra la vista Edit (Modifica) generata dal sistema di scaffolding di Visual Studio:

@model MvcMovie.Models.Movie

@{
    ViewData["Title"] = "Edit";
}

<h1>Edit</h1>

<h4>Movie</h4>
<hr />
<div class="row">
    <div class="col-md-4">
        <form asp-action="Edit">
            <div asp-validation-summary="ModelOnly" class="text-danger"></div>
            <input type="hidden" asp-for="Id" />
            <div class="form-group">
                <label asp-for="Title" class="control-label"></label>
                <input asp-for="Title" class="form-control" />
                <span asp-validation-for="Title" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="ReleaseDate" class="control-label"></label>
                <input asp-for="ReleaseDate" class="form-control" />
                <span asp-validation-for="ReleaseDate" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="Genre" class="control-label"></label>
                <input asp-for="Genre" class="form-control" />
                <span asp-validation-for="Genre" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="Price" class="control-label"></label>
                <input asp-for="Price" class="form-control" />
                <span asp-validation-for="Price" class="text-danger"></span>
            </div>
            <div class="form-group">
                <input type="submit" value="Save" class="btn btn-primary" />
            </div>
        </form>
    </div>
</div>

<div>
    <a asp-action="Index">Back to List</a>
</div>

@section Scripts {
    @{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}

Si noti come il modello di vista contiene un'istruzione @model MvcMovie.Models.Movie all'inizio del file. @model MvcMovie.Models.Movie specifica che il modelli previsto dalla vista per il modello di vista sia di tipo Movie.

Il codice di scaffolding usa diversi metodi helper tag per semplificare il markup HTML. L'helper tag etichetta visualizza il nome del campo ("Title", "ReleaseDate", "Genre" o "Price"). L'helper tag di input esegue il rendering di un elemento <input> HTML. L'helper tag di convalida visualizza eventuali messaggi di convalida associati a questa proprietà.

Eseguire l'applicazione e passare all'URL /Movies. Fare clic su un collegamento Edit (Modifica). Nel browser visualizzare l'origine per la pagina. Il codice HTML generato per l'elemento <form> è riportato di seguito.

<form action="/Movies/Edit/7" method="post">
    <div class="form-horizontal">
        <h4>Movie</h4>
        <hr />
        <div class="text-danger" />
        <input type="hidden" data-val="true" data-val-required="The ID field is required." id="ID" name="ID" value="7" />
        <div class="form-group">
            <label class="control-label col-md-2" for="Genre" />
            <div class="col-md-10">
                <input class="form-control" type="text" id="Genre" name="Genre" value="Western" />
                <span class="text-danger field-validation-valid" data-valmsg-for="Genre" data-valmsg-replace="true"></span>
            </div>
        </div>
        <div class="form-group">
            <label class="control-label col-md-2" for="Price" />
            <div class="col-md-10">
                <input class="form-control" type="text" data-val="true" data-val-number="The field Price must be a number." data-val-required="The Price field is required." id="Price" name="Price" value="3.99" />
                <span class="text-danger field-validation-valid" data-valmsg-for="Price" data-valmsg-replace="true"></span>
            </div>
        </div>
        <!-- Markup removed for brevity -->
        <div class="form-group">
            <div class="col-md-offset-2 col-md-10">
                <input type="submit" value="Save" class="btn btn-default" />
            </div>
        </div>
    </div>
    <input name="__RequestVerificationToken" type="hidden" value="CfDJ8Inyxgp63fRFqUePGvuI5jGZsloJu1L7X9le1gy7NCIlSduCRx9jDQClrV9pOTTmqUyXnJBXhmrjcUVDJyDUMm7-MF_9rK8aAZdRdlOri7FmKVkRe_2v5LIHGKFcTjPrWPYnc9AdSbomkiOSaTEg7RU" />
</form>

Gli elementi <input> si trovano in un elemento HTML <form> il cui attributo action è impostato per inviare all'URL /Movies/Edit/id. I dati del modulo verranno inviati al server quando si fa clic sul pulsante Save. L'ultima riga prima dell'elemento </form> di chiusura mostra il token XSRF nascosto generato dall'helper tag del modulo.

Elaborazione della richiesta POST

Nell'elenco seguente viene indicata la versione [HttpPost] del metodo di azione Edit.

// POST: Movies/Edit/5
// To protect from overposting attacks, enable the specific properties you want to bind to.
// For more details, see http://go.microsoft.com/fwlink/?LinkId=317598.
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Edit(int id, [Bind("Id,Title,ReleaseDate,Genre,Price,Rating")] Movie movie)
{
    if (id != movie.Id)
    {
        return NotFound();
    }

    if (ModelState.IsValid)
    {
        try
        {
            _context.Update(movie);
            await _context.SaveChangesAsync();
        }
        catch (DbUpdateConcurrencyException)
        {
            if (!MovieExists(movie.Id))
            {
                return NotFound();
            }
            else
            {
                throw;
            }
        }
        return RedirectToAction(nameof(Index));
    }
    return View(movie);
}

L'attributo [ValidateAntiForgeryToken] convalida il token XSRF nascosto generato dal generatore di token antifalsificazione nell'helper tag del modulo

Il sistema di associazione di modelli accetta i valori del modulo inseriti e crea un oggetto Movie passato come parametro movie. La ModelState.IsValid proprietà verifica che i dati inviati nel modulo possano essere utilizzati per modificare (modificare o aggiornare) un Movie oggetto . Se sono validi, i dati vengono salvati. I dati dei film aggiornati (modificati) vengono salvati nel database chiamando il metodo SaveChangesAsync del contesto di database. Dopo avere salvato i dati, il codice reindirizza l'utente al metodo di azione Index della classe MoviesController, che visualizza la raccolta di film, incluse le modifiche appena apportate.

Prima di inviare il modulo al server, la convalida sul lato client controlla tutte le regole di convalida nei campi. Se sono presenti errori di convalida, viene visualizzato un messaggio di errore e il modulo non viene inviato. Se JavaScript è disabilitato, non verrà eseguita la convalida sul lato client, ma il server rileverà i valori inviati non validi e i valori del modulo verranno visualizzati nuovamente con messaggi di errore. Più avanti in questa esercitazione la convalida del modello verrà esaminata in maggiore dettaglio. L'helper tag di convalida nel Views/Movies/Edit.cshtml modello di visualizzazione si occupa della visualizzazione dei messaggi di errore appropriati.

Modifica visualizzazione: eccezione per un valore di prezzo non corretto di abc indica che il campo Prezzo deve essere un numero. Eccezione per un valore di data di rilascio non corretto degli stati xyz Immettere una data valida.

Tutti i metodi HttpGet nel controller di film seguono un pattern simile. Ricevono un oggetto film (o un elenco di oggetti nel caso di Index) e passano l'oggetto (modello) alla vista. Il metodo Create passa un oggetto vuoto alla vista Create. Tutti i metodi che creano, modificano, eliminano o cambiano in altro modo i dati, eseguono questa operazione nell'overload [HttpPost] del metodo. La modifica dei dati in un metodo HTTP GET è un rischio per la sicurezza. La modifica dei dati in un HTTP GET metodo viola anche le procedure consigliate HTTP e il modello di architettura REST , che specifica che le richieste GET non devono modificare lo stato dell'applicazione. In altre parole, l'esecuzione di un'operazione GET deve essere sicura, senza effetti collaterali e non modificare dati persistenti.

Risorse aggiuntive

Le operazioni iniziali con l'app per i film sono state efficaci, ma la presentazione non è ottimale, ad esempio ReleaseDate dovrebbe essere scritto come due parole.

Vista Index: Release Date è un'unica parola (senza spazi) e la data di rilascio di ogni film indica l'ora nel formato 12 AM

Aprire il Models/Movie.cs file e aggiungere le righe evidenziate illustrate di seguito:

using System;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;

namespace MvcMovie.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; }
    }
}

DataAnnotations sono spiegate nell'esercitazione successiva. L'attributo Display specifica il testo da visualizzare per il nome di un campo, in questo caso "Release Date" anziché "ReleaseDate". L'attributo DataType specifica il tipo di dati (Date) e quindi non vengono visualizzate le informazioni sull'ora archiviate nel campo.

L'annotazione dei dati [Column(TypeName = "decimal(18, 2)")] è necessaria per consentire a Entity Framework Core di eseguire correttamente il mapping di Price nella valuta del database. Per altre informazioni, vedere Tipi di dati.

Passare al controller Movies e posizionare il puntatore del mouse su un collegamento Edit (Modifica) per visualizzare l'URL di destinazione.

Finestra del browser con il passaggio del mouse sul collegamento Edit (Modifica) e un URL di collegamento di https://localhost:5001/Movies/Edit/5

I collegamenti Modifica, Dettagli ed Elimina vengono generati dall'helper tag di ancoraggio MVC principale nel Views/Movies/Index.cshtml file.

        <a asp-action="Edit" asp-route-id="@item.Id">Edit</a> |
        <a asp-action="Details" asp-route-id="@item.Id">Details</a> |
        <a asp-action="Delete" asp-route-id="@item.Id">Delete</a>
    </td>
</tr>

Gli helper tag consentono al codice lato server di partecipare alla creazione e al rendering di elementi HTML nei file Razor. Nel codice precedente, il valore dell'attributo AnchorTagHelper HTML href viene generato dinamicamente dal metodo di azione del controller e dall'ID di route. Usare Visualizza origine dal browser preferito o usare gli strumenti di sviluppo per esaminare il markup generato. Di seguito è riportata una parte del codice HTML generato:

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

Richiamare il formato per il routing impostato nel Program.cs file:

app.MapControllerRoute(
    name: "default",
    pattern: "{controller=Home}/{action=Index}/{id?}");

ASP.NET Core converte https://localhost:5001/Movies/Edit/4 in una richiesta al metodo di azione Edit del controller Movies con il parametro Id impostato su 4. I metodi del controller sono noti anche come metodi di azione.

Gli helper tag sono una funzionalità diffusa in ASP.NET Core. Per altre informazioni, vedere Risorse aggiuntive.

Aprire il controller Movies ed esaminare i due metodi di azione Edit. Il codice seguente illustra il HTTP GET Edit metodo , che recupera il filmato e popola il modulo di modifica generato dal Edit.cshtmlRazor file .

// GET: Movies/Edit/5
public async Task<IActionResult> Edit(int? id)
{
    if (id == null)
    {
        return NotFound();
    }

    var movie = await _context.Movie.FindAsync(id);
    if (movie == null)
    {
        return NotFound();
    }
    return View(movie);
}

Il codice seguente illustra il metodo HTTP POST Edit, che elabora i valori di film inviati:

// POST: Movies/Edit/5
// To protect from overposting attacks, enable the specific properties you want to bind to.
// For more details, see http://go.microsoft.com/fwlink/?LinkId=317598.
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Edit(int id, [Bind("Id,Title,ReleaseDate,Genre,Price,Rating")] Movie movie)
{
    if (id != movie.Id)
    {
        return NotFound();
    }

    if (ModelState.IsValid)
    {
        try
        {
            _context.Update(movie);
            await _context.SaveChangesAsync();
        }
        catch (DbUpdateConcurrencyException)
        {
            if (!MovieExists(movie.Id))
            {
                return NotFound();
            }
            else
            {
                throw;
            }
        }
        return RedirectToAction(nameof(Index));
    }
    return View(movie);
}

L'attributo [Bind] è un modo per proteggersi dall'overposting. È necessario includere solo le proprietà nell'attributo [Bind] che si vuole modificare. Per altre informazioni, vedere Proteggere il controller dall'overposting. ViewModel offre un approccio alternativo per evitare l'overposting.

Si noti che il secondo metodo di azione Edit è preceduto dall'attributo [HttpPost].

// POST: Movies/Edit/5
// To protect from overposting attacks, enable the specific properties you want to bind to.
// For more details, see http://go.microsoft.com/fwlink/?LinkId=317598.
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Edit(int id, [Bind("Id,Title,ReleaseDate,Genre,Price,Rating")] Movie movie)
{
    if (id != movie.Id)
    {
        return NotFound();
    }

    if (ModelState.IsValid)
    {
        try
        {
            _context.Update(movie);
            await _context.SaveChangesAsync();
        }
        catch (DbUpdateConcurrencyException)
        {
            if (!MovieExists(movie.Id))
            {
                return NotFound();
            }
            else
            {
                throw;
            }
        }
        return RedirectToAction(nameof(Index));
    }
    return View(movie);
}

L'attributo HttpPost specifica che questo metodo Edit può essere richiamato solo per le richieste POST. È possibile applicare l'attributo [HttpGet] al primo metodo di modifica, ma non è necessario perché l'impostazione predefinita è [HttpGet].

L'attributo ValidateAntiForgeryToken viene usato per impedire la falsificazione di una richiesta e viene associato a un token anti-falsità generato nel file di visualizzazione di modifica (Views/Movies/Edit.cshtml). Il file di vista di modifica genera il token antifalsificazione con l'helper tag di modulo.

<form asp-action="Edit">

L'helper tag genera un token antifalsificazione nascosto che deve corrispondere al token antifalsificazione generato [ValidateAntiForgeryToken] nel metodo Edit del controller di film. Per altre informazioni, vedere Prevenire attacchi tramite richieste intersito false (XSRF/CSRF) in ASP.NET Core.

Il metodo HttpGet Edit accetta il parametro ID, cerca il film tramite il metodo FindAsync Entity Framework e restituisce il film selezionato nella vista Edit. Se non vengono trovati film, viene restituito l'errore HTTP 404 NotFound.

// GET: Movies/Edit/5
public async Task<IActionResult> Edit(int? id)
{
    if (id == null)
    {
        return NotFound();
    }

    var movie = await _context.Movie.FindAsync(id);
    if (movie == null)
    {
        return NotFound();
    }
    return View(movie);
}

Quando il sistema di scaffolding ha creato la vista Edit, ha esaminato la classe Movie e il codice creato per eseguire il rendering degli elementi <label> e <input> per ogni proprietà della classe. L'esempio seguente illustra la vista Edit (Modifica) generata dal sistema di scaffolding di Visual Studio:

@model MvcMovie.Models.Movie

@{
    ViewData["Title"] = "Edit";
}

<h1>Edit</h1>

<h4>Movie</h4>
<hr />
<div class="row">
    <div class="col-md-4">
        <form asp-action="Edit">
            <div asp-validation-summary="ModelOnly" class="text-danger"></div>
            <input type="hidden" asp-for="Id" />
            <div class="form-group">
                <label asp-for="Title" class="control-label"></label>
                <input asp-for="Title" class="form-control" />
                <span asp-validation-for="Title" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="ReleaseDate" class="control-label"></label>
                <input asp-for="ReleaseDate" class="form-control" />
                <span asp-validation-for="ReleaseDate" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="Genre" class="control-label"></label>
                <input asp-for="Genre" class="form-control" />
                <span asp-validation-for="Genre" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="Price" class="control-label"></label>
                <input asp-for="Price" class="form-control" />
                <span asp-validation-for="Price" class="text-danger"></span>
            </div>
            <div class="form-group">
                <input type="submit" value="Save" class="btn btn-primary" />
            </div>
        </form>
    </div>
</div>

<div>
    <a asp-action="Index">Back to List</a>
</div>

@section Scripts {
    @{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}

Si noti come il modello di vista contiene un'istruzione @model MvcMovie.Models.Movie all'inizio del file. @model MvcMovie.Models.Movie specifica che il modelli previsto dalla vista per il modello di vista sia di tipo Movie.

Il codice di scaffolding usa diversi metodi helper tag per semplificare il markup HTML. L'helper tag etichetta visualizza il nome del campo ("Title", "ReleaseDate", "Genre" o "Price"). L'helper tag di input esegue il rendering di un elemento <input> HTML. L'helper tag di convalida visualizza eventuali messaggi di convalida associati a questa proprietà.

Eseguire l'applicazione e passare all'URL /Movies. Fare clic su un collegamento Edit (Modifica). Nel browser visualizzare l'origine per la pagina. Il codice HTML generato per l'elemento <form> è riportato di seguito.

<form action="/Movies/Edit/7" method="post">
    <div class="form-horizontal">
        <h4>Movie</h4>
        <hr />
        <div class="text-danger" />
        <input type="hidden" data-val="true" data-val-required="The ID field is required." id="ID" name="ID" value="7" />
        <div class="form-group">
            <label class="control-label col-md-2" for="Genre" />
            <div class="col-md-10">
                <input class="form-control" type="text" id="Genre" name="Genre" value="Western" />
                <span class="text-danger field-validation-valid" data-valmsg-for="Genre" data-valmsg-replace="true"></span>
            </div>
        </div>
        <div class="form-group">
            <label class="control-label col-md-2" for="Price" />
            <div class="col-md-10">
                <input class="form-control" type="text" data-val="true" data-val-number="The field Price must be a number." data-val-required="The Price field is required." id="Price" name="Price" value="3.99" />
                <span class="text-danger field-validation-valid" data-valmsg-for="Price" data-valmsg-replace="true"></span>
            </div>
        </div>
        <!-- Markup removed for brevity -->
        <div class="form-group">
            <div class="col-md-offset-2 col-md-10">
                <input type="submit" value="Save" class="btn btn-default" />
            </div>
        </div>
    </div>
    <input name="__RequestVerificationToken" type="hidden" value="CfDJ8Inyxgp63fRFqUePGvuI5jGZsloJu1L7X9le1gy7NCIlSduCRx9jDQClrV9pOTTmqUyXnJBXhmrjcUVDJyDUMm7-MF_9rK8aAZdRdlOri7FmKVkRe_2v5LIHGKFcTjPrWPYnc9AdSbomkiOSaTEg7RU" />
</form>

Gli elementi <input> si trovano in un elemento HTML <form> il cui attributo action è impostato per inviare all'URL /Movies/Edit/id. I dati del modulo verranno inviati al server quando si fa clic sul pulsante Save. L'ultima riga prima dell'elemento </form> di chiusura mostra il token XSRF nascosto generato dall'helper tag del modulo.

Elaborazione della richiesta POST

Nell'elenco seguente viene indicata la versione [HttpPost] del metodo di azione Edit.

// POST: Movies/Edit/5
// To protect from overposting attacks, enable the specific properties you want to bind to.
// For more details, see http://go.microsoft.com/fwlink/?LinkId=317598.
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Edit(int id, [Bind("Id,Title,ReleaseDate,Genre,Price,Rating")] Movie movie)
{
    if (id != movie.Id)
    {
        return NotFound();
    }

    if (ModelState.IsValid)
    {
        try
        {
            _context.Update(movie);
            await _context.SaveChangesAsync();
        }
        catch (DbUpdateConcurrencyException)
        {
            if (!MovieExists(movie.Id))
            {
                return NotFound();
            }
            else
            {
                throw;
            }
        }
        return RedirectToAction(nameof(Index));
    }
    return View(movie);
}

L'attributo [ValidateAntiForgeryToken] convalida il token XSRF nascosto generato dal generatore di token antifalsificazione nell'helper tag del modulo

Il sistema di associazione di modelli accetta i valori del modulo inseriti e crea un oggetto Movie passato come parametro movie. La ModelState.IsValid proprietà verifica che i dati inviati nel modulo possano essere utilizzati per modificare (modificare o aggiornare) un Movie oggetto . Se sono validi, i dati vengono salvati. I dati dei film aggiornati (modificati) vengono salvati nel database chiamando il metodo SaveChangesAsync del contesto di database. Dopo avere salvato i dati, il codice reindirizza l'utente al metodo di azione Index della classe MoviesController, che visualizza la raccolta di film, incluse le modifiche appena apportate.

Prima di inviare il modulo al server, la convalida sul lato client controlla tutte le regole di convalida nei campi. Se sono presenti errori di convalida, viene visualizzato un messaggio di errore e il modulo non viene inviato. Se JavaScript è disabilitato, non verrà eseguita la convalida sul lato client, ma il server rileverà i valori inviati non validi e i valori del modulo verranno visualizzati nuovamente con messaggi di errore. Più avanti in questa esercitazione la convalida del modello verrà esaminata in maggiore dettaglio. L'helper tag di convalida nel Views/Movies/Edit.cshtml modello di visualizzazione si occupa della visualizzazione dei messaggi di errore appropriati.

Modifica visualizzazione: eccezione per un valore di prezzo non corretto di abc indica che il campo Prezzo deve essere un numero. Eccezione per un valore di data di rilascio non corretto degli stati xyz Immettere una data valida.

Tutti i metodi HttpGet nel controller di film seguono un pattern simile. Ricevono un oggetto film (o un elenco di oggetti nel caso di Index) e passano l'oggetto (modello) alla vista. Il metodo Create passa un oggetto vuoto alla vista Create. Tutti i metodi che creano, modificano, eliminano o cambiano in altro modo i dati, eseguono questa operazione nell'overload [HttpPost] del metodo. La modifica dei dati in un metodo HTTP GET è un rischio per la sicurezza. La modifica dei dati in un HTTP GET metodo viola anche le procedure consigliate HTTP e il modello di architettura REST , che specifica che le richieste GET non devono modificare lo stato dell'applicazione. In altre parole, l'esecuzione di un'operazione GET deve essere sicura, senza effetti collaterali e non modificare dati persistenti.

Risorse aggiuntive

Le operazioni iniziali con l'app per i film sono state efficaci, ma la presentazione non è ottimale, ad esempio ReleaseDate dovrebbe essere scritto come due parole.

Vista Index: Release Date è un'unica parola (senza spazi) e la data di rilascio di ogni film indica l'ora nel formato 12 AM

Aprire il Models/Movie.cs file e aggiungere le righe evidenziate illustrate di seguito:

using System;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;

namespace MvcMovie.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; }
    }
}

L'attributo DataAnnotations viene esaminato nell'esercitazione successiva. L'attributo Display specifica il testo da visualizzare per il nome di un campo, in questo caso "Release Date" anziché "ReleaseDate". L'attributo DataType specifica il tipo di dati (Date) e quindi non vengono visualizzate le informazioni sull'ora archiviate nel campo.

L'annotazione dei dati [Column(TypeName = "decimal(18, 2)")] è necessaria per consentire a Entity Framework Core di eseguire correttamente il mapping di Price nella valuta del database. Per altre informazioni, vedere Tipi di dati.

Passare al controller Movies e posizionare il puntatore del mouse su un collegamento Edit (Modifica) per visualizzare l'URL di destinazione.

Finestra del browser con il passaggio del mouse sul collegamento Edit (Modifica) e un URL di collegamento di https://localhost:5001/Movies/Edit/5

I collegamenti Modifica, Dettagli ed Elimina vengono generati dall'helper tag di ancoraggio MVC principale nel Views/Movies/Index.cshtml file.

        <a asp-action="Edit" asp-route-id="@item.ID">Edit</a> |
        <a asp-action="Details" asp-route-id="@item.ID">Details</a> |
        <a asp-action="Delete" asp-route-id="@item.ID">Delete</a>
    </td>
</tr>

Gli helper tag consentono al codice lato server di partecipare alla creazione e al rendering di elementi HTML nei file Razor. Nel codice precedente, il valore dell'attributo AnchorTagHelper HTML href viene generato dinamicamente dal metodo di azione del controller e dall'ID di route. Usare Visualizza origine dal browser preferito o usare gli strumenti di sviluppo per esaminare il markup generato. Di seguito è riportata una parte del codice HTML generato:

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

Richiamare il formato per il routing impostato nel Startup.cs file:

app.UseEndpoints(endpoints =>
{
    endpoints.MapControllerRoute(
        name: "default",
        pattern: "{controller=Home}/{action=Index}/{id?}");
});

ASP.NET Core converte https://localhost:5001/Movies/Edit/4 in una richiesta al metodo di azione Edit del controller Movies con il parametro Id impostato su 4. I metodi del controller sono noti anche come metodi di azione.

Per altre informazioni sugli helper tag, vedere Risorse aggiuntive.

Aprire il controller Movies ed esaminare i due metodi di azione Edit. Il codice seguente illustra il HTTP GET Edit metodo , che recupera il filmato e popola il modulo di modifica generato dal Edit.cshtmlRazor file .

// GET: Movies/Edit/5
public async Task<IActionResult> Edit(int? id)
{
    if (id == null)
    {
        return NotFound();
    }

    var movie = await _context.Movie.FindAsync(id);
    if (movie == null)
    {
        return NotFound();
    }
    return View(movie);
}

Il codice seguente illustra il metodo HTTP POST Edit, che elabora i valori di film inviati:

// POST: Movies/Edit/5
// To protect from overposting attacks, please enable the specific properties you want to bind to, for 
// more details see http://go.microsoft.com/fwlink/?LinkId=317598.
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Edit(int id, [Bind("ID,Title,ReleaseDate,Genre,Price")] Movie movie)
{
    if (id != movie.ID)
    {
        return NotFound();
    }

    if (ModelState.IsValid)
    {
        try
        {
            _context.Update(movie);
            await _context.SaveChangesAsync();
        }
        catch (DbUpdateConcurrencyException)
        {
            if (!MovieExists(movie.ID))
            {
                return NotFound();
            }
            else
            {
                throw;
            }
        }
        return RedirectToAction("Index");
    }
    return View(movie);
}

L'attributo [Bind] è un modo per proteggersi dall'overposting. È necessario includere solo le proprietà nell'attributo [Bind] che si vuole modificare. Per altre informazioni, vedere Proteggere il controller dall'overposting. ViewModel offre un approccio alternativo per evitare l'overposting.

Si noti che il secondo metodo di azione Edit è preceduto dall'attributo [HttpPost].

[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Edit(int id, [Bind("ID,Title,ReleaseDate,Genre,Price")] Movie movie)
{
    if (id != movie.ID)
    {
        return NotFound();
    }

    if (ModelState.IsValid)
    {
        try
        {
            _context.Update(movie);
            await _context.SaveChangesAsync();
        }
        catch (DbUpdateConcurrencyException)
        {
            if (!MovieExists(movie.ID))
            {
                return NotFound();
            }
            else
            {
                throw;
            }
        }
        return RedirectToAction(nameof(Index));
    }
    return View(movie);
}

L'attributo HttpPost specifica che questo metodo Edit può essere richiamato solo per le richieste POST. È possibile applicare l'attributo [HttpGet] al primo metodo di modifica, ma non è necessario perché l'impostazione predefinita è [HttpGet].

L'attributo ValidateAntiForgeryToken viene usato per impedire la falsificazione di una richiesta e viene associato a un token anti-falsità generato nel file di visualizzazione di modifica (Views/Movies/Edit.cshtml). Il file di vista di modifica genera il token antifalsificazione con l'helper tag di modulo.

<form asp-action="Edit">

L'helper tag genera un token antifalsificazione nascosto che deve corrispondere al token antifalsificazione generato [ValidateAntiForgeryToken] nel metodo Edit del controller di film. Per altre informazioni, vedere Prevenire attacchi tramite richieste intersito false (XSRF/CSRF) in ASP.NET Core.

Il metodo HttpGet Edit accetta il parametro ID, cerca il film tramite il metodo FindAsync Entity Framework e restituisce il film selezionato nella vista Edit. Se non vengono trovati film, viene restituito l'errore HTTP 404 NotFound.

// GET: Movies/Edit/5
public async Task<IActionResult> Edit(int? id)
{
    if (id == null)
    {
        return NotFound();
    }

    var movie = await _context.Movie.FindAsync(id);
    if (movie == null)
    {
        return NotFound();
    }
    return View(movie);
}

Quando il sistema di scaffolding ha creato la vista Edit, ha esaminato la classe Movie e il codice creato per eseguire il rendering degli elementi <label> e <input> per ogni proprietà della classe. L'esempio seguente illustra la vista Edit (Modifica) generata dal sistema di scaffolding di Visual Studio:

@model MvcMovie.Models.Movie

@{
    ViewData["Title"] = "Edit";
}

<h1>Edit</h1>

<h4>Movie</h4>
<hr />
<div class="row">
    <div class="col-md-4">
        <form asp-action="Edit">
            <div asp-validation-summary="ModelOnly" class="text-danger"></div>
            <input type="hidden" asp-for="Id" />
            <div class="form-group">
                <label asp-for="Title" class="control-label"></label>
                <input asp-for="Title" class="form-control" />
                <span asp-validation-for="Title" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="ReleaseDate" class="control-label"></label>
                <input asp-for="ReleaseDate" class="form-control" />
                <span asp-validation-for="ReleaseDate" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="Genre" class="control-label"></label>
                <input asp-for="Genre" class="form-control" />
                <span asp-validation-for="Genre" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="Price" class="control-label"></label>
                <input asp-for="Price" class="form-control" />
                <span asp-validation-for="Price" class="text-danger"></span>
            </div>
            <div class="form-group">
                <input type="submit" value="Save" class="btn btn-primary" />
            </div>
        </form>
    </div>
</div>

<div>
    <a asp-action="Index">Back to List</a>
</div>

@section Scripts {
    @{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}

Si noti come il modello di vista contiene un'istruzione @model MvcMovie.Models.Movie all'inizio del file. @model MvcMovie.Models.Movie specifica che il modelli previsto dalla vista per il modello di vista sia di tipo Movie.

Il codice di scaffolding usa diversi metodi helper tag per semplificare il markup HTML. L'helper tag etichetta visualizza il nome del campo ("Title", "ReleaseDate", "Genre" o "Price"). L'helper tag di input esegue il rendering di un elemento <input> HTML. L'helper tag di convalida visualizza eventuali messaggi di convalida associati a questa proprietà.

Eseguire l'applicazione e passare all'URL /Movies. Fare clic su un collegamento Edit (Modifica). Nel browser visualizzare l'origine per la pagina. Il codice HTML generato per l'elemento <form> è riportato di seguito.

<form action="/Movies/Edit/7" method="post">
    <div class="form-horizontal">
        <h4>Movie</h4>
        <hr />
        <div class="text-danger" />
        <input type="hidden" data-val="true" data-val-required="The ID field is required." id="ID" name="ID" value="7" />
        <div class="form-group">
            <label class="control-label col-md-2" for="Genre" />
            <div class="col-md-10">
                <input class="form-control" type="text" id="Genre" name="Genre" value="Western" />
                <span class="text-danger field-validation-valid" data-valmsg-for="Genre" data-valmsg-replace="true"></span>
            </div>
        </div>
        <div class="form-group">
            <label class="control-label col-md-2" for="Price" />
            <div class="col-md-10">
                <input class="form-control" type="text" data-val="true" data-val-number="The field Price must be a number." data-val-required="The Price field is required." id="Price" name="Price" value="3.99" />
                <span class="text-danger field-validation-valid" data-valmsg-for="Price" data-valmsg-replace="true"></span>
            </div>
        </div>
        <!-- Markup removed for brevity -->
        <div class="form-group">
            <div class="col-md-offset-2 col-md-10">
                <input type="submit" value="Save" class="btn btn-default" />
            </div>
        </div>
    </div>
    <input name="__RequestVerificationToken" type="hidden" value="CfDJ8Inyxgp63fRFqUePGvuI5jGZsloJu1L7X9le1gy7NCIlSduCRx9jDQClrV9pOTTmqUyXnJBXhmrjcUVDJyDUMm7-MF_9rK8aAZdRdlOri7FmKVkRe_2v5LIHGKFcTjPrWPYnc9AdSbomkiOSaTEg7RU" />
</form>

Gli elementi <input> si trovano in un elemento HTML <form> il cui attributo action è impostato per inviare all'URL /Movies/Edit/id. I dati del modulo verranno inviati al server quando si fa clic sul pulsante Save. L'ultima riga prima dell'elemento </form> di chiusura mostra il token XSRF nascosto generato dall'helper tag del modulo.

Elaborazione della richiesta POST

Nell'elenco seguente viene indicata la versione [HttpPost] del metodo di azione Edit.

[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Edit(int id, [Bind("ID,Title,ReleaseDate,Genre,Price")] Movie movie)
{
    if (id != movie.ID)
    {
        return NotFound();
    }

    if (ModelState.IsValid)
    {
        try
        {
            _context.Update(movie);
            await _context.SaveChangesAsync();
        }
        catch (DbUpdateConcurrencyException)
        {
            if (!MovieExists(movie.ID))
            {
                return NotFound();
            }
            else
            {
                throw;
            }
        }
        return RedirectToAction(nameof(Index));
    }
    return View(movie);
}

L'attributo [ValidateAntiForgeryToken] convalida il token XSRF nascosto generato dal generatore di token antifalsificazione nell'helper tag del modulo

Il sistema di associazione di modelli accetta i valori del modulo inseriti e crea un oggetto Movie passato come parametro movie. La ModelState.IsValid proprietà verifica che i dati inviati nel modulo possano essere utilizzati per modificare (modificare o aggiornare) un Movie oggetto . Se sono validi, i dati vengono salvati. I dati dei film aggiornati (modificati) vengono salvati nel database chiamando il metodo SaveChangesAsync del contesto di database. Dopo avere salvato i dati, il codice reindirizza l'utente al metodo di azione Index della classe MoviesController, che visualizza la raccolta di film, incluse le modifiche appena apportate.

Prima di inviare il modulo al server, la convalida sul lato client controlla tutte le regole di convalida nei campi. Se sono presenti errori di convalida, viene visualizzato un messaggio di errore e il modulo non viene inviato. Se JavaScript è disabilitato, non verrà eseguita la convalida sul lato client, ma il server rileverà i valori inviati non validi e i valori del modulo verranno visualizzati nuovamente con messaggi di errore. Più avanti in questa esercitazione la convalida del modello verrà esaminata in maggiore dettaglio. L'helper tag di convalida nel Views/Movies/Edit.cshtml modello di visualizzazione si occupa della visualizzazione dei messaggi di errore appropriati.

Modifica visualizzazione: eccezione per un valore di prezzo non corretto di abc indica che il campo Prezzo deve essere un numero. Eccezione per un valore di data di rilascio non corretto degli stati xyz Immettere una data valida.

Tutti i metodi HttpGet nel controller di film seguono un pattern simile. Ricevono un oggetto film (o un elenco di oggetti nel caso di Index) e passano l'oggetto (modello) alla vista. Il metodo Create passa un oggetto vuoto alla vista Create. Tutti i metodi che creano, modificano, eliminano o cambiano in altro modo i dati, eseguono questa operazione nell'overload [HttpPost] del metodo. La modifica dei dati in un metodo HTTP GET è un rischio per la sicurezza. La modifica dei dati in un HTTP GET metodo viola anche le procedure consigliate HTTP e il modello di architettura REST , che specifica che le richieste GET non devono modificare lo stato dell'applicazione. In altre parole, l'esecuzione di un'operazione GET deve essere sicura, senza effetti collaterali e non modificare dati persistenti.

Risorse aggiuntive