Condividi tramite


Iterazione 3 - Aggiungere la convalida dei form (VB)

da Microsoft

Scaricare codice

Nella terza iterazione si aggiunge la convalida dei moduli di base. Impedisciamo agli utenti di inviare un modulo senza completare i campi del modulo obbligatori. Si convalidano anche gli indirizzi di posta elettronica e i numeri di telefono.

Creazione di un ASP.NET applicazione MVC (VB)

In questa serie di esercitazioni viene creata un'intera applicazione Di gestione contatti dall'inizio alla fine. L'applicazione Contact Manager consente di archiviare informazioni di contatto, nomi, numeri di telefono e indirizzi di posta elettronica, per un elenco di persone.

Viene creata l'applicazione su più iterazioni. Con ogni iterazione, si migliora gradualmente l'applicazione. L'obiettivo di questo approccio a più iterazioni è quello di consentire di comprendere il motivo di ogni modifica.

  • Iterazione #1: creare l'applicazione. Nella prima iterazione, creiamo Contact Manager nel modo più semplice possibile. È possibile aggiungere il supporto per le operazioni di base del database: creare, leggere, aggiornare ed eliminare (CRUD).

  • Iterazione #2: rendere l'applicazione più bella. In questa iterazione si migliora l'aspetto dell'applicazione modificando la pagina master della visualizzazione MVC predefinita ASP.NET e il foglio di stile a catena.

  • Iterazione #3 - Aggiungere la convalida del modulo. Nella terza iterazione si aggiunge la convalida dei moduli di base. Impedisciamo agli utenti di inviare un modulo senza completare i campi del modulo obbligatori. Si convalidano anche gli indirizzi di posta elettronica e i numeri di telefono.

  • Iterazione #4: rendere l'applicazione in modo libero. In questa quarta iterazione si sfruttano diversi modelli di progettazione software per semplificare la gestione e la modifica dell'applicazione Contact Manager. Ad esempio, l'applicazione viene refactoring per usare il modello repository e il modello di inserimento delle dipendenze.

  • Iterazione #5 - Creare unit test. Nella quinta iterazione, l'applicazione semplifica la gestione e la modifica dell'applicazione aggiungendo unit test. È possibile simulare le classi del modello di dati e compilare unit test per i controller e la logica di convalida.

  • Iterazione #6 : usare lo sviluppo basato su test. In questa sesta iterazione si aggiungono nuove funzionalità all'applicazione scrivendo prima unit test e scrivendo codice rispetto agli unit test. In questa iterazione si aggiungono gruppi di contatti.

  • Iterazione 7 - Aggiungere funzionalità Ajax. Nella settima iterazione si migliora la velocità di risposta e le prestazioni dell'applicazione aggiungendo il supporto per Ajax.

Iterazione

In questa seconda iterazione dell'applicazione Contact Manager viene aggiunta la convalida dei moduli di base. Impedisciamo agli utenti di inviare un contatto senza immettere i valori per i campi del modulo obbligatori. È anche possibile convalidare i numeri di telefono e gli indirizzi di posta elettronica (vedere la figura 1).

Finestra di dialogo relativa al nuovo progetto

Figura 01: modulo con convalida (Fare clic per visualizzare l'immagine full-size)

In questa iterazione si aggiunge la logica di convalida direttamente alle azioni del controller. In generale, questo non è il modo consigliato per aggiungere la convalida a un'applicazione MVC ASP.NET. Un approccio migliore consiste nell'inserire una logica di convalida dell'applicazione in un livello di servizio separato. Nell'iterazione successiva si esegue il refactoring dell'applicazione Contact Manager per rendere l'applicazione più gestibile.

In questa iterazione, per mantenere le cose semplici, viene scritto tutto il codice di convalida in base alla mano. Anziché scrivere il codice di convalida, è possibile sfruttare un framework di convalida. Ad esempio, è possibile usare Microsoft Enterprise Library Validation Application Block (VAB) per implementare la logica di convalida per l'applicazione MVC ASP.NET. Per altre informazioni sul blocco di applicazioni di convalida, vedere:

http://msdn.microsoft.com/library/dd203099.aspx

Aggiunta della convalida alla visualizzazione crea

Iniziamo aggiungendo la logica di convalida alla visualizzazione Crea. Fortunatamente, poiché è stata generata la visualizzazione Crea con Visual Studio, la visualizzazione Crea contiene già tutta la logica dell'interfaccia utente necessaria per visualizzare i messaggi di convalida. La visualizzazione Crea è contenuta nell'elenco 1.

Elenco 1 - \Views\Contact\Create.aspx

<%@ Page Title="" Language="VB" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage(Of ContactManager.Contact)" %>

<asp:Content ID="Content1" ContentPlaceHolderID="head" runat="server">
<title>Create</title>
</asp:Content>

<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">

    <%= Html.ValidationSummary() %>

    <% Using Html.BeginForm()%>

        <fieldset>
            <legend>Create New Contact</legend>
            <p>
                <label for="FirstName">First Name:</label>
                <%= Html.TextBox("FirstName") %>
                <%= Html.ValidationMessage("FirstName", "*") %>
            </p>
            <p>
                <label for="LastName">Last Name:</label>
                <%= Html.TextBox("LastName") %>
                <%= Html.ValidationMessage("LastName", "*") %>
            </p>
            <p>
                <label for="Phone">Phone:</label>
                <%= Html.TextBox("Phone") %>
                <%= Html.ValidationMessage("Phone", "*") %>
            </p>
            <p>
                <label for="Email">Email:</label>
                <%= Html.TextBox("Email") %>
                <%= Html.ValidationMessage("Email", "*") %>
            </p>
            <p class="submit">
                <input type="submit" value="Create" />
            </p>
        </fieldset>

    <% End Using %>

</asp:Content>

La classe field-validation-error viene usata per stilere l'output eseguito dal helper Html.ValidationMessage(). La classe input-validation-error viene usata per stilere la casella di testo (input) sottoposta a rendering dall'helper Html.TextBox(). La classe validation-summary-errors viene usata per stilere l'elenco non ordinato eseguito dal helper Html.ValidationSummary().

Nota

È possibile modificare le classi del foglio di stile descritte in questa sezione per personalizzare l'aspetto dei messaggi di errore di convalida.

Aggiunta della logica di convalida all'azione Crea

Al momento, la visualizzazione Crea non visualizza mai messaggi di errore di convalida perché non è stata scritta la logica per generare messaggi. Per visualizzare i messaggi di errore di convalida, è necessario aggiungere i messaggi di errore a ModelState.

Nota

Il metodo UpdateModel() aggiunge automaticamente messaggi di errore a ModelState quando si verifica un errore che assegna il valore di un campo di modulo a una proprietà. Ad esempio, se si tenta di assegnare la stringa "apple" a una proprietà BirthDate che accetta valori DateTime, il metodo UpdateModel() aggiunge un errore a ModelState.

Il metodo Create() modificato in List 2 contiene una nuova sezione che convalida le proprietà della classe Contact prima che il nuovo contatto venga inserito nel database.

Elenco 2 - Controller\ContactController.vb (Crea con convalida)

<AcceptVerbs(HttpVerbs.Post)> _
Function Create(<Bind(Exclude:="Id")> ByVal contactToCreate As Contact) As ActionResult
    ' Validation logic
    If contactToCreate.FirstName.Trim().Length = 0 Then
        ModelState.AddModelError("FirstName", "First name is required.")
    End If
    If contactToCreate.LastName.Trim().Length = 0 Then
        ModelState.AddModelError("LastName", "Last name is required.")
    End If
    If (contactToCreate.Phone.Length > 0 AndAlso Not Regex.IsMatch(contactToCreate.Phone, "((\(\d{3}\) ?)|(\d{3}-))?\d{3}-\d{4}"))
        ModelState.AddModelError("Phone", "Invalid phone number.")
    End If        
    If (contactToCreate.Email.Length > 0 AndAlso  Not Regex.IsMatch(contactToCreate.Email, "^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$"))
        ModelState.AddModelError("Email", "Invalid email address.")
    End If
    If Not ModelState.IsValid Then
        Return View()
    End If

    ' Database logic
    Try
        _entities.AddToContactSet(contactToCreate)
        _entities.SaveChanges()
        Return RedirectToAction("Index")
    Catch
        Return View()
    End Try
End Function

La sezione convalida applica quattro regole di convalida distinte:

  • La proprietà FirstName deve avere una lunghezza maggiore di zero (e non può essere costituita esclusivamente da spazi)
  • La proprietà LastName deve avere una lunghezza maggiore di zero (e non può essere costituita esclusivamente da spazi)
  • Se la proprietà Phone ha un valore (ha una lunghezza maggiore di 0) la proprietà Phone deve corrispondere a un'espressione regolare.
  • Se la proprietà Email ha un valore (ha una lunghezza maggiore di 0), la proprietà Email deve corrispondere a un'espressione regolare.

Quando si verifica una violazione della regola di convalida, viene aggiunto un messaggio di errore a ModelState con la guida del metodo AddModelError(). Quando si aggiunge un messaggio a ModelState, specificare il nome di una proprietà e il testo di un messaggio di errore di convalida. Questo messaggio di errore viene visualizzato nella visualizzazione dai metodi helper Html.ValidationSummary() e Html.ValidationMessage().

Dopo l'esecuzione delle regole di convalida, viene selezionata la proprietà IsValid di ModelState. La proprietà IsValid restituisce false quando sono stati aggiunti messaggi di errore di convalida a ModelState. Se la convalida ha esito negativo, il modulo Crea viene riprodotto con i messaggi di errore.

Nota

Ho ottenuto le espressioni regolari per convalidare il numero di telefono e l'indirizzo di posta elettronica dal repository di espressioni regolari in http://regexlib.com

Aggiunta della logica di convalida all'azione Modifica

L'azione Edit() aggiorna un contatto. L'azione Edit() deve eseguire esattamente la stessa convalida dell'azione Create(). Anziché duplicare lo stesso codice di convalida, è necessario eseguire il refactoring del controller Contact in modo che le azioni Create() e Edit() chiamino lo stesso metodo di convalida.

La classe controller Contact modificata è contenuta nell'elenco 3. Questa classe ha un nuovo metodo ValidateContact() chiamato all'interno delle azioni Create() e Edit().

Elenco 3 - Controller\ContactController.vb

Public Class ContactController
    Inherits System.Web.Mvc.Controller

    Private _entities As New ContactManagerDBEntities()

    Protected Sub ValidateContact(contactToValidate As Contact)
        If contactToValidate.FirstName.Trim().Length = 0 Then
            ModelState.AddModelError("FirstName", "First name is required.")
        End If
        If contactToValidate.LastName.Trim().Length = 0 Then
            ModelState.AddModelError("LastName", "Last name is required.")
        End If
        If (contactToValidate.Phone.Length > 0 AndAlso Not Regex.IsMatch(contactToValidate.Phone, "((\(\d{3}\) ?)|(\d{3}-))?\d{3}-\d{4}"))
            ModelState.AddModelError("Phone", "Invalid phone number.")
        End If        
        If (contactToValidate.Email.Length > 0 AndAlso  Not Regex.IsMatch(contactToValidate.Email, "^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$"))
            ModelState.AddModelError("Email", "Invalid email address.")
        End If
    End Sub

    '
    ' GET: /Contact

    Function Index() As ActionResult
        Return View(_entities.ContactSet.ToList())
    End Function

    '
    ' GET: /Contact/Create

    Function Create() As ActionResult
        Return View()
    End Function

    '
    ' POST: /Contact/Create

    <AcceptVerbs(HttpVerbs.Post)> _
    Function Create(<Bind(Exclude:="Id")> ByVal contactToCreate As Contact) As ActionResult
        ' Validation logic
        ValidateContact(contactToCreate)
        If Not ModelState.IsValid Then
            Return View()
        End If

        ' Database logic
        Try
            _entities.AddToContactSet(contactToCreate)
            _entities.SaveChanges()
            Return RedirectToAction("Index")
        Catch
            Return View()
        End Try
    End Function

    '
    ' GET: /Contact/Edit/5

    Function Edit(ByVal id As Integer) As ActionResult
        Dim contactToEdit = (from c in _entities.ContactSet _
                           where c.Id = id _
                           select c).FirstOrDefault()

        Return View(contactToEdit)
    End Function

    '
    ' POST: /Contact/Edit/5

    <AcceptVerbs(HttpVerbs.Post)> _
    Function Edit(ByVal contactToEdit As Contact) As ActionResult
        ' Validation logic
        ValidateContact(contactToEdit)
        If Not ModelState.IsValid Then
            Return View()
        End If

        ' Database logic
        Try
            Dim originalContact = (from c in _entities.ContactSet _
                             where c.Id = contactToEdit.Id _
                             select c).FirstOrDefault()
            _entities.ApplyPropertyChanges(originalContact.EntityKey.EntitySetName, contactToEdit)
            _entities.SaveChanges()
            Return RedirectToAction("Index")
        Catch
            Return View()
        End Try
    End Function

    '
    ' GET: /Contact/Delete/5

    Function Delete(ByVal id As Integer) As ActionResult
        Dim contactToDelete = (from c in _entities.ContactSet _
                           where c.Id = id _
                           select c).FirstOrDefault()

        Return View(contactToDelete)
    End Function

    '
    ' POST: /Contact/Delete/5

    <AcceptVerbs(HttpVerbs.Post)> _
    Function Delete(ByVal contactToDelete As Contact) As ActionResult
        Try
            Dim originalContact = (from c in _entities.ContactSet _
                             where c.Id = contactToDelete.Id _
                             select c).FirstOrDefault()
            _entities.DeleteObject(originalContact)
            _entities.SaveChanges()
            Return RedirectToAction("Index")
        Catch
            Return View()
        End Try
    End Function

End Class

Riepilogo

In questa iterazione è stata aggiunta la convalida dei moduli di base all'applicazione Contact Manager. La logica di convalida impedisce agli utenti di inviare un nuovo contatto o modificare un contatto esistente senza fornire valori per le proprietà FirstName e LastName. Inoltre, gli utenti devono fornire numeri di telefono validi e indirizzi di posta elettronica.

In questa iterazione è stata aggiunta la logica di convalida all'applicazione Contact Manager nel modo più semplice possibile. Tuttavia, la combinazione della logica di convalida nella logica del controller creerà problemi a lungo termine. L'applicazione sarà più difficile da gestire e modificare nel tempo.

Nell'iterazione successiva si eseguirà il refactoring della logica di convalida e della logica di accesso al database dai controller. Si useranno diversi principi di progettazione software per consentire di creare un'applicazione più associato e più gestibile.