Condividi tramite


Aggiunta della logica di convalida al modello movie

di Rick Anderson

Nota

Una versione aggiornata di questa esercitazione è disponibile qui che usa ASP.NET MVC 5 e Visual Studio 2013. È più sicuro, molto più semplice da seguire e dimostra più funzionalità.

In questa sezione si aggiungerà la logica di convalida al Movie modello e si assicurerà che le regole di convalida vengano applicate ogni volta che un utente tenta di creare o modificare un filmato usando l'applicazione.

Mantenere le cose DRY

Uno dei principali set di progettazione di ASP.NET MVC è DRY ("Non ripetere se stessi"). ASP.NET MVC incoraggia a specificare funzionalità o comportamento una sola volta e quindi rifletterla ovunque in un'applicazione. In questo modo si riduce la quantità di codice che è necessario scrivere e rende il codice meno soggetto a errori e più facile da gestire.

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

Di seguito viene illustrato come sfruttare questo supporto per la convalida nell'applicazione film.

Aggiunta di regole di convalida al modello di film

Si inizierà aggiungendo una logica di convalida alla Movie classe .

Aprire il file Movie.cs. Aggiungere un'istruzione using all'inizio del file che fa riferimento allo System.ComponentModel.DataAnnotations spazio dei nomi :

using System.ComponentModel.DataAnnotations;

Si noti che lo spazio dei nomi non contiene System.Web. DataAnnotations fornisce un set predefinito di attributi di convalida che è possibile applicare in modo dichiarativo a qualsiasi classe o proprietà.

Aggiornare ora la Movie classe per sfruttare i vantaggi degli Requiredattributi di convalida predefiniti , StringLengthe Range . Usare il codice seguente come esempio di dove applicare gli attributi.

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

    [Required]
    public string Title { get; set; }

    [DataType(DataType.Date)]
    public DateTime ReleaseDate { get; set; }

    [Required]
    public string Genre { get; set; }

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

    [StringLength(5)]
    public string Rating { get; set; }
}

Eseguire l'applicazione e verrà visualizzato di nuovo l'errore di runtime seguente:

Il modello che esegue il backup del contesto 'MovieDBContext' è stato modificato dopo la creazione del database. È consigliabile usare Migrazioni Code First per aggiornare il database (https://go.microsoft.com/fwlink/?LinkId=238269).

Verranno usate le migrazioni per aggiornare lo schema. Compilare la soluzione e quindi aprire la finestra della console di Gestione pacchetti e immettere i comandi seguenti:

add-migration AddDataAnnotationsMig
update-database

Al termine di questo comando, Visual Studio apre il file di classe che definisce la nuova DbMigration classe derivata con il nome specificato (AddDataAnnotationsMig) e nel Up metodo è possibile visualizzare il codice che aggiorna i vincoli dello schema. I Title campi e Genre non sono più nullable (ovvero è necessario immettere un valore) e il Rating campo ha una lunghezza massima di 5.

Gli attributi di convalida specificano il comportamento da applicare per le proprietà del modello a cui vengono applicati. L'attributo Required indica che una proprietà deve avere un valore. In questo esempio, un filmato deve avere valori per le Titleproprietà , GenreReleaseDate, e Price per essere valide. 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 intrinseci (ad esempio decimal, int, float, DateTime) sono richiesti per impostazione predefinita e non richiedono l'attributo Required .

Code First garantisce che le regole di convalida specificate in una classe modello vengano applicate prima che l'applicazione salvi le modifiche nel database. Ad esempio, il codice seguente genererà un'eccezione quando viene chiamato il SaveChanges metodo , perché mancano diversi valori di proprietà obbligatori Movie e il prezzo è zero (che non rientra nell'intervallo valido).

MovieDBContext db = new MovieDBContext();

Movie movie = new Movie();
movie.Title = "Gone with the Wind";
movie.Price = 0.0M;

db.Movies.Add(movie);  
db.SaveChanges();        // <= Will throw server side validation exception  

La presenza di regole di convalida applicate automaticamente da .NET Framework consente di rendere l'applicazione più affidabile. In questo modo inoltre non è possibile omettere la convalida di un elemento e quindi inserire involontariamente dati errati nel database.

Ecco un elenco di codice completo per il file di Movie.cs aggiornato:

using System;
using System.Data.Entity;
using System.ComponentModel.DataAnnotations;

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

        [Required]
        public string Title { get; set; }

        [DataType(DataType.Date)]
        public DateTime ReleaseDate { get; set; }

        [Required]
        public string Genre { get; set; }

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

        [StringLength(5)]
        public string Rating { get; set; }
    }

    public class MovieDBContext : DbContext {
        public DbSet<Movie> Movies { get; set; }
    }
}

Interfaccia utente degli errori di convalida in ASP.NET MVC

Eseguire di nuovo l'applicazione e passare all'URL /Movies .

Fare clic sul collegamento Crea nuovo per aggiungere un nuovo film. Compilare il modulo con alcuni valori non validi e quindi fare clic sul pulsante Crea .

8_validationErrors

Nota

per supportare la convalida di jQuery per impostazioni locali non in lingua inglese che usano una virgola (",") per un separatore decimale, è necessario includere globalize.js e i file di impostazioni cultura/globalize.cultures.js specifici (da https://github.com/jquery/globalize ) e JavaScript per usare Globalize.parseFloat. Il codice seguente mostra le modifiche apportate al file Views\Movies\Edit.cshtml per l'uso delle impostazioni cultura "fr-FR":

@section Scripts {
    @Scripts.Render("~/bundles/jqueryval")
    <script src="~/Scripts/globalize.js"></script>
    <script src="~/Scripts/globalize.culture.fr-FR.js"></script>
    <script>
        $.validator.methods.number = function (value, element) {
            return this.optional(element) ||
                !isNaN(Globalize.parseFloat(value));
        }
        $(document).ready(function () {
            Globalize.culture('fr-FR');
        });
    </script>
    <script>
        jQuery.extend(jQuery.validator.methods, {    
            range: function (value, element, param) {        
                //Use the Globalization plugin to parse the value        
                var val = $.global.parseFloat(value);
                return this.optional(element) || (
                    val >= param[0] && val <= param[1]);
            }
        });

    </script>
}

Si noti che il modulo ha utilizzato automaticamente un colore rosso del bordo per evidenziare le caselle di testo che contengono dati non validi e ha generato un messaggio di errore di convalida appropriato accanto a ognuno di essi. 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 reale è che non è necessario modificare una singola riga di codice nella MoviesController classe o nella visualizzazione Create.cshtml 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.

È possibile che sia stato notato per le proprietà Title e Genre, l'attributo obbligatorio non viene applicato fino a quando non si invia il modulo (premere il pulsante Crea ) o si immette il testo nel campo di input e lo ha rimosso. Per un campo inizialmente vuoto (ad esempio i campi nella visualizzazione Crea) e che ha solo l'attributo obbligatorio e nessun altro attributo di convalida, è possibile eseguire le operazioni seguenti per attivare la convalida:

  1. Tabulazioni nel campo.
  2. Immettere del testo.
  3. Uscire dalla scheda tramite tabulazione.
  4. Tornare al campo.
  5. Rimuovere il testo.
  6. Uscire dalla scheda tramite tabulazione.

La sequenza precedente attiverà la convalida richiesta senza premere il pulsante di invio. È sufficiente premere il pulsante di invio senza immettere uno dei campi attiverà la convalida lato client. I dati del modulo non vengono inviati al server fino a quando non sono più presenti errori di convalida sul lato client. È possibile testarlo inserendo un punto di interruzione nel metodo HTTP Post o usando lo strumento fiddler o gli strumenti di sviluppo F12 di Internet Explorer 9.

Screenshot che mostra la pagina M V C Movie Create. Un avviso accanto a Titolo indica che il campo Titolo è obbligatorio. Un avviso accanto a Genere indica che il campo Genere è obbligatorio.

Modalità di esecuzione della convalida nel metodo Crea visualizzazione e Crea azione

Ci si potrebbe chiedere come la convalida dell'interfaccia utente sia stata generata senza aggiornamenti al codice nel controller o nelle viste. L'elenco successivo mostra l'aspetto dei Create metodi nella MovieController classe . Sono invariati rispetto al modo in cui sono stati creati in precedenza in questa esercitazione.

//
// GET: /Movies/Create

public ActionResult Create()
{
    return View();
}

//
// POST: /Movies/Create

[HttpPost]
public ActionResult Create(Movie movie)
{
    if (ModelState.IsValid)
    {
        db.Movies.Add(movie);
        db.SaveChanges();
        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 filmato in uso, il modulo non viene inviato al server quando vengono rilevati errori di convalida sul lato client. Il secondo Createmetodo non viene mai chiamato. Se disabiliti JavaScript nel browser, la convalida del client è disabilitata e il metodo HTTP POST Create chiama ModelState.IsValid per verificare se il filmato presenta 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 in Internet Explorer.

Screenshot che mostra la finestra Opzioni Internet aperta alla scheda Sicurezza. Il livello personalizzato è cerchiato in rosso. Nella finestra Impostazioni di sicurezza, lo scripting attivo è impostato per disabilitare. La barra di scorrimento è cerchiata in rosso.

Screenshot che mostra il post H t t p. Se il punto di stato del modello è valido è evidenziato.

La figura seguente illustra come disabilitare JavaScript nel browser FireFox.

Screenshot che mostra la finestra Opzioni. Il contenuto è selezionato e viene selezionato Enable Java Script (Abilita script Java).

L'immagine seguente mostra come disabilitare JavaScript con il browser Chrome.

Screenshot che mostra la pagina Opzioni. Sotto il cappuccio è selezionato e cerchiato in rosso. In Impostazioni contenuto, Script Java è impostato su Consenti a tutti i siti di eseguire script Java.

Di seguito è riportato il modello di visualizzazione Create.cshtml di cui è stato eseguito lo scaffolding in precedenza nell'esercitazione. Viene usata dai metodi di azione illustrati in precedenza per visualizzare il modulo iniziale e per visualizzarlo nuovamente in caso di errore.

@model MvcMovie.Models.Movie

@{
    ViewBag.Title = "Create";
}

<h2>Create</h2>

<script src="@Url.Content("~/Scripts/jquery.validate.min.js")"></script>
<script src="@Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")"></script>

@using (Html.BeginForm()) {
    @Html.ValidationSummary(true)

    <fieldset>
        <legend>Movie</legend>

        <div class="editor-label">
            @Html.LabelFor(model => model.Title)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.Title)
            @Html.ValidationMessageFor(model => model.Title)
        </div>

        <div class="editor-label">
            @Html.LabelFor(model => model.ReleaseDate)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.ReleaseDate)
            @Html.ValidationMessageFor(model => model.ReleaseDate)
        </div>

        <div class="editor-label">
            @Html.LabelFor(model => model.Genre)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.Genre)
            @Html.ValidationMessageFor(model => model.Genre)
        </div>

        <div class="editor-label">
            @Html.LabelFor(model => model.Price)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.Price)
            @Html.ValidationMessageFor(model => model.Price)
        </div>
        <div class="editor-label">
    @Html.LabelFor(model => model.Rating)
</div>
<div class="editor-field">
    @Html.EditorFor(model => model.Rating)
    @Html.ValidationMessageFor(model => model.Rating)
</div>
        <p>
            <input type="submit" value="Create" />
        </p>
    </fieldset>
}

<div>
    @Html.ActionLink("Back to List", "Index")
</div>

Si noti che il codice usa un Html.EditorFor helper per restituire l'elemento <input> per ogni Movie proprietà. Accanto a questo helper è una chiamata al Html.ValidationMessageFor metodo helper. Questi due metodi helper funzionano con l'oggetto modello passato dal controller alla visualizzazione (in questo caso, un Movie oggetto ). Cercano automaticamente gli attributi di convalida specificati nel modello e visualizzano i messaggi di errore in base alle esigenze.

Ciò che è davvero interessante di questo approccio è che né il controller né il modello di visualizzazione Crea sanno nulla sulle regole di convalida effettive applicate o sui messaggi di errore specifici visualizzati. Le regole di convalida e le stringhe di errore vengono specificate solo nella classe Movie. Queste stesse regole di convalida vengono applicate automaticamente alla visualizzazione Modifica e a tutti gli altri modelli di viste che è possibile creare che modificano il modello.

Se si vuole modificare la logica di convalida in un secondo momento, è possibile farlo in un'unica posizione aggiungendo attributi di convalida al modello (in questo esempio la movie classe ). 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.

Aggiunta della formattazione al modello di film

Aprire il file Movie.cs ed esaminare la classe Movie. 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 DisplayFormat.

[DataType(DataType.Date)] 
public DateTime ReleaseDate { get; set; }

[DataType(DataType.Currency)] 
public decimal Price { get; set; }

Gli DataType attributi non sono attributi di convalida, vengono usati per indicare al motore di visualizzazione come eseguire il rendering del codice HTML. Nell'esempio precedente, l'attributo DataType.Date visualizza le date del film solo come date, senza ora. Ad esempio, gli attributi seguenti DataType non convalidano il formato dei dati:

[DataType(DataType.EmailAddress)]
[DataType(DataType.PhoneNumber)]
[DataType(DataType.Url)]

Gli attributi elencati in precedenza forniscono solo suggerimenti per il motore di visualizzazione per formattare i dati e specificare attributi come <per> URL e <href="mailto:EmailAddress.com"> per la posta elettronica. È possibile usare l'attributo RegularExpression per convalidare il formato dei dati.

Un approccio alternativo all'uso degli DataType attributi può essere impostato in modo esplicito su un DataFormatString valore. Il codice seguente mostra la proprietà data di rilascio con una stringa di formato data (vale a dire "d"). Usare questa opzione per specificare che non si vuole eseguire l'ora come parte della data di rilascio.

[DisplayFormat(DataFormatString = "{0:d}")]
public DateTime ReleaseDate { get; set; }

La classe completa Movie è illustrata di seguito.

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

    [Required]
    public string Title { get; set; }

    [DataType(DataType.Date)]
    public DateTime ReleaseDate { get; set; }

    [Required]
    public string Genre { get; set; }

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

    [StringLength(5)]
    public string Rating { get; set; }
}

Eseguire l'applicazione e passare al Movies controller. La data di rilascio e il prezzo sono ben formattati. L'immagine seguente mostra la data di rilascio e il prezzo usando "fr-FR" come impostazioni cultura.

8_format_SM

L'immagine seguente mostra gli stessi dati visualizzati con le impostazioni cultura predefinite (Stati Uniti).

Screenshot che mostra la pagina M V C Movie Index con quattro film elencati.

Nella parte successiva della serie verrà esaminata l'applicazione e verranno apportati alcuni miglioramenti ai metodi Details e Delete generati automaticamente.