Condividi tramite


Aggiunta della convalida

di Rick Anderson

Nota

Una versione aggiornata di questa esercitazione è disponibile qui usando la versione più recente di Visual Studio. La nuova esercitazione usa ASP.NET Core MVC, che offre molti miglioramenti in questa esercitazione.

Questa esercitazione illustra ASP.NET Core MVC con i controller e le viste. Razor Pages è una nuova alternativa in ASP.NET Core, un modello di programmazione basato su pagine che semplifica la creazione dell'interfaccia utente Web e una maggiore produttività. È consigliabile provare l'esercitazione sulle pagine Razor prima della versione MVC. L'esercitazione sulle pagine Razor:

  • È più semplice da seguire.
  • Riguarda più funzionalità.
  • È l'approccio preferito per lo sviluppo di nuove app.

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. Si noti che lo System.ComponentModel.DataAnnotations 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à. Contiene anche attributi di formattazione come DataType che consentono la formattazione e non forniscono alcuna convalida.

Aggiornare ora la Movie classe per sfruttare i vantaggi degli Requiredattributi predefiniti , StringLength, RegularExpression e Range convalida. Sostituire la Movie classe con quanto segue:

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

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

    [Display(Name = "Release Date")]
    [DataType(DataType.Date)]
    [DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}", ApplyFormatInEditMode = true)]
    public DateTime ReleaseDate { get; set; }
  
    [RegularExpression(@"^[A-Z]+[a-zA-Z]*$")]
    [Required]
    [StringLength(30)]
    public string Genre { get; set; }

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

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

L'attributo StringLength imposta la lunghezza massima della stringa e imposta questa limitazione nel database, pertanto lo schema del database verrà modificato. Fare clic con il pulsante destro del mouse sulla tabella Movies in Esplora server e scegliere Apri definizione tabella:

Screenshot che mostra la finestra Esplora server aperta e nella scheda d b o dot Movies Design .

Nell'immagine precedente è possibile vedere che tutti i campi stringa sono impostati su NVARCHAR (MAX). 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 DataAnnotations
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 (DataAnnotations) e nel Up metodo è possibile visualizzare il codice che aggiorna i vincoli dello schema:

public override void Up()
{
    AlterColumn("dbo.Movies", "Title", c => c.String(maxLength: 60));
    AlterColumn("dbo.Movies", "Genre", c => c.String(nullable: false, maxLength: 30));
    AlterColumn("dbo.Movies", "Rating", c => c.String(maxLength: 5));
}

Il Genre campo non è più nullable, ovvero è necessario immettere un valore. Il Rating campo ha una lunghezza massima di 5 e Title ha una lunghezza massima di 60. La lunghezza minima di 3 in Title e l'intervallo Price in non ha creato modifiche allo schema.

Esaminare lo schema Movie:

Screenshot che mostra la scheda d b o dot Movies Design. Il titolo e la classificazione vengono controllati nella colonna Consenti valori Null.

I campi stringa mostrano i nuovi limiti di lunghezza e Genre non sono più controllati come nullable.

Gli attributi di convalida specificano il comportamento da applicare per le 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 immessi. Nel codice precedente, per Genre e Rating è necessario usare solo lettere (spazi, numeri e caratteri speciali non consentiti). 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 valore (ad esempio decimal, int, float, DateTime) sono intrinsecamente obbligatori 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 DbEntityValidationException quando viene chiamato il SaveChanges metodo, perché mancano diversi valori di proprietà obbligatori Movie :

MovieDBContext db = new MovieDBContext();
Movie movie = new Movie();
movie.Title = "Gone with the Wind";
db.Movies.Add(movie);
db.SaveChanges();        // <= Will throw server side validation exception

Il codice precedente genera l'eccezione seguente:

Convalida non riuscita per una o più entità. Per altri dettagli, vedere la proprietà 'EntityValidationErrors'.

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.

Interfaccia utente degli errori di convalida in ASP.NET MVC

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

Fare clic sul 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.

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 la globalizzazione nuGet come descritto in precedenza in questa esercitazione.

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. 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 verificarlo inserendo un punto di interruzione nel metodo HTTP Post, usando lo strumento fiddler o gli strumenti di sviluppo F12 di Internet Explorer.

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.

public ActionResult Create()
{
    return View();
}
// POST: /Movies/Create
// To protect from overposting attacks, please enable the specific properties you want to bind to, for 
// more details see https://go.microsoft.com/fwlink/?LinkId=317598.
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create([Bind(Include = "ID,Title,ReleaseDate,Genre,Price,Rating")] 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 Create metodo (la HttpPost versione) verifica ModelState.IsValid se il film presenta errori di convalida. Il recupero di questa proprietà valuta tutti gli attributi di convalida applicati all'oggetto . Se l'oggetto presenta errori di convalida, il Create metodo riproduce il modulo. Se non sono presenti errori, il metodo salva il nuovo film nel database. Nell'esempio del filmato, il modulo non viene inviato al server quando vengono rilevati errori di convalida sul lato client. Il secondo Create metodo non viene mai chiamato. Se si disabilita JavaScript nel browser, la convalida del client è disabilitata e il metodo HTTP POST Create ottiene 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 e nella scheda sicurezza. La finestra Livello personalizzato è aperta e lo scripting attivo è disabilitato.

Screenshot che mostra il post H t t p e 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 Abilita script Java viene cerchiato in rosso.

La figura seguente illustra come disabilitare JavaScript nel browser Chrome.

Screenshot che mostra l'impostazione Script Java e l'opzione per consentire o disabilitare.

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>
@using (Html.BeginForm()) 
{
    @Html.AntiForgeryToken()    
    <div class="form-horizontal">
        <h4>Movie</h4>
        <hr />
        @Html.ValidationSummary(true)
        <div class="form-group">
            @Html.LabelFor(model => model.Title, new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.EditorFor(model => model.Title)
                @Html.ValidationMessageFor(model => model.Title)
            </div>
        </div>
        @*Fields removed for brevity.*@        




        <div class="form-group">
            <div class="col-md-offset-2 col-md-10">
                <input type="submit" value="Create" class="btn btn-default" />
            </div>
        </div>
    </div>
}
<div>
    @Html.ActionLink("Back to List", "Index")
</div>
@section Scripts {
    @Scripts.Render("~/bundles/jqueryval")
}

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.

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 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. E significa che sarete pienamente onorati del principio DRY .

Utilizzo degli attributi DataType

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 DataType.

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

Gli attributi DataType forniscono solo suggerimenti per il motore di visualizzazione per formattare i dati e specificare attributi come <a> per 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 sono attributi di convalida. In questo caso si vuole tenere traccia solo della data e non di data e ora. L'enumerazione DataType offre molti tipi di dati, ad esempio Data, Ora, PhoneNumber, Valuta, EmailAddress e altro ancora. L'attributo DataType può anche consentire all'applicazione di fornire automaticamente le funzionalità specifiche del tipo. Ad esempio, è possibile creare un mailto: collegamento per DataType.EmailAddress e un selettore data può essere fornito per DataType.Date nei browser che supportano HTML5. Gli attributi DataType generano attributi HTML 5 data- (pronunciato trattino dati) che i browser HTML 5 possono comprendere. Gli attributi DataType non forniscono alcuna convalida.

DataType.Date non specifica il formato della data visualizzata. Per impostazione predefinita, il campo dati viene visualizzato in base ai formati predefiniti basati su 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 EnrollmentDate { get; set; }

L'impostazione ApplyFormatInEditMode specifica che la formattazione specificata deve essere applicata anche quando il valore viene visualizzato in una casella di testo per la modifica. È possibile che non si voglia che per alcuni campi, ad esempio per i valori di valuta, non si voglia che il simbolo di valuta nella casella di testo venga modificato.

È possibile usare l'attributo DisplayFormat da solo, ma in genere è consigliabile usare anche l'attributo DataType . L'attributo DataType fornisce la semantica dei dati anziché come eseguirne il rendering su una schermata e offre i vantaggi seguenti che non si ottengono con DisplayFormat:

  • Il browser può abilitare le funzionalità HTML5, ad esempio per visualizzare un controllo calendario, il simbolo di valuta appropriato per le impostazioni locali, i collegamenti di posta elettronica e così via.
  • Per impostazione predefinita, il browser eseguirà il rendering dei dati usando il formato corretto in base alle impostazioni locali.
  • L'attributo DataType può consentire a MVC di scegliere il modello di campo corretto per eseguire il rendering dei dati (displayFormat se usato da solo usa il modello stringa). Per altre informazioni, vedere Modelli ASP.NET MVC 2 di Brad Wilson. Anche se scritto per MVC 2, questo articolo si applica ancora alla versione corrente di ASP.NET MVC.

Se si usa l'attributo DataType con un campo data, è necessario specificare anche l'attributo DisplayFormat per assicurarsi che il rendering del campo venga eseguito correttamente nei browser Chrome. Per altre informazioni, vedere questo thread StackOverflow.

Nota

La convalida di jQuery non funziona con l'attributo Range e 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 di jQuery per usare l'attributo Range con DateTime. In genere non è consigliabile compilare date hard nei modelli, quindi è sconsigliato usare l'attributo Range e DateTime .

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

public class Movie
{
   public int ID { get; set; }
   [Required,StringLength(60, MinimumLength = 3)]
   public string Title { get; set; }
   [Display(Name = "Release Date"),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; }
   [Required,StringLength(5)]
   public string Rating { get; set; }
}

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