Condividi tramite


Parte 9, aggiungere la convalida a un'app MVC core ASP.NET

Nota

Questa non è la versione più recente di questo articolo. Per la versione corrente, vedere la versione .NET 8 di questo articolo.

Avviso

Questa versione di ASP.NET Core non è più supportata. Per altre informazioni, vedere Criteri di supporto di .NET e .NET Core. 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

Contenuto della sezione:

  • La logica di convalida viene aggiunta al modello Movie.
  • Si verifica che le regole di convalida vengano applicate ogni volta che un utente crea o modifica un film.

Rispetto del principio DRY

Uno dei principi di progettazione MVC è DRY ("Don't Repeat Yourself"). ASP.NET Core MVC promuove la specifica delle funzionalità o del comportamento una sola volta, con successiva applicazione ovunque in un'app. In questo modo si riduce la quantità di codice che è necessario scrivere e si rende il codice meno soggetto a errori, più semplice da testare e gestire.

Il supporto di convalida fornito da MVC ed Entity Framework Core è un buon esempio del principio DRY in azione. È possibile specificare in modo dichiarativo le regole di convalida in un'unica posizione (nella classe del modello) e le regole vengono applicate ovunque nell'app.

Eliminare i dati modificati in precedenza

Nel passaggio successivo vengono aggiunte regole di convalida che non consentono valori Null. Eseguire l'app, passare a /Movies/Index, eliminare tutti i film elencati e arrestare l'app. L'app userà i dati di inizializzazione alla successiva esecuzione.

Aggiungere regole di convalida al modello movie

Lo spazio dei nomi DataAnnotations offre un set di attributi di convalida predefiniti che vengono applicati in modo dichiarativo a una classe o una proprietà. DataAnnotations contiene anche gli attributi di formattazione come DataType che guidano nella formattazione e non offrono alcuna convalida.

Aggiornare la Movie classe per sfruttare i vantaggi degli attributi Requireddi convalida predefiniti , , RegularExpressionStringLengthRange e dell'attributo DataType di formattazione.

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

namespace MvcMovie.Models;

public class Movie
{
    public int Id { get; set; }

    [StringLength(60, MinimumLength = 3)]
    [Required]
    public string? Title { get; set; }

    [Display(Name = "Release Date")]
    [DataType(DataType.Date)]
    public DateTime ReleaseDate { get; set; }

    [Range(1, 100)]
    [DataType(DataType.Currency)]
    [Column(TypeName = "decimal(18, 2)")]
    public decimal Price { get; set; }    

    [RegularExpression(@"^[A-Z]+[a-zA-Z\s]*$")]
    [Required]
    [StringLength(30)]
    public string? Genre { get; set; }

    [RegularExpression(@"^[A-Z]+[a-zA-Z0-9""'\s-]*$")]
    [StringLength(5)]
    [Required]
    public string? Rating { get; set; }
}

Gli attributi di convalida specificano il comportamento da implementare nelle proprietà del modello a cui vengono applicati:

  • Gli attributi Required e MinimumLength indicano che una proprietà deve avere un valore, ma nulla impedisce all'utente di inserire spazi vuoti per soddisfare questa convalida.

  • L'attributo RegularExpression viene usato per limitare i caratteri che possono essere inseriti. Nel codice precedente "Genre":

    • Deve includere solo lettere.
    • La prima lettera deve essere maiuscola. Gli spazi vuoti sono consentiti mentre i numeri e i caratteri speciali non sono consentiti.
  • RegularExpression "Rating":

    • Richiede che il primo carattere sia una lettera maiuscola.
    • Consente i caratteri speciali e i numeri negli spazi successivi. "PG-13" è valido per una classificazione, ma non per "Genre".
  • L'attributo Range vincola un valore all'interno di un intervallo specificato.

  • L'attributo StringLength consente di impostare la lunghezza massima di una proprietà stringa e, facoltativamente, la lunghezza minima.

  • I tipi di valore, ad esempio decimal, int, float e DateTime, sono intrinsecamente necessari e non richiedono l'attributo [Required].

L'applicazione automatica di regole di convalida da ASP.NET Core è utile per rendere un'app più solida. In questo modo inoltre non è possibile omettere la convalida di un elemento e quindi inserire involontariamente dati errati nel database.

Interfaccia utente dell'errore di convalida

Eseguire l'app e passare al controller di film.

Selezionare il collegamento Crea nuovo per aggiungere un nuovo film. Completare il modulo con alcuni valori non validi. Non appena la convalida del lato client jQuery rileva l'errore, viene visualizzato un messaggio di errore.

Modulo di vista del film con diversi errori di convalida sul lato client jQuery

Nota

È possibile che non si riesca a immettere virgole decimali nel campo. Per supportare la convalida jQuery per impostazioni locali diverse dall'inglese che usano la virgola (",") come separatore decimale e per formati di data diversi da quello dell'inglese degli Stati Uniti, è necessario eseguire alcuni passaggi per globalizzare l'app. Per istruzioni sull'aggiunta di una virgola decimale, vedere questo commento di GitHub 4076 .

Si noti come il modulo ha eseguito automaticamente il rendering di un messaggio di errore di convalida appropriato in ogni campo contenente un valore non valido. Gli errori vengono applicati sia sul lato client (utilizzo di JavaScript e jQuery) sia sul lato server (nel caso di un utente con JavaScript disabilitato).

Un vantaggio significativo è che non è necessario modificare una singola riga di codice nella MoviesController classe o nella Create.cshtml visualizzazione per abilitare questa interfaccia utente di convalida. Il controller e le viste creati in una fase precedente di questa esercitazione hanno selezionato automaticamente le regole di convalida specificate usando gli attributi di convalida delle proprietà della classe Movie del modello. Eseguire il test della convalida usando il metodo di azione Edit e viene applicata la stessa convalida.

I dati del modulo non vengono inviati al server fino a quando non sono più presenti errori di convalida sul lato client. È possibile verificare questa condizione inserendo un punto di interruzione nel metodo HTTP Post usando lo strumento Fiddler o gli strumenti di sviluppo F12.

Funzionamento della convalida

Ci si potrebbe chiedere come la convalida dell'interfaccia utente sia stata generata senza aggiornamenti al codice nel controller o nelle viste. Il codice seguente mostra i due metodi Create.

// GET: Movies/Create
public IActionResult Create()
{
    return View();
}

// POST: Movies/Create
// 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> Create([Bind("Id,Title,ReleaseDate,Genre,Price,Rating")] Movie movie)
{
    if (ModelState.IsValid)
    {
        _context.Add(movie);
        await _context.SaveChangesAsync();
        return RedirectToAction(nameof(Index));
    }
    return View(movie);
}

Il primo metodo di azione (HTTP GET) Create visualizza il modulo di creazione iniziale. La seconda versione ([HttpPost]) gestisce l'invio del modulo. Il secondo metodo Create (la versione [HttpPost]) chiama ModelState.IsValid per verificare se esistono errori di convalida per il film. La chiamata a questo metodo valuta tutti gli attributi di convalida applicati all'oggetto. Se l'oggetto presenta errori di convalida, il metodo Create visualizza di nuovo il modulo. Se non sono presenti errori, il metodo salva il nuovo film nel database. Nell'esempio del film, il modulo non viene inviato al server quando vengono rilevati errori di convalida sul lato client; il secondo metodo Create non viene mai chiamato quando sono presenti errori di convalida sul lato client. Se si disabilita JavaScript nel browser, la convalida sul lato client viene disabilitata ed è possibile testare ModelState.IsValid del metodo Create HTTP POST rilevando eventuali errori di convalida.

È possibile impostare un punto di interruzione nel metodo [HttpPost] Create e verificare che il metodo non venga mai chiamato, la convalida sul lato client non invierà i dati del modulo in caso di rilevamento di errori di convalida. Se si disabilita JavaScript nel browser, quindi si invia il modulo con errori, verrà raggiunto il punto di interruzione. Si ottiene comunque la convalida completa senza JavaScript.

L'immagine seguente mostra come disabilitare JavaScript nel browser Firefox.

Firefox: nella scheda Contenuti in Opzioni deselezionare la casella di controllo Abilita Javascript.

La figura seguente illustra come disabilitare JavaScript nel browser Chrome.

Google Chrome: nella sezione Javascript delle impostazioni dei contenuti selezionare l'opzione per non consentire ai siti di eseguire JavaScript.

Dopo avere disabilitato JavaScript, inviare i dati non validi e procedere con il debugger.

Durante il debug su un invio di dati non validi, Intellisense su ModelState.IsValid mostra che il valore è false.

Una parte del Create.cshtml modello di visualizzazione è illustrata nel markup seguente:

<h4>Movie</h4>
<hr />
<div class="row">
    <div class="col-md-4">
        <form asp-action="Create">
            <div asp-validation-summary="ModelOnly" class="text-danger"></div>
            <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>

            @*Markup removed for brevity.*@

Il markup precedente viene usato dai metodi di azione per visualizzare il modulo iniziale e per visualizzarlo nuovamente in caso di errore.

L'helper tag di input usa gli attributi DataAnnotations e produce gli attributi HTML necessari per la convalida jQuery sul lato client. L'helper tag di convalida visualizza gli errori di convalida. Per altre informazioni, vedere Convalida.

L'aspetto molto interessante di questo approccio è che né il controller né il modello di vista Create sono consapevoli delle regole di convalida effettive applicate o dei messaggi di errore specifici visualizzati. Le regole di convalida e le stringhe di errore vengono specificate solo nella classe Movie. Le stesse regole di convalida vengono applicate automaticamente alla vista Edit e ad altri modelli di vista eventualmente creati che modificano il modello.

Se necessario, è possibile modificare la logica di convalida in una posizione tramite l'aggiunta di attributi di convalida al modello, in questo esempio la classe Movie. Non è necessario preoccuparsi dell'incoerenza delle diverse parti dell'applicazione con la modalità di applicazione delle regole perché tutta la logica di convalida verrà definita in un'unica posizione e usata ovunque. In questo modo il codice rimane molto pulito e facile da gestire e sviluppare. Il principio DRY sarà ampiamente rispettato.

Utilizzo degli attributi DataType

Aprire il Movie.cs file ed esaminare la Movie classe . Lo spazio dei nomi System.ComponentModel.DataAnnotations fornisce gli attributi di formattazione oltre al set predefinito di attributi di convalida. È già stato applicato un valore di enumerazione DataType ai campi della data di rilascio e del prezzo. Il codice seguente illustra le proprietà ReleaseDate e Price con l'attributo appropriato DataType.

[Display(Name = "Release Date")]
[DataType(DataType.Date)]
public DateTime ReleaseDate { get; set; }

[Range(1, 100)]
[DataType(DataType.Currency)]
[Column(TypeName = "decimal(18, 2)")]
public decimal Price { get; set; }    

Gli DataType attributi forniscono solo suggerimenti per il motore di visualizzazione per formattare i dati e fornire elementi/attributi, ad <a> esempio per l'URL e <a href="mailto:EmailAddress.com"> per il messaggio di posta elettronica. È possibile usare l'attributo RegularExpression per convalidare il formato dei dati. L'attributo DataType viene usato per specificare un tipo di dati più specifico del tipo intrinseco del database; non si tratta di attributi di convalida. In questo caso si vuole solo tenere traccia della data, non dell'ora. L'enumerazione DataType fornisce molti tipi di dati, ad esempio Data, Ora, Numero di telefono, Valuta, Indirizzo di posta elettronica e altro ancora. L'attributo DataType può anche consentire all'applicazione di fornire automaticamente le funzionalità specifiche del tipo. Ad esempio, è possibile creare un collegamento mailto: per DataType.EmailAddress e fornire un selettore data per DataType.Date nei browser che supportano HTML5. Gli attributi DataType generano attributi data- HTML5 (pronunciato data dash) supportati dai browser HTML5. Gli attributi DataTypenon forniscono alcuna convalida.

DataType.Date non specifica il formato della data visualizzata. Per impostazione predefinita, il campo dei dati viene visualizzato in base ai formati predefiniti per il valore CultureInfo del server.

L'attributo DisplayFormat viene usato per specificare in modo esplicito il formato della data:

[DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}", ApplyFormatInEditMode = true)]
public DateTime ReleaseDate { get; set; }

L'impostazione ApplyFormatInEditMode specifica che la formattazione deve essere applicata anche quando il valore viene visualizzato in una casella di testo per la modifica. Questa scelta non è consigliabile per alcuni campi, ad esempio per i valori della valuta poiché non è opportuno che il simbolo di valuta sia inserito nella casella di testo per la modifica.

È possibile usare l'attributo DisplayFormat da solo, ma in genere è consigliabile usare l'attributo DataType. L'attributo DataType fornisce la semantica dei dati anziché la modalità di esecuzione del rendering in una schermata e fornisce i seguenti vantaggi che non si ottengono con DisplayFormat:

  • Il browser può abilitare le funzionalità HTML5, ad esempio visualizzare un controllo di calendario, il simbolo della valuta appropriato per le impostazioni locali, i collegamenti alla posta elettronica e così via.

  • Per impostazione predefinita, il browser eseguirà il rendering dei dati usando il formato corretto in base alle impostazioni locali del sistema.

  • L'attributo DataType consente di abilitare MVC in modo da scegliere il modello di campo corretto per il rendering dei dati (DisplayFormat, se usato da solo, usa il modello di stringa).

Nota

La convalida jQuery non funziona con l'attributo Range e con DateTime. Ad esempio, il codice seguente visualizzerà sempre un errore di convalida sul lato client, anche quando la data è compreso nell'intervallo specificato:

[Range(typeof(DateTime), "1/1/1966", "1/1/2020")]

È necessario disabilitare la convalida della data jQuery per usare l'attributo Range con DateTime. In genere non è consigliabile compilare date reali nei modelli, quindi l'uso dell'attributo Range e di DateTime è sconsigliato.

Il codice seguente illustra la combinazione di attributi in una sola riga:

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

namespace MvcMovie.Models;

public class Movie
{
    public int Id { get; set; }
    [StringLength(60, MinimumLength = 3)]
    public string Title { get; set; }
    [Display(Name = "Release Date"), DataType(DataType.Date)]
    public DateTime ReleaseDate { get; set; }
    [RegularExpression(@"^[A-Z]+[a-zA-Z\s]*$"), Required, StringLength(30)]
    public string Genre { get; set; }
    [Range(1, 100), DataType(DataType.Currency)]
    [Column(TypeName = "decimal(18, 2)")]
    public decimal Price { get; set; }
    [RegularExpression(@"^[A-Z]+[a-zA-Z0-9""'\s-]*$"), StringLength(5)]
    public string Rating { get; set; }
}

Nella parte successiva della serie viene esaminata l'app e vengono apportati alcuni miglioramenti ai metodi Details e Delete generati automaticamente.

Risorse aggiuntive

Contenuto della sezione:

  • La logica di convalida viene aggiunta al modello Movie.
  • Si verifica che le regole di convalida vengano applicate ogni volta che un utente crea o modifica un film.

Rispetto del principio DRY

Uno dei principi di progettazione MVC è DRY ("Don't Repeat Yourself"). ASP.NET Core MVC promuove la specifica delle funzionalità o del comportamento una sola volta, con successiva applicazione ovunque in un'app. In questo modo si riduce la quantità di codice che è necessario scrivere e si rende il codice meno soggetto a errori, più semplice da testare e gestire.

Il supporto della convalida fornito da MVC ed Entity Framework Core Code First è un valido esempio pratico del principio DRY. È possibile specificare in modo dichiarativo le regole di convalida in un'unica posizione (nella classe del modello) e le regole vengono applicate ovunque nell'app.

Eliminare i dati modificati in precedenza

Nel passaggio successivo vengono aggiunte regole di convalida che non consentono valori Null. Eseguire l'app, passare a /Movies/Index, eliminare tutti i film elencati e arrestare l'app. L'app userà i dati di inizializzazione alla successiva esecuzione.

Aggiungere regole di convalida al modello movie

Lo spazio dei nomi DataAnnotations offre un set di attributi di convalida predefiniti che vengono applicati in modo dichiarativo a una classe o una proprietà. DataAnnotations contiene anche gli attributi di formattazione come DataType che guidano nella formattazione e non offrono alcuna convalida.

Aggiornare la Movie classe per sfruttare i vantaggi degli attributi Requireddi convalida predefiniti , , RegularExpressionStringLengthRange e dell'attributo DataType di formattazione.

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

namespace MvcMovie.Models;

public class Movie
{
    public int Id { get; set; }

    [StringLength(60, MinimumLength = 3)]
    [Required]
    public string? Title { get; set; }

    [Display(Name = "Release Date")]
    [DataType(DataType.Date)]
    public DateTime ReleaseDate { get; set; }

    [Range(1, 100)]
    [DataType(DataType.Currency)]
    [Column(TypeName = "decimal(18, 2)")]
    public decimal Price { get; set; }    

    [RegularExpression(@"^[A-Z]+[a-zA-Z\s]*$")]
    [Required]
    [StringLength(30)]
    public string? Genre { get; set; }

    [RegularExpression(@"^[A-Z]+[a-zA-Z0-9""'\s-]*$")]
    [StringLength(5)]
    [Required]
    public string? Rating { get; set; }
}

Gli attributi di convalida specificano il comportamento da implementare nelle proprietà del modello a cui vengono applicati:

  • Gli attributi Required e MinimumLength indicano che una proprietà deve avere un valore, ma nulla impedisce all'utente di inserire spazi vuoti per soddisfare questa convalida.

  • L'attributo RegularExpression viene usato per limitare i caratteri che possono essere inseriti. Nel codice precedente "Genre":

    • Deve includere solo lettere.
    • La prima lettera deve essere maiuscola. Gli spazi vuoti sono consentiti mentre i numeri e i caratteri speciali non sono consentiti.
  • RegularExpression "Rating":

    • Richiede che il primo carattere sia una lettera maiuscola.
    • Consente i caratteri speciali e i numeri negli spazi successivi. "PG-13" è valido per una classificazione, ma non per "Genre".
  • L'attributo Range vincola un valore all'interno di un intervallo specificato.

  • L'attributo StringLength consente di impostare la lunghezza massima di una proprietà stringa e, facoltativamente, la lunghezza minima.

  • I tipi di valore, ad esempio decimal, int, float e DateTime, sono intrinsecamente necessari e non richiedono l'attributo [Required].

L'applicazione automatica di regole di convalida da ASP.NET Core è utile per rendere un'app più solida. In questo modo inoltre non è possibile omettere la convalida di un elemento e quindi inserire involontariamente dati errati nel database.

Interfaccia utente dell'errore di convalida

Eseguire l'app e passare al controller di film.

Selezionare il collegamento Crea nuovo per aggiungere un nuovo film. Completare il modulo con alcuni valori non validi. Non appena la convalida del lato client jQuery rileva l'errore, viene visualizzato un messaggio di errore.

Modulo di vista del film con diversi errori di convalida sul lato client jQuery

Nota

È possibile che non si riesca a immettere virgole decimali nel campo. Per supportare la convalida jQuery per impostazioni locali diverse dall'inglese che usano la virgola (",") come separatore decimale e per formati di data diversi da quello dell'inglese degli Stati Uniti, è necessario eseguire alcuni passaggi per globalizzare l'app. Per istruzioni sull'aggiunta di una virgola decimale, vedere questo commento di GitHub 4076 .

Si noti come il modulo ha eseguito automaticamente il rendering di un messaggio di errore di convalida appropriato in ogni campo contenente un valore non valido. Gli errori vengono applicati sia sul lato client (utilizzo di JavaScript e jQuery) sia sul lato server (nel caso di un utente con JavaScript disabilitato).

Un vantaggio significativo è che non è necessario modificare una singola riga di codice nella MoviesController classe o nella Create.cshtml visualizzazione per abilitare questa interfaccia utente di convalida. Il controller e le viste creati in una fase precedente di questa esercitazione hanno selezionato automaticamente le regole di convalida specificate usando gli attributi di convalida delle proprietà della classe Movie del modello. Eseguire il test della convalida usando il metodo di azione Edit e viene applicata la stessa convalida.

I dati del modulo non vengono inviati al server fino a quando non sono più presenti errori di convalida sul lato client. È possibile verificare questa condizione inserendo un punto di interruzione nel metodo HTTP Post usando lo strumento Fiddler o gli strumenti di sviluppo F12.

Funzionamento della convalida

Ci si potrebbe chiedere come la convalida dell'interfaccia utente sia stata generata senza aggiornamenti al codice nel controller o nelle viste. Il codice seguente mostra i due metodi Create.

// GET: Movies/Create
public IActionResult Create()
{
    return View();
}

// POST: Movies/Create
// 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> Create([Bind("Id,Title,ReleaseDate,Genre,Price,Rating")] Movie movie)
{
    if (ModelState.IsValid)
    {
        _context.Add(movie);
        await _context.SaveChangesAsync();
        return RedirectToAction(nameof(Index));
    }
    return View(movie);
}

Il primo metodo di azione (HTTP GET) Create visualizza il modulo di creazione iniziale. La seconda versione ([HttpPost]) gestisce l'invio del modulo. Il secondo metodo Create (la versione [HttpPost]) chiama ModelState.IsValid per verificare se esistono errori di convalida per il film. La chiamata a questo metodo valuta tutti gli attributi di convalida applicati all'oggetto. Se l'oggetto presenta errori di convalida, il metodo Create visualizza di nuovo il modulo. Se non sono presenti errori, il metodo salva il nuovo film nel database. Nell'esempio del film, il modulo non viene inviato al server quando vengono rilevati errori di convalida sul lato client; il secondo metodo Create non viene mai chiamato quando sono presenti errori di convalida sul lato client. Se si disabilita JavaScript nel browser, la convalida sul lato client viene disabilitata ed è possibile testare ModelState.IsValid del metodo Create HTTP POST rilevando eventuali errori di convalida.

È possibile impostare un punto di interruzione nel metodo [HttpPost] Create e verificare che il metodo non venga mai chiamato, la convalida sul lato client non invierà i dati del modulo in caso di rilevamento di errori di convalida. Se si disabilita JavaScript nel browser, quindi si invia il modulo con errori, verrà raggiunto il punto di interruzione. Si ottiene comunque la convalida completa senza JavaScript.

L'immagine seguente mostra come disabilitare JavaScript nel browser Firefox.

Firefox: nella scheda Contenuti in Opzioni deselezionare la casella di controllo Abilita Javascript.

La figura seguente illustra come disabilitare JavaScript nel browser Chrome.

Google Chrome: nella sezione Javascript delle impostazioni dei contenuti selezionare l'opzione per non consentire ai siti di eseguire JavaScript.

Dopo avere disabilitato JavaScript, inviare i dati non validi e procedere con il debugger.

Durante il debug su un invio di dati non validi, Intellisense su ModelState.IsValid mostra che il valore è false.

Una parte del Create.cshtml modello di visualizzazione è illustrata nel markup seguente:

<h4>Movie</h4>
<hr />
<div class="row">
    <div class="col-md-4">
        <form asp-action="Create">
            <div asp-validation-summary="ModelOnly" class="text-danger"></div>
            <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>

            @*Markup removed for brevity.*@

Il markup precedente viene usato dai metodi di azione per visualizzare il modulo iniziale e per visualizzarlo nuovamente in caso di errore.

L'helper tag di input usa gli attributi DataAnnotations e produce gli attributi HTML necessari per la convalida jQuery sul lato client. L'helper tag di convalida visualizza gli errori di convalida. Per altre informazioni, vedere Convalida.

L'aspetto molto interessante di questo approccio è che né il controller né il modello di vista Create sono consapevoli delle regole di convalida effettive applicate o dei messaggi di errore specifici visualizzati. Le regole di convalida e le stringhe di errore vengono specificate solo nella classe Movie. Le stesse regole di convalida vengono applicate automaticamente alla vista Edit e ad altri modelli di vista eventualmente creati che modificano il modello.

Se necessario, è possibile modificare la logica di convalida in una posizione tramite l'aggiunta di attributi di convalida al modello, in questo esempio la classe Movie. Non è necessario preoccuparsi dell'incoerenza delle diverse parti dell'applicazione con la modalità di applicazione delle regole perché tutta la logica di convalida verrà definita in un'unica posizione e usata ovunque. In questo modo il codice rimane molto pulito e facile da gestire e sviluppare. Il principio DRY sarà ampiamente rispettato.

Utilizzo degli attributi DataType

Aprire il Movie.cs file ed esaminare la Movie classe . Lo spazio dei nomi System.ComponentModel.DataAnnotations fornisce gli attributi di formattazione oltre al set predefinito di attributi di convalida. È già stato applicato un valore di enumerazione DataType ai campi della data di rilascio e del prezzo. Il codice seguente illustra le proprietà ReleaseDate e Price con l'attributo appropriato DataType.

[Display(Name = "Release Date")]
[DataType(DataType.Date)]
public DateTime ReleaseDate { get; set; }

[Range(1, 100)]
[DataType(DataType.Currency)]
[Column(TypeName = "decimal(18, 2)")]
public decimal Price { get; set; }    

Gli DataType attributi forniscono solo suggerimenti per il motore di visualizzazione per formattare i dati e fornire elementi/attributi, ad <a> esempio per l'URL e <a href="mailto:EmailAddress.com"> per il messaggio di posta elettronica. È possibile usare l'attributo RegularExpression per convalidare il formato dei dati. L'attributo DataType viene usato per specificare un tipo di dati più specifico del tipo intrinseco del database; non si tratta di attributi di convalida. In questo caso si vuole solo tenere traccia della data, non dell'ora. L'enumerazione DataType fornisce molti tipi di dati, ad esempio Data, Ora, Numero di telefono, Valuta, Indirizzo di posta elettronica e altro ancora. L'attributo DataType può anche consentire all'applicazione di fornire automaticamente le funzionalità specifiche del tipo. Ad esempio, è possibile creare un collegamento mailto: per DataType.EmailAddress e fornire un selettore data per DataType.Date nei browser che supportano HTML5. Gli attributi DataType generano attributi data- HTML5 (pronunciato data dash) supportati dai browser HTML5. Gli attributi DataTypenon forniscono alcuna convalida.

DataType.Date non specifica il formato della data visualizzata. Per impostazione predefinita, il campo dei dati viene visualizzato in base ai formati predefiniti per il valore CultureInfo del server.

L'attributo DisplayFormat viene usato per specificare in modo esplicito il formato della data:

[DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}", ApplyFormatInEditMode = true)]
public DateTime ReleaseDate { get; set; }

L'impostazione ApplyFormatInEditMode specifica che la formattazione deve essere applicata anche quando il valore viene visualizzato in una casella di testo per la modifica. Questa scelta non è consigliabile per alcuni campi, ad esempio per i valori della valuta poiché non è opportuno che il simbolo di valuta sia inserito nella casella di testo per la modifica.

È possibile usare l'attributo DisplayFormat da solo, ma in genere è consigliabile usare l'attributo DataType. L'attributo DataType fornisce la semantica dei dati anziché la modalità di esecuzione del rendering in una schermata e fornisce i seguenti vantaggi che non si ottengono con DisplayFormat:

  • Il browser può abilitare le funzionalità HTML5, ad esempio visualizzare un controllo di calendario, il simbolo della valuta appropriato per le impostazioni locali, i collegamenti alla posta elettronica e così via.

  • Per impostazione predefinita, il browser eseguirà il rendering dei dati usando il formato corretto in base alle impostazioni locali del sistema.

  • L'attributo DataType consente di abilitare MVC in modo da scegliere il modello di campo corretto per il rendering dei dati (DisplayFormat, se usato da solo, usa il modello di stringa).

Nota

La convalida jQuery non funziona con l'attributo Range e con DateTime. Ad esempio, il codice seguente visualizzerà sempre un errore di convalida sul lato client, anche quando la data è compreso nell'intervallo specificato:

[Range(typeof(DateTime), "1/1/1966", "1/1/2020")]

È necessario disabilitare la convalida della data jQuery per usare l'attributo Range con DateTime. In genere non è consigliabile compilare date reali nei modelli, quindi l'uso dell'attributo Range e di DateTime è sconsigliato.

Il codice seguente illustra la combinazione di attributi in una sola riga:

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

namespace MvcMovie.Models;

public class Movie
{
    public int Id { get; set; }
    [StringLength(60, MinimumLength = 3)]
    public string Title { get; set; }
    [Display(Name = "Release Date"), DataType(DataType.Date)]
    public DateTime ReleaseDate { get; set; }
    [RegularExpression(@"^[A-Z]+[a-zA-Z\s]*$"), Required, StringLength(30)]
    public string Genre { get; set; }
    [Range(1, 100), DataType(DataType.Currency)]
    [Column(TypeName = "decimal(18, 2)")]
    public decimal Price { get; set; }
    [RegularExpression(@"^[A-Z]+[a-zA-Z0-9""'\s-]*$"), StringLength(5)]
    public string Rating { get; set; }
}

Nella parte successiva della serie viene esaminata l'app e vengono apportati alcuni miglioramenti ai metodi Details e Delete generati automaticamente.

Risorse aggiuntive

Contenuto della sezione:

  • La logica di convalida viene aggiunta al modello Movie.
  • Si verifica che le regole di convalida vengano applicate ogni volta che un utente crea o modifica un film.

Rispetto del principio DRY

Uno dei principi di progettazione MVC è DRY ("Don't Repeat Yourself"). ASP.NET Core MVC promuove la specifica delle funzionalità o del comportamento una sola volta, con successiva applicazione ovunque in un'app. In questo modo si riduce la quantità di codice che è necessario scrivere e si rende il codice meno soggetto a errori, più semplice da testare e gestire.

Il supporto della convalida fornito da MVC ed Entity Framework Core Code First è un valido esempio pratico del principio DRY. È possibile specificare in modo dichiarativo le regole di convalida in un'unica posizione (nella classe del modello) e le regole vengono applicate ovunque nell'app.

Aggiungere regole di convalida al modello movie

Lo spazio dei nomi DataAnnotations offre un set di attributi di convalida predefiniti che vengono applicati in modo dichiarativo a una classe o una proprietà. DataAnnotations contiene anche gli attributi di formattazione come DataType che guidano nella formattazione e non offrono alcuna convalida.

Aggiornare la Movie classe per sfruttare i vantaggi degli attributi Requireddi convalida predefiniti , , RegularExpressionStringLengthRange e dell'attributo DataType di formattazione.

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

namespace MvcMovie.Models;

public class Movie
{
    public int Id { get; set; }

    [StringLength(60, MinimumLength = 3)]
    [Required]
    public string? Title { get; set; }

    [Display(Name = "Release Date")]
    [DataType(DataType.Date)]
    public DateTime ReleaseDate { get; set; }

    [Range(1, 100)]
    [DataType(DataType.Currency)]
    [Column(TypeName = "decimal(18, 2)")]
    public decimal Price { get; set; }    

    [RegularExpression(@"^[A-Z]+[a-zA-Z\s]*$")]
    [Required]
    [StringLength(30)]
    public string? Genre { get; set; }
    
    [RegularExpression(@"^[A-Z]+[a-zA-Z0-9""'\s-]*$")]
    [StringLength(5)]
    [Required]
    public string? Rating { get; set; }
}

Gli attributi di convalida specificano il comportamento da implementare nelle proprietà del modello a cui vengono applicati:

  • Gli attributi Required e MinimumLength indicano che una proprietà deve avere un valore, ma nulla impedisce all'utente di inserire spazi vuoti per soddisfare questa convalida.

  • L'attributo RegularExpression viene usato per limitare i caratteri che possono essere inseriti. Nel codice precedente "Genre":

    • Deve includere solo lettere.
    • La prima lettera deve essere maiuscola. Gli spazi vuoti sono consentiti mentre i numeri e i caratteri speciali non sono consentiti.
  • RegularExpression "Rating":

    • Richiede che il primo carattere sia una lettera maiuscola.
    • Consente i caratteri speciali e i numeri negli spazi successivi. "PG-13" è valido per una classificazione, ma non per "Genre".
  • L'attributo Range vincola un valore all'interno di un intervallo specificato.

  • L'attributo StringLength consente di impostare la lunghezza massima di una proprietà stringa e, facoltativamente, la lunghezza minima.

  • I tipi di valore, ad esempio decimal, int, float e DateTime, sono intrinsecamente necessari e non richiedono l'attributo [Required].

L'applicazione automatica di regole di convalida da ASP.NET Core è utile per rendere un'app più solida. In questo modo inoltre non è possibile omettere la convalida di un elemento e quindi inserire involontariamente dati errati nel database.

Interfaccia utente dell'errore di convalida

Eseguire l'app e passare al controller di film.

Selezionare il collegamento Crea nuovo per aggiungere un nuovo film. Completare il modulo con alcuni valori non validi. Non appena la convalida del lato client jQuery rileva l'errore, viene visualizzato un messaggio di errore.

Modulo di vista del film con diversi errori di convalida sul lato client jQuery

Nota

È possibile che non si riesca a immettere virgole decimali nel campo. Per supportare la convalida jQuery per impostazioni locali diverse dall'inglese che usano la virgola (",") come separatore decimale e per formati di data diversi da quello dell'inglese degli Stati Uniti, è necessario eseguire alcuni passaggi per globalizzare l'app. Per istruzioni sull'aggiunta di una virgola decimale, vedere questo commento di GitHub 4076 .

Si noti come il modulo ha eseguito automaticamente il rendering di un messaggio di errore di convalida appropriato in ogni campo contenente un valore non valido. Gli errori vengono applicati sia sul lato client (utilizzo di JavaScript e jQuery) sia sul lato server (nel caso di un utente con JavaScript disabilitato).

Un vantaggio significativo è che non è necessario modificare una singola riga di codice nella MoviesController classe o nella Create.cshtml visualizzazione per abilitare questa interfaccia utente di convalida. Il controller e le viste creati in una fase precedente di questa esercitazione hanno selezionato automaticamente le regole di convalida specificate usando gli attributi di convalida delle proprietà della classe Movie del modello. Eseguire il test della convalida usando il metodo di azione Edit e viene applicata la stessa convalida.

I dati del modulo non vengono inviati al server fino a quando non sono più presenti errori di convalida sul lato client. È possibile verificare questa condizione inserendo un punto di interruzione nel metodo HTTP Post usando lo strumento Fiddler o gli strumenti di sviluppo F12.

Funzionamento della convalida

Ci si potrebbe chiedere come la convalida dell'interfaccia utente sia stata generata senza aggiornamenti al codice nel controller o nelle viste. Il codice seguente mostra i due metodi Create.

// GET: Movies/Create
public IActionResult Create()
{
    return View();
}

// POST: Movies/Create
// 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> Create([Bind("Id,Title,ReleaseDate,Genre,Price,Rating")] Movie movie)
{
    if (ModelState.IsValid)
    {
        _context.Add(movie);
        await _context.SaveChangesAsync();
        return RedirectToAction(nameof(Index));
    }
    return View(movie);
}

Il primo metodo di azione (HTTP GET) Create visualizza il modulo di creazione iniziale. La seconda versione ([HttpPost]) gestisce l'invio del modulo. Il secondo metodo Create (la versione [HttpPost]) chiama ModelState.IsValid per verificare se esistono errori di convalida per il film. La chiamata a questo metodo valuta tutti gli attributi di convalida applicati all'oggetto. Se l'oggetto presenta errori di convalida, il metodo Create visualizza di nuovo il modulo. Se non sono presenti errori, il metodo salva il nuovo film nel database. Nell'esempio del film, il modulo non viene inviato al server quando vengono rilevati errori di convalida sul lato client; il secondo metodo Create non viene mai chiamato quando sono presenti errori di convalida sul lato client. Se si disabilita JavaScript nel browser, la convalida sul lato client viene disabilitata ed è possibile testare ModelState.IsValid del metodo Create HTTP POST rilevando eventuali errori di convalida.

È possibile impostare un punto di interruzione nel metodo [HttpPost] Create e verificare che il metodo non venga mai chiamato, la convalida sul lato client non invierà i dati del modulo in caso di rilevamento di errori di convalida. Se si disabilita JavaScript nel browser, quindi si invia il modulo con errori, verrà raggiunto il punto di interruzione. Si ottiene comunque la convalida completa senza JavaScript.

L'immagine seguente mostra come disabilitare JavaScript nel browser Firefox.

Firefox: nella scheda Contenuti in Opzioni deselezionare la casella di controllo Abilita Javascript.

La figura seguente illustra come disabilitare JavaScript nel browser Chrome.

Google Chrome: nella sezione Javascript delle impostazioni dei contenuti selezionare l'opzione per non consentire ai siti di eseguire JavaScript.

Dopo avere disabilitato JavaScript, inviare i dati non validi e procedere con il debugger.

Durante il debug su un invio di dati non validi, Intellisense su ModelState.IsValid mostra che il valore è false.

Una parte del Create.cshtml modello di visualizzazione è illustrata nel markup seguente:

<h4>Movie</h4>
<hr />
<div class="row">
    <div class="col-md-4">
        <form asp-action="Create">
            <div asp-validation-summary="ModelOnly" class="text-danger"></div>
            <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>

            @*Markup removed for brevity.*@

Il markup precedente viene usato dai metodi di azione per visualizzare il modulo iniziale e per visualizzarlo nuovamente in caso di errore.

L'helper tag di input usa gli attributi DataAnnotations e produce gli attributi HTML necessari per la convalida jQuery sul lato client. L'helper tag di convalida visualizza gli errori di convalida. Per altre informazioni, vedere Convalida.

L'aspetto molto interessante di questo approccio è che né il controller né il modello di vista Create sono consapevoli delle regole di convalida effettive applicate o dei messaggi di errore specifici visualizzati. Le regole di convalida e le stringhe di errore vengono specificate solo nella classe Movie. Le stesse regole di convalida vengono applicate automaticamente alla vista Edit e ad altri modelli di vista eventualmente creati che modificano il modello.

Se necessario, è possibile modificare la logica di convalida in una posizione tramite l'aggiunta di attributi di convalida al modello, in questo esempio la classe Movie. Non è necessario preoccuparsi dell'incoerenza delle diverse parti dell'applicazione con la modalità di applicazione delle regole perché tutta la logica di convalida verrà definita in un'unica posizione e usata ovunque. In questo modo il codice rimane molto pulito e facile da gestire e sviluppare. Il principio DRY sarà ampiamente rispettato.

Utilizzo degli attributi DataType

Aprire il Movie.cs file ed esaminare la Movie classe . Lo spazio dei nomi System.ComponentModel.DataAnnotations fornisce gli attributi di formattazione oltre al set predefinito di attributi di convalida. È già stato applicato un valore di enumerazione DataType ai campi della data di rilascio e del prezzo. Il codice seguente illustra le proprietà ReleaseDate e Price con l'attributo appropriato DataType.

[Display(Name = "Release Date")]
[DataType(DataType.Date)]
public DateTime ReleaseDate { get; set; }

[Range(1, 100)]
[DataType(DataType.Currency)]
[Column(TypeName = "decimal(18, 2)")]
public decimal Price { get; set; }    

Gli DataType attributi forniscono solo suggerimenti per il motore di visualizzazione per formattare i dati e fornire elementi/attributi, ad <a> esempio per l'URL e <a href="mailto:EmailAddress.com"> per il messaggio di posta elettronica. È possibile usare l'attributo RegularExpression per convalidare il formato dei dati. L'attributo DataType viene usato per specificare un tipo di dati più specifico del tipo intrinseco del database; non si tratta di attributi di convalida. In questo caso si vuole solo tenere traccia della data, non dell'ora. L'enumerazione DataType fornisce molti tipi di dati, ad esempio Data, Ora, Numero di telefono, Valuta, Indirizzo di posta elettronica e altro ancora. L'attributo DataType può anche consentire all'applicazione di fornire automaticamente le funzionalità specifiche del tipo. Ad esempio, è possibile creare un collegamento mailto: per DataType.EmailAddress e fornire un selettore data per DataType.Date nei browser che supportano HTML5. Gli attributi DataType generano attributi data- HTML5 (pronunciato data dash) supportati dai browser HTML5. Gli attributi DataTypenon forniscono alcuna convalida.

DataType.Date non specifica il formato della data visualizzata. Per impostazione predefinita, il campo dei dati viene visualizzato in base ai formati predefiniti per il valore CultureInfo del server.

L'attributo DisplayFormat viene usato per specificare in modo esplicito il formato della data:

[DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}", ApplyFormatInEditMode = true)]
public DateTime ReleaseDate { get; set; }

L'impostazione ApplyFormatInEditMode specifica che la formattazione deve essere applicata anche quando il valore viene visualizzato in una casella di testo per la modifica. Questa scelta non è consigliabile per alcuni campi, ad esempio per i valori della valuta poiché non è opportuno che il simbolo di valuta sia inserito nella casella di testo per la modifica.

È possibile usare l'attributo DisplayFormat da solo, ma in genere è consigliabile usare l'attributo DataType. L'attributo DataType fornisce la semantica dei dati anziché la modalità di esecuzione del rendering in una schermata e fornisce i seguenti vantaggi che non si ottengono con DisplayFormat:

  • Il browser può abilitare le funzionalità HTML5, ad esempio visualizzare un controllo di calendario, il simbolo della valuta appropriato per le impostazioni locali, i collegamenti alla posta elettronica e così via.

  • Per impostazione predefinita, il browser eseguirà il rendering dei dati usando il formato corretto in base alle impostazioni locali del sistema.

  • L'attributo DataType consente di abilitare MVC in modo da scegliere il modello di campo corretto per il rendering dei dati (DisplayFormat, se usato da solo, usa il modello di stringa).

Nota

La convalida jQuery non funziona con l'attributo Range e con DateTime. Ad esempio, il codice seguente visualizzerà sempre un errore di convalida sul lato client, anche quando la data è compreso nell'intervallo specificato:

[Range(typeof(DateTime), "1/1/1966", "1/1/2020")]

È necessario disabilitare la convalida della data jQuery per usare l'attributo Range con DateTime. In genere non è consigliabile compilare date reali nei modelli, quindi l'uso dell'attributo Range e di DateTime è sconsigliato.

Il codice seguente illustra la combinazione di attributi in una sola riga:

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

namespace MvcMovie.Models;

public class Movie
{
    public int Id { get; set; }
    [StringLength(60, MinimumLength = 3)]
    public string Title { get; set; }
    [Display(Name = "Release Date"), DataType(DataType.Date)]
    public DateTime ReleaseDate { get; set; }
    [RegularExpression(@"^[A-Z]+[a-zA-Z\s]*$"), Required, StringLength(30)]
    public string Genre { get; set; }
    [Range(1, 100), DataType(DataType.Currency)]
    [Column(TypeName = "decimal(18, 2)")]
    public decimal Price { get; set; }
    [RegularExpression(@"^[A-Z]+[a-zA-Z0-9""'\s-]*$"), StringLength(5)]
    public string Rating { get; set; }
}

Nella parte successiva della serie viene esaminata l'app e vengono apportati alcuni miglioramenti ai metodi Details e Delete generati automaticamente.

Risorse aggiuntive

Contenuto della sezione:

  • La logica di convalida viene aggiunta al modello Movie.
  • Si verifica che le regole di convalida vengano applicate ogni volta che un utente crea o modifica un film.

Rispetto del principio DRY

Uno dei principi di progettazione MVC è DRY ("Don't Repeat Yourself"). ASP.NET Core MVC promuove la specifica delle funzionalità o del comportamento una sola volta, con successiva applicazione ovunque in un'app. In questo modo si riduce la quantità di codice che è necessario scrivere e si rende il codice meno soggetto a errori, più semplice da testare e gestire.

Il supporto della convalida fornito da MVC ed Entity Framework Core Code First è un valido esempio pratico del principio DRY. È possibile specificare in modo dichiarativo le regole di convalida in un'unica posizione (nella classe del modello) e le regole vengono applicate ovunque nell'app.

Aggiungere regole di convalida al modello movie

Lo spazio dei nomi DataAnnotations offre un set di attributi di convalida predefiniti che vengono applicati in modo dichiarativo a una classe o una proprietà. DataAnnotations contiene anche gli attributi di formattazione come DataType che guidano nella formattazione e non offrono alcuna convalida.

Aggiornare la classe Movie per poter sfruttare gli attributi di convalida Required, StringLength, RegularExpression e Range predefiniti.

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

namespace MvcMovie.Models
{
    public class Movie
    {
        public int Id { get; set; }

        [StringLength(60, MinimumLength = 3)]
        [Required]
        public string? Title { get; set; }

        [Display(Name = "Release Date")]
        [DataType(DataType.Date)]
        public DateTime ReleaseDate { get; set; }

        [Range(1, 100)]
        [DataType(DataType.Currency)]
        [Column(TypeName = "decimal(18, 2)")]
        public decimal Price { get; set; }

        [RegularExpression(@"^[A-Z]+[a-zA-Z\s]*$")]
        [Required]
        [StringLength(30)]
        public string? Genre { get; set; }

        [RegularExpression(@"^[A-Z]+[a-zA-Z0-9""'\s-]*$")]
        [StringLength(5)]
        [Required]
        public string? Rating { get; set; }
    }
}

Gli attributi di convalida specificano il comportamento da implementare nelle proprietà del modello a cui vengono applicati:

  • Gli attributi Required e MinimumLength indicano che una proprietà deve avere un valore, ma nulla impedisce all'utente di inserire spazi vuoti per soddisfare questa convalida.

  • L'attributo RegularExpression viene usato per limitare i caratteri che possono essere inseriti. Nel codice precedente "Genre":

    • Deve includere solo lettere.
    • La prima lettera deve essere maiuscola. Gli spazi vuoti sono consentiti mentre i numeri e i caratteri speciali non sono consentiti.
  • RegularExpression "Rating":

    • Richiede che il primo carattere sia una lettera maiuscola.
    • Consente i caratteri speciali e i numeri negli spazi successivi. "PG-13" è valido per una classificazione, ma non per "Genre".
  • L'attributo Range vincola un valore all'interno di un intervallo specificato.

  • L'attributo StringLength consente di impostare la lunghezza massima di una proprietà stringa e, facoltativamente, la lunghezza minima.

  • I tipi di valore, ad esempio decimal, int, float e DateTime, sono intrinsecamente necessari e non richiedono l'attributo [Required].

L'applicazione automatica di regole di convalida da ASP.NET Core è utile per rendere un'app più solida. In questo modo inoltre non è possibile omettere la convalida di un elemento e quindi inserire involontariamente dati errati nel database.

Interfaccia utente dell'errore di convalida

Eseguire l'app e passare al controller di film.

Selezionare il collegamento Crea nuovo per aggiungere un nuovo film. Completare il modulo con alcuni valori non validi. Non appena la convalida del lato client jQuery rileva l'errore, viene visualizzato un messaggio di errore.

Modulo di vista del film con diversi errori di convalida sul lato client jQuery

Nota

È possibile che non si riesca a immettere virgole decimali nel campo. Per supportare la convalida jQuery per impostazioni locali diverse dall'inglese che usano la virgola (",") come separatore decimale e per formati di data diversi da quello dell'inglese degli Stati Uniti, è necessario eseguire alcuni passaggi per globalizzare l'app. Per istruzioni sull'aggiunta di una virgola decimale, vedere questo commento di GitHub 4076 .

Si noti come il modulo ha eseguito automaticamente il rendering di un messaggio di errore di convalida appropriato in ogni campo contenente un valore non valido. Gli errori vengono applicati sia sul lato client (utilizzo di JavaScript e jQuery) sia sul lato server (nel caso di un utente con JavaScript disabilitato).

Un vantaggio significativo è che non è necessario modificare una singola riga di codice nella MoviesController classe o nella Create.cshtml visualizzazione per abilitare questa interfaccia utente di convalida. Il controller e le viste creati in una fase precedente di questa esercitazione hanno selezionato automaticamente le regole di convalida specificate usando gli attributi di convalida delle proprietà della classe Movie del modello. Eseguire il test della convalida usando il metodo di azione Edit e viene applicata la stessa convalida.

I dati del modulo non vengono inviati al server fino a quando non sono più presenti errori di convalida sul lato client. È possibile verificare questa condizione inserendo un punto di interruzione nel metodo HTTP Post usando lo strumento Fiddler o gli strumenti di sviluppo F12.

Funzionamento della convalida

Ci si potrebbe chiedere come la convalida dell'interfaccia utente sia stata generata senza aggiornamenti al codice nel controller o nelle viste. Il codice seguente mostra i due metodi Create.

// GET: Movies/Create
public IActionResult Create()
{
    return View();
}

// POST: Movies/Create
// 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> Create([Bind("Id,Title,ReleaseDate,Genre,Price,Rating")] Movie movie)
{
    if (ModelState.IsValid)
    {
        _context.Add(movie);
        await _context.SaveChangesAsync();
        return RedirectToAction(nameof(Index));
    }
    return View(movie);
}

Il primo metodo di azione (HTTP GET) Create visualizza il modulo di creazione iniziale. La seconda versione ([HttpPost]) gestisce l'invio del modulo. Il secondo metodo Create (la versione [HttpPost]) chiama ModelState.IsValid per verificare se esistono errori di convalida per il film. La chiamata a questo metodo valuta tutti gli attributi di convalida applicati all'oggetto. Se l'oggetto presenta errori di convalida, il metodo Create visualizza di nuovo il modulo. Se non sono presenti errori, il metodo salva il nuovo film nel database. Nell'esempio del film, il modulo non viene inviato al server quando vengono rilevati errori di convalida sul lato client; il secondo metodo Create non viene mai chiamato quando sono presenti errori di convalida sul lato client. Se si disabilita JavaScript nel browser, la convalida sul lato client viene disabilitata ed è possibile testare ModelState.IsValid del metodo Create HTTP POST rilevando eventuali errori di convalida.

È possibile impostare un punto di interruzione nel metodo [HttpPost] Create e verificare che il metodo non venga mai chiamato, la convalida sul lato client non invierà i dati del modulo in caso di rilevamento di errori di convalida. Se si disabilita JavaScript nel browser, quindi si invia il modulo con errori, verrà raggiunto il punto di interruzione. Si ottiene comunque la convalida completa senza JavaScript.

L'immagine seguente mostra come disabilitare JavaScript nel browser Firefox.

Firefox: nella scheda Contenuti in Opzioni deselezionare la casella di controllo Abilita Javascript.

La figura seguente illustra come disabilitare JavaScript nel browser Chrome.

Google Chrome: nella sezione Javascript delle impostazioni dei contenuti selezionare l'opzione per non consentire ai siti di eseguire JavaScript.

Dopo avere disabilitato JavaScript, inviare i dati non validi e procedere con il debugger.

Durante il debug su un invio di dati non validi, Intellisense su ModelState.IsValid mostra che il valore è false.

Una parte del Create.cshtml modello di visualizzazione è illustrata nel markup seguente:

<h4>Movie</h4>
<hr />
<div class="row">
    <div class="col-md-4">
        <form asp-action="Create">
            <div asp-validation-summary="ModelOnly" class="text-danger"></div>
            <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>

            @*Markup removed for brevity.*@

Il markup precedente viene usato dai metodi di azione per visualizzare il modulo iniziale e per visualizzarlo nuovamente in caso di errore.

L'helper tag di input usa gli attributi DataAnnotations e produce gli attributi HTML necessari per la convalida jQuery sul lato client. L'helper tag di convalida visualizza gli errori di convalida. Per altre informazioni, vedere Convalida.

L'aspetto molto interessante di questo approccio è che né il controller né il modello di vista Create sono consapevoli delle regole di convalida effettive applicate o dei messaggi di errore specifici visualizzati. Le regole di convalida e le stringhe di errore vengono specificate solo nella classe Movie. Le stesse regole di convalida vengono applicate automaticamente alla vista Edit e ad altri modelli di vista eventualmente creati che modificano il modello.

Se necessario, è possibile modificare la logica di convalida in una posizione tramite l'aggiunta di attributi di convalida al modello, in questo esempio la classe Movie. Non è necessario preoccuparsi dell'incoerenza delle diverse parti dell'applicazione con la modalità di applicazione delle regole perché tutta la logica di convalida verrà definita in un'unica posizione e usata ovunque. In questo modo il codice rimane molto pulito e facile da gestire e sviluppare. Il principio DRY sarà ampiamente rispettato.

Utilizzo degli attributi DataType

Aprire il Movie.cs file ed esaminare la Movie classe . Lo spazio dei nomi System.ComponentModel.DataAnnotations fornisce gli attributi di formattazione oltre al set predefinito di attributi di convalida. È già stato applicato un valore di enumerazione DataType ai campi della data di rilascio e del prezzo. Il codice seguente illustra le proprietà ReleaseDate e Price con l'attributo appropriato DataType.

[Display(Name = "Release Date")]
[DataType(DataType.Date)]
public DateTime ReleaseDate { get; set; }

[Range(1, 100)]
[DataType(DataType.Currency)]
[Column(TypeName = "decimal(18, 2)")]
public decimal Price { get; set; }

Gli DataType attributi forniscono solo suggerimenti per il motore di visualizzazione per formattare i dati e fornire elementi/attributi, ad <a> esempio per l'URL e <a href="mailto:EmailAddress.com"> per il messaggio di posta elettronica. È possibile usare l'attributo RegularExpression per convalidare il formato dei dati. L'attributo DataType viene usato per specificare un tipo di dati più specifico del tipo intrinseco del database; non si tratta di attributi di convalida. In questo caso si vuole solo tenere traccia della data, non dell'ora. L'enumerazione DataType fornisce molti tipi di dati, ad esempio Data, Ora, Numero di telefono, Valuta, Indirizzo di posta elettronica e altro ancora. L'attributo DataType può anche consentire all'applicazione di fornire automaticamente le funzionalità specifiche del tipo. Ad esempio, è possibile creare un collegamento mailto: per DataType.EmailAddress e fornire un selettore data per DataType.Date nei browser che supportano HTML5. Gli attributi DataType generano attributi data- HTML5 (pronunciato data dash) supportati dai browser HTML5. Gli attributi DataTypenon forniscono alcuna convalida.

DataType.Date non specifica il formato della data visualizzata. Per impostazione predefinita, il campo dei dati viene visualizzato in base ai formati predefiniti per il valore CultureInfo del server.

L'attributo DisplayFormat viene usato per specificare in modo esplicito il formato della data:

[DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}", ApplyFormatInEditMode = true)]
public DateTime ReleaseDate { get; set; }

L'impostazione ApplyFormatInEditMode specifica che la formattazione deve essere applicata anche quando il valore viene visualizzato in una casella di testo per la modifica. Questa scelta non è consigliabile per alcuni campi, ad esempio per i valori della valuta poiché non è opportuno che il simbolo di valuta sia inserito nella casella di testo per la modifica.

È possibile usare l'attributo DisplayFormat da solo, ma in genere è consigliabile usare l'attributo DataType. L'attributo DataType fornisce la semantica dei dati anziché la modalità di esecuzione del rendering in una schermata e fornisce i seguenti vantaggi che non si ottengono con DisplayFormat:

  • Il browser può abilitare le funzionalità HTML5, ad esempio visualizzare un controllo di calendario, il simbolo della valuta appropriato per le impostazioni locali, i collegamenti alla posta elettronica e così via.

  • Per impostazione predefinita, il browser eseguirà il rendering dei dati usando il formato corretto in base alle impostazioni locali del sistema.

  • L'attributo DataType consente di abilitare MVC in modo da scegliere il modello di campo corretto per il rendering dei dati (DisplayFormat, se usato da solo, usa il modello di stringa).

Nota

La convalida jQuery non funziona con l'attributo Range e con DateTime. Ad esempio, il codice seguente visualizzerà sempre un errore di convalida sul lato client, anche quando la data è compreso nell'intervallo specificato:

[Range(typeof(DateTime), "1/1/1966", "1/1/2020")]

È necessario disabilitare la convalida della data jQuery per usare l'attributo Range con DateTime. In genere non è consigliabile compilare date reali nei modelli, quindi l'uso dell'attributo Range e di DateTime è sconsigliato.

Il codice seguente illustra la combinazione di attributi in una sola riga:

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

namespace MvcMovie.Models
{
    public class Movie
    {
        public int Id { get; set; }

        [StringLength(60, MinimumLength = 3)]
        public string Title { get; set; }

        [Display(Name = "Release Date"), DataType(DataType.Date)]
        public DateTime ReleaseDate { get; set; }

        [RegularExpression(@"^[A-Z]+[a-zA-Z\s]*$"), Required, StringLength(30)]
        public string Genre { get; set; }

        [Range(1, 100), DataType(DataType.Currency)]
        [Column(TypeName = "decimal(18, 2)")]
        public decimal Price { get; set; }

        [RegularExpression(@"^[A-Z]+[a-zA-Z0-9""'\s-]*$"), StringLength(5)]
        public string Rating { get; set; }
    }
}

Nella parte successiva della serie viene esaminata l'app e vengono apportati alcuni miglioramenti ai metodi Details e Delete generati automaticamente.

Risorse aggiuntive

Contenuto della sezione:

  • La logica di convalida viene aggiunta al modello Movie.
  • Si verifica che le regole di convalida vengano applicate ogni volta che un utente crea o modifica un film.

Rispetto del principio DRY

Uno dei principi di progettazione MVC è DRY ("Don't Repeat Yourself"). ASP.NET Core MVC promuove la specifica delle funzionalità o del comportamento una sola volta, con successiva applicazione ovunque in un'app. In questo modo si riduce la quantità di codice che è necessario scrivere e si rende il codice meno soggetto a errori, più semplice da testare e gestire.

Il supporto della convalida fornito da MVC ed Entity Framework Core Code First è un valido esempio pratico del principio DRY. È possibile specificare in modo dichiarativo le regole di convalida in un'unica posizione (nella classe del modello) e le regole vengono applicate ovunque nell'app.

Aggiungere regole di convalida al modello movie

Lo spazio dei nomi DataAnnotations offre un set di attributi di convalida predefiniti che vengono applicati in modo dichiarativo a una classe o una proprietà. DataAnnotations contiene anche gli attributi di formattazione come DataType che guidano nella formattazione e non offrono alcuna convalida.

Aggiornare la classe Movie per poter sfruttare gli attributi di convalida Required, StringLength, RegularExpression e Range predefiniti.

public class Movie
{
    public int Id { get; set; }

    [StringLength(60, MinimumLength = 3)]
    [Required]
    public string Title { get; set; }

    [Display(Name = "Release Date")]
    [DataType(DataType.Date)]
    public DateTime ReleaseDate { get; set; }

    [Range(1, 100)]
    [DataType(DataType.Currency)]
    [Column(TypeName = "decimal(18, 2)")]
    public decimal Price { get; set; }

    [RegularExpression(@"^[A-Z]+[a-zA-Z\s]*$")]
    [Required]
    [StringLength(30)]
    public string Genre { get; set; }

    [RegularExpression(@"^[A-Z]+[a-zA-Z0-9""'\s-]*$")]
    [StringLength(5)]
    [Required]
    public string Rating { get; set; }
}

Gli attributi di convalida specificano il comportamento da implementare nelle proprietà del modello a cui vengono applicati:

  • Gli attributi Required e MinimumLength indicano che una proprietà deve avere un valore, ma nulla impedisce all'utente di inserire spazi vuoti per soddisfare questa convalida.

  • L'attributo RegularExpression viene usato per limitare i caratteri che possono essere inseriti. Nel codice precedente "Genre":

    • Deve includere solo lettere.
    • La prima lettera deve essere maiuscola. Gli spazi vuoti sono consentiti, mentre i numeri e i caratteri speciali non sono consentiti.
  • RegularExpression "Rating":

    • Richiede che il primo carattere sia una lettera maiuscola.
    • Consente i caratteri speciali e i numeri negli spazi successivi. "PG-13" è valido per una classificazione, ma non per "Genre".
  • L'attributo Range vincola un valore all'interno di un intervallo specificato.

  • L'attributo StringLength consente di impostare la lunghezza massima di una proprietà stringa e, facoltativamente, la lunghezza minima.

  • I tipi di valore, ad esempio decimal, int, float e DateTime, sono intrinsecamente necessari e non richiedono l'attributo [Required].

L'applicazione automatica di regole di convalida da ASP.NET Core è utile per rendere un'app più solida. In questo modo inoltre non è possibile omettere la convalida di un elemento e quindi inserire involontariamente dati errati nel database.

Interfaccia utente dell'errore di convalida

Eseguire l'app e passare al controller di film.

Toccare il collegamento Crea nuovo per aggiungere un nuovo film. Completare il modulo con alcuni valori non validi. Non appena la convalida del lato client jQuery rileva l'errore, viene visualizzato un messaggio di errore.

Modulo di vista del film con diversi errori di convalida sul lato client jQuery

Nota

È possibile che non si riesca a immettere virgole decimali nel campo. Per supportare la convalida jQuery per impostazioni locali diverse dall'inglese che usano la virgola (",") come separatore decimale e per formati di data diversi da quello dell'inglese degli Stati Uniti, è necessario eseguire alcuni passaggi per globalizzare l'app. Per istruzioni sull'aggiunta di una virgola decimale, vedere questo commento di GitHub 4076 .

Si noti come il modulo ha eseguito automaticamente il rendering di un messaggio di errore di convalida appropriato in ogni campo contenente un valore non valido. Gli errori vengono applicati sia sul lato client (utilizzo di JavaScript e jQuery) sia sul lato server (nel caso di un utente con JavaScript disabilitato).

Un vantaggio significativo è che non è necessario modificare una singola riga di codice nella MoviesController classe o nella Create.cshtml visualizzazione per abilitare questa interfaccia utente di convalida. Il controller e le viste creati in una fase precedente di questa esercitazione hanno selezionato automaticamente le regole di convalida specificate usando gli attributi di convalida delle proprietà della classe Movie del modello. Eseguire il test della convalida usando il metodo di azione Edit e viene applicata la stessa convalida.

I dati del modulo non vengono inviati al server fino a quando non sono più presenti errori di convalida sul lato client. È possibile verificare questa condizione inserendo un punto di interruzione nel metodo HTTP Post usando lo strumento Fiddler o gli strumenti di sviluppo F12.

Funzionamento della convalida

Ci si potrebbe chiedere come la convalida dell'interfaccia utente sia stata generata senza aggiornamenti al codice nel controller o nelle viste. Il codice seguente mostra i due metodi Create.

// GET: Movies/Create
public IActionResult Create()
{
    return View();
}

// POST: Movies/Create
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Create(
    [Bind("ID,Title,ReleaseDate,Genre,Price, Rating")] Movie movie)
{
    if (ModelState.IsValid)
    {
        _context.Add(movie);
        await _context.SaveChangesAsync();
        return RedirectToAction("Index");
    }
    return View(movie);
}

Il primo metodo di azione (HTTP GET) Create visualizza il modulo di creazione iniziale. La seconda versione ([HttpPost]) gestisce l'invio del modulo. Il secondo metodo Create (la versione [HttpPost]) chiama ModelState.IsValid per verificare se esistono errori di convalida per il film. La chiamata a questo metodo valuta tutti gli attributi di convalida applicati all'oggetto. Se l'oggetto presenta errori di convalida, il metodo Create visualizza di nuovo il modulo. Se non sono presenti errori, il metodo salva il nuovo film nel database. Nell'esempio del film, il modulo non viene inviato al server quando vengono rilevati errori di convalida sul lato client; il secondo metodo Create non viene mai chiamato quando sono presenti errori di convalida sul lato client. Se si disabilita JavaScript nel browser, la convalida sul lato client viene disabilitata ed è possibile testare ModelState.IsValid del metodo Create HTTP POST rilevando eventuali errori di convalida.

È possibile impostare un punto di interruzione nel metodo [HttpPost] Create e verificare che il metodo non venga mai chiamato, la convalida sul lato client non invierà i dati del modulo in caso di rilevamento di errori di convalida. Se si disabilita JavaScript nel browser, quindi si invia il modulo con errori, verrà raggiunto il punto di interruzione. Si ottiene comunque la convalida completa senza JavaScript.

L'immagine seguente mostra come disabilitare JavaScript nel browser Firefox.

Firefox: nella scheda Contenuti in Opzioni deselezionare la casella di controllo Abilita Javascript.

La figura seguente illustra come disabilitare JavaScript nel browser Chrome.

Google Chrome: nella sezione Javascript delle impostazioni dei contenuti selezionare l'opzione per non consentire ai siti di eseguire JavaScript.

Dopo avere disabilitato JavaScript, inviare i dati non validi e procedere con il debugger.

Durante il debug su un invio di dati non validi, Intellisense su ModelState.IsValid mostra che il valore è false.

La parte del modello di Create.cshtml visualizzazione è illustrata nel markup seguente:


<h4>Movie</h4>
<hr />
<div class="row">
    <div class="col-md-4">
        <form asp-action="Create">
            <div asp-validation-summary="ModelOnly" class="text-danger"></div>
            <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>           
       
        @*Markup removed for brevity.*@

Il markup precedente viene usato dai metodi di azione per visualizzare il modulo iniziale e per visualizzarlo nuovamente in caso di errore.

L'helper tag di input usa gli attributi DataAnnotations e produce gli attributi HTML necessari per la convalida jQuery sul lato client. L'helper tag di convalida visualizza gli errori di convalida. Per altre informazioni, vedere Convalida.

L'aspetto molto interessante di questo approccio è che né il controller né il modello di vista Create sono consapevoli delle regole di convalida effettive applicate o dei messaggi di errore specifici visualizzati. Le regole di convalida e le stringhe di errore vengono specificate solo nella classe Movie. Le stesse regole di convalida vengono applicate automaticamente alla vista Edit e ad altri modelli di vista eventualmente creati che modificano il modello.

Se necessario, è possibile modificare la logica di convalida in una posizione tramite l'aggiunta di attributi di convalida al modello, in questo esempio la classe Movie. Non è necessario preoccuparsi dell'incoerenza delle diverse parti dell'applicazione con la modalità di applicazione delle regole perché tutta la logica di convalida verrà definita in un'unica posizione e usata ovunque. In questo modo il codice rimane molto pulito e facile da gestire e sviluppare. Il principio DRY sarà ampiamente rispettato.

Utilizzo degli attributi DataType

Aprire il Movie.cs file ed esaminare la Movie classe . Lo spazio dei nomi System.ComponentModel.DataAnnotations fornisce gli attributi di formattazione oltre al set predefinito di attributi di convalida. È già stato applicato un valore di enumerazione DataType ai campi della data di rilascio e del prezzo. Il codice seguente illustra le proprietà ReleaseDate e Price con l'attributo appropriato DataType.

[Display(Name = "Release Date")]
[DataType(DataType.Date)]
public DateTime ReleaseDate { get; set; }

[Range(1, 100)]
[DataType(DataType.Currency)]
public decimal Price { get; set; }

Gli attributi DataType specificano solo gli hint per far sì che il motore di vista formatti i dati (e fornisca gli elementi/attributi, ad esempio <a> per l'URL e <a href="mailto:EmailAddress.com"> per la posta elettronica). È possibile usare l'attributo RegularExpression per convalidare il formato dei dati. L'attributo DataType viene usato per specificare un tipo di dati più specifico del tipo intrinseco del database; non si tratta di attributi di convalida. In questo caso si vuole solo tenere traccia della data, non dell'ora. L'enumerazione DataType fornisce molti tipi di dati, ad esempio Data, Ora, Numero di telefono, Valuta, Indirizzo di posta elettronica e altro ancora. L'attributo DataType può anche consentire all'applicazione di fornire automaticamente le funzionalità specifiche del tipo. Ad esempio, è possibile creare un collegamento mailto: per DataType.EmailAddress e fornire un selettore data per DataType.Date nei browser che supportano HTML5. Gli attributi DataType generano attributi data- HTML5 (pronunciato data dash) supportati dai browser HTML5. Gli attributi DataTypenon forniscono alcuna convalida.

DataType.Date non specifica il formato della data visualizzata. Per impostazione predefinita, il campo dei dati viene visualizzato in base ai formati predefiniti per il valore CultureInfo del server.

L'attributo DisplayFormat viene usato per specificare in modo esplicito il formato della data:

[DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}", ApplyFormatInEditMode = true)]
public DateTime ReleaseDate { get; set; }

L'impostazione ApplyFormatInEditMode specifica che la formattazione deve essere applicata anche quando il valore viene visualizzato in una casella di testo per la modifica. Questa scelta non è consigliabile per alcuni campi, ad esempio per i valori della valuta poiché non è opportuno che il simbolo di valuta sia inserito nella casella di testo per la modifica.

È possibile usare l'attributo DisplayFormat da solo, ma in genere è consigliabile usare l'attributo DataType. L'attributo DataType fornisce la semantica dei dati anziché la modalità di esecuzione del rendering in una schermata e fornisce i seguenti vantaggi che non si ottengono con DisplayFormat:

  • Il browser può abilitare le funzionalità HTML5, ad esempio visualizzare un controllo di calendario, il simbolo della valuta appropriato per le impostazioni locali, i collegamenti alla posta elettronica e così via.

  • Per impostazione predefinita, il browser eseguirà il rendering dei dati usando il formato corretto in base alle impostazioni locali del sistema.

  • L'attributo DataType consente di abilitare MVC in modo da scegliere il modello di campo corretto per il rendering dei dati (DisplayFormat, se usato da solo, usa il modello di stringa).

Nota

La convalida jQuery non funziona con l'attributo Range e con DateTime. Ad esempio, il codice seguente visualizzerà sempre un errore di convalida sul lato client, anche quando la data è compreso nell'intervallo specificato:

[Range(typeof(DateTime), "1/1/1966", "1/1/2020")]

È necessario disabilitare la convalida della data jQuery per usare l'attributo Range con DateTime. In genere non è consigliabile compilare date reali nei modelli, quindi l'uso dell'attributo Range e di DateTime è sconsigliato.

Il codice seguente illustra la combinazione di attributi in una sola riga:

public class Movie
{
    public int Id { get; set; }

    [StringLength(60, MinimumLength = 3)]
    public string Title { get; set; }

    [Display(Name = "Release Date"), DataType(DataType.Date)]
    public DateTime ReleaseDate { get; set; }

    [RegularExpression(@"^[A-Z]+[a-zA-Z\s]*$"), Required, StringLength(30)]
    public string Genre { get; set; }

    [Range(1, 100), DataType(DataType.Currency)]
    [Column(TypeName = "decimal(18, 2)")]
    public decimal Price { get; set; }

    [RegularExpression(@"^[A-Z]+[a-zA-Z0-9""'\s-]*$"), StringLength(5)]
    public string Rating { get; set; }
}

Nella parte successiva della serie viene esaminata l'app e vengono apportati alcuni miglioramenti ai metodi Details e Delete generati automaticamente.

Risorse aggiuntive