Share via


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 fornisce molti miglioramenti su 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 ASCIUTTE

Uno dei set di base di progettazione di ASP.NET MVC è DRY ("Non ripetere te stesso"). ASP.NET MVC incoraggia l'utente a specificare funzionalità o comportamento una sola volta e quindi rifletterlo ovunque in un'applicazione. Ciò 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 e 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.

Esaminiamo come sfruttare questo supporto di 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 gli attributi predefiniti Required, , StringLengthRegularExpression 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 cambierà. Fare clic con il pulsante destro del mouse sulla tabella Film in Esplora server e scegliere Apri definizione tabella:

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

Nell'immagine precedente è possibile visualizzare tutti i campi stringa impostati su NVARCHAR (MAX). Verranno usate le migrazioni per aggiornare lo schema. Compilare la soluzione e quindi aprire la finestra 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 su Title e l'intervallo in Price non ha creato modifiche dello schema.

Esaminare lo schema Del filmato:

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

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 di input. 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 di valore (ad esempio decimal, int, float, DateTime) sono intrinsecamente necessari e non hanno bisogno dell'attributo Required .

Code First garantisce che le regole di convalida specificate in una classe modello vengano applicate prima che l'applicazione salva 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 altre informazioni, 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 dell'errore di convalida in ASP.NET MVC

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

Fare clic sul collegamento Crea nuovo per aggiungere un nuovo filmato. 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 jQuery per le impostazioni locali non inglesi che usano una virgola (",") per un punto decimale, è necessario includere la globalizzazione NuGet come descritto in precedenza in questa esercitazione.

Si noti come il modulo ha usato automaticamente un colore bordo rosso 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 classe o nella MoviesController 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 verificare questa operazione inserendo un punto di interruzione nel metodo HTTP Post, usando lo strumento fiddler o gli strumenti di sviluppo IE F12.

Come si verifica la convalida nel metodo Create View and Create Action

Ci si potrebbe chiedere come la convalida dell'interfaccia utente sia stata generata senza aggiornamenti al codice nel controller o nelle viste. L'elenco MovieController successivo mostra i Create metodi della classe. Sono invariati dal 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 (versione HttpPost ) verifica ModelState.IsValid se il film ha eventuali errori di convalida. Ottenere questa proprietà valuta gli attributi di convalida applicati all'oggetto. Se l'oggetto ha errori di convalida, il Create metodo redisplay 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 si verificano errori di convalida rilevati sul lato client. Il secondoCreatemetodo non viene mai chiamato. Se si disabilita JavaScript nel browser, la convalida client è disabilitata e il metodo HTTP POST Create ottiene ModelState.IsValid per verificare se il film ha 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 illustra 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 che è stato eseguito 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 come 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 sarai completamente onorato 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 hint per il motore di visualizzazione per formattare i dati (e specificare attributi, ad <a> esempio 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 sono attributi di convalida. In questo caso si vuole tenere traccia solo della data e non di data e ora. L'enumerazione DataType fornisce molti tipi di dati, ad esempio Date, Time, PhoneNumber, Currency, 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 di date può essere fornito per DataType.Date nei browser che supportano HTML5. Gli attributi DataType generano attributi HTML 5 data- ( trattino dati pronunciati) 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. Potrebbe non essere necessario che per alcuni campi, ad esempio per i valori di valuta, non si voglia il simbolo di valuta nella casella di testo per la modifica.

È possibile usare l'attributo DisplayFormat da solo, ma è in genere consigliabile usare anche l'attributo DataType . L'attributo DataType trasmette la semantica dei dati anziché come eseguirne il rendering su uno schermo 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ò abilitare MVC per scegliere il modello di campo corretto per eseguire il rendering dei dati ( displayFormat se usato da se stesso usa il modello di stringa). Per altre informazioni, vedere i modelli ASP.NET MVC 2 di Brad Wilson. Sebbene scritto per MVC 2, questo articolo si applica ancora alla versione corrente di ASP.NET MVC.

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

Nota

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

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.