Itération #3 : Ajouter une validation de formulaire (VB)
par Microsoft
Dans la troisième itération, nous ajoutons la validation de formulaire de base. Nous empêcherons les utilisateurs d’envoyer un formulaire sans remplir les champs de formulaire requis. Nous validons également les adresses e-mail et les numéros de téléphone.
Génération d’une application Gestion des contacts ASP.NET MVC (VB)
Dans cette série de tutoriels, nous créons une application de gestion des contacts complète du début à la fin. L’application Gestionnaire de contacts vous permet de stocker des informations de contact (noms, numéros de téléphone et adresses e-mail) pour une liste de personnes.
Nous créons l’application sur plusieurs itérations. À chaque itération, nous améliorons progressivement l’application. L’objectif de cette approche à itérations multiples est de vous permettre de comprendre la raison de chaque modification.
Itération #1 : créez l’application. Dans la première itération, nous créons le Gestionnaire de contacts de la manière la plus simple possible. Nous ajoutons la prise en charge des opérations de base de données de base de données : Create, Read, Update et Delete (CRUD).
Itération n°2 : rendre l’application agréable. Dans cette itération, nous améliorons l’apparence de l’application en modifiant la ASP.NET vue MVC par défaut master page et la feuille de style en cascade.
Itération n°3 - Ajouter la validation de formulaire. Dans la troisième itération, nous ajoutons la validation de formulaire de base. Nous empêcherons les utilisateurs d’envoyer un formulaire sans remplir les champs de formulaire requis. Nous validons également les adresses e-mail et les numéros de téléphone.
Itération n° 4 : rendre l’application faiblement couplée. Dans cette quatrième itération, nous profitons de plusieurs modèles de conception logicielle pour faciliter la maintenance et la modification de l’application Gestionnaire de contacts. Par exemple, nous refactorisons notre application pour utiliser le modèle référentiel et le modèle d’injection de dépendances.
Itération #5 - Créer des tests unitaires. Dans la cinquième itération, nous rendons notre application plus facile à gérer et à modifier en ajoutant des tests unitaires. Nous modélisons nos classes de modèle de données et créons des tests unitaires pour nos contrôleurs et notre logique de validation.
Itération n°6 - Utiliser le développement piloté par les tests. Dans cette sixième itération, nous ajoutons de nouvelles fonctionnalités à notre application en écrivant d’abord des tests unitaires et en écrivant du code sur les tests unitaires. Dans cette itération, nous ajoutons des groupes de contacts.
Itération n°7 - Ajouter une fonctionnalité Ajax. Dans la septième itération, nous améliorons la réactivité et les performances de notre application en ajoutant la prise en charge d’Ajax.
Cette itération
Dans cette deuxième itération de l’application Gestionnaire de contacts, nous ajoutons la validation de formulaire de base. Nous empêchez les personnes d’envoyer un contact sans entrer de valeurs pour les champs de formulaire obligatoires. Nous validons également les numéros de téléphone et les adresses e-mail (voir la figure 1).
Figure 01 : Formulaire avec validation (Cliquez pour afficher l’image en taille réelle)
Dans cette itération, nous ajoutons la logique de validation directement aux actions du contrôleur. En général, ce n’est pas la méthode recommandée pour ajouter la validation à une application ASP.NET MVC. Une meilleure approche consiste à placer une logique de validation d’application dans une couche de service distincte. Dans l’itération suivante, nous refactorisons l’application Gestionnaire de contacts pour rendre l’application plus facile à gérer.
Dans cette itération, pour simplifier les choses, nous écrivons manuellement tout le code de validation. Au lieu d’écrire le code de validation nous-mêmes, nous pourrions tirer parti d’une infrastructure de validation. Par exemple, vous pouvez utiliser le bloc d’application de validation de bibliothèque d’entreprise Microsoft (VAB) pour implémenter la logique de validation pour votre application ASP.NET MVC. Pour en savoir plus sur le bloc d’application de validation, consultez :
http://msdn.microsoft.com/library/dd203099.aspx
Ajout de la validation à la vue Créer
Commençons par ajouter une logique de validation à la vue Créer. Heureusement, étant donné que nous avons généré la vue Créer avec Visual Studio, la vue Créer contient déjà toute la logique d’interface utilisateur nécessaire pour afficher les messages de validation. La vue Créer est contenue dans la liste 1.
Listing 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 est utilisée pour appliquer un style à la sortie rendue par l’assistance Html.ValidationMessage(). La classe input-validation-error est utilisée pour appliquer un style à la zone de texte (entrée) rendue par l’assistance Html.TextBox(). La classe validation-summary-errors est utilisée pour appliquer un style à la liste non triée rendue par l’assistance Html.ValidationSummary().
Notes
Vous pouvez modifier les classes de feuille de style décrites dans cette section pour personnaliser l’apparence des messages d’erreur de validation.
Ajout d’une logique de validation à l’action Créer
À l’heure actuelle, la vue Créer n’affiche jamais de messages d’erreur de validation, car nous n’avons pas écrit la logique pour générer des messages. Pour afficher les messages d’erreur de validation, vous devez ajouter les messages d’erreur à ModelState.
Notes
La méthode UpdateModel() ajoute automatiquement des messages d’erreur à ModelState en cas d’erreur lors de l’affectation de la valeur d’un champ de formulaire à une propriété. Par exemple, si vous essayez d’affecter la chaîne « apple » à une propriété BirthDate qui accepte des valeurs DateTime, la méthode UpdateModel() ajoute une erreur à ModelState.
La méthode Create() modifiée dans la liste 2 contient une nouvelle section qui valide les propriétés de la classe Contact avant l’insertion du nouveau contact dans la base de données.
Listing 2 - Controllers\ContactController.vb (Créer avec validation)
<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 section validate applique quatre règles de validation distinctes :
- La propriété FirstName doit avoir une longueur supérieure à zéro (et elle ne peut pas se composer uniquement d’espaces)
- La propriété LastName doit avoir une longueur supérieure à zéro (et elle ne peut pas se composer uniquement d’espaces)
- Si la propriété Phone a une valeur (a une longueur supérieure à 0), la propriété Phone doit correspondre à une expression régulière.
- Si la propriété Email a une valeur (a une longueur supérieure à 0), la propriété Email doit correspondre à une expression régulière.
En cas de violation de règle de validation, un message d’erreur est ajouté à ModelState à l’aide de la méthode AddModelError(). Lorsque vous ajoutez un message à ModelState, vous fournissez le nom d’une propriété et le texte d’un message d’erreur de validation. Ce message d’erreur est affiché dans la vue par les méthodes d’assistance Html.ValidationSummary() et Html.ValidationMessage().
Une fois les règles de validation exécutées, la propriété IsValid de ModelState est cochée. La propriété IsValid retourne false quand des messages d’erreur de validation ont été ajoutés à ModelState. Si la validation échoue, le formulaire Créer est réaffiché avec les messages d’erreur.
Notes
J’ai obtenu les expressions régulières pour valider le numéro de téléphone et l’adresse e-mail à partir du référentiel d’expressions régulières à l’adresse http://regexlib.com
Ajout d’une logique de validation à l’action Modifier
L’action Modifier() met à jour un contact. L’action Modifier() doit effectuer exactement la même validation que l’action Créer(). Au lieu de dupliquer le même code de validation, nous devons refactoriser le contrôleur de contacts afin que les actions Create() et Edit() appellent la même méthode de validation.
La classe de contrôleur de contact modifiée est contenue dans la liste 3. Cette classe a une nouvelle méthode ValidateContact() appelée dans les actions Create() et Edit().
Listing 3 - Controllers\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
Résumé
Dans cette itération, nous avons ajouté la validation de formulaire de base à notre application Gestionnaire de contacts. Notre logique de validation empêche les utilisateurs d’envoyer un nouveau contact ou de modifier un contact existant sans fournir de valeurs pour les propriétés FirstName et LastName. En outre, les utilisateurs doivent fournir des numéros de téléphone et des adresses e-mail valides.
Dans cette itération, nous avons ajouté la logique de validation à notre application Gestionnaire de contacts de la manière la plus simple possible. Toutefois, la combinaison de notre logique de validation dans notre logique de contrôleur nous créera des problèmes à long terme. Notre application sera plus difficile à gérer et à modifier au fil du temps.
Dans l’itération suivante, nous allons refactoriser notre logique de validation et la logique d’accès à la base de données à partir de nos contrôleurs. Nous allons tirer parti de plusieurs principes de conception de logiciels pour nous permettre de créer une application plus faiblement couplée et plus facile à gérer.