Partager via


Itération #3 : Ajouter une validation de formulaire (C#)

par Microsoft

Télécharger le code

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 (C#)

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

Boîte de dialogue New Project

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="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<ContactManager.Models.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 class="fields">
            <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>

    <% } %>

</asp:Content>

Notez l’appel à la méthode d’assistance Html.ValidationSummary() qui apparaît immédiatement au-dessus du formulaire HTML. S’il existe des messages d’erreur de validation, cette méthode affiche les messages de validation dans une liste à puces.

Notez, en outre, les appels à Html.ValidationMessage() qui s’affichent en regard de chaque champ de formulaire. L’assistance ValidationMessage() affiche un message d’erreur de validation individuel. Dans le cas de la liste 1, un astérisque s’affiche en cas d’erreur de validation.

Enfin, l’assistance Html.TextBox() affiche automatiquement une classe Feuille de style en cascade lorsqu’une erreur de validation est associée à la propriété affichée par l’assistance. L’assistance Html.TextBox() affiche une classe nommée input-validation-error.

Lorsque vous créez une application ASP.NET MVC, une feuille de style nommée Site.css est automatiquement créée dans le dossier Contenu. Cette feuille de style contient les définitions suivantes pour les classes CSS liées à l’apparence des messages d’erreur de validation :

.field-validation-error
{
    color: #ff0000;
}

.input-validation-error
{
    border: 1px solid #ff0000;
    background-color: #ffeeee;
}

.validation-summary-errors
{
    font-weight: bold;
    color: #ff0000;
}

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.cs (Créer avec validation)

//
// POST: /Contact/Create

[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Create([Bind(Exclude = "Id")] Contact contactToCreate)
{
    // Validation logic
    if (contactToCreate.FirstName.Trim().Length == 0)
        ModelState.AddModelError("FirstName", "First name is required.");
    if (contactToCreate.LastName.Trim().Length == 0)
        ModelState.AddModelError("LastName", "Last name is required.");
    if (contactToCreate.Phone.Length > 0 && !Regex.IsMatch(contactToCreate.Phone, @"((\(\d{3}\) ?)|(\d{3}-))?\d{3}-\d{4}"))
        ModelState.AddModelError("Phone", "Invalid phone number.");
    if (contactToCreate.Email.Length > 0 && !Regex.IsMatch(contactToCreate.Email, @"^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$"))
        ModelState.AddModelError("Email", "Invalid email address.");
    if (!ModelState.IsValid)
        return View();

    // Database logic
    try
    {
        _entities.AddToContactSet(contactToCreate);
        _entities.SaveChanges();
        return RedirectToAction("Index");
    }
    catch
    {
        return View();
    }
}

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

using System.Linq;
using System.Text.RegularExpressions;
using System.Web.Mvc;
using ContactManager.Models;

namespace ContactManager.Controllers
{
    public class ContactController : Controller
    {
        private ContactManagerDBEntities _entities = new ContactManagerDBEntities();

        protected void ValidateContact(Contact contactToValidate)
        {
            if (contactToValidate.FirstName.Trim().Length == 0)
                ModelState.AddModelError("FirstName", "First name is required.");
            if (contactToValidate.LastName.Trim().Length == 0)
                ModelState.AddModelError("LastName", "Last name is required.");
            if (contactToValidate.Phone.Length > 0 && !Regex.IsMatch(contactToValidate.Phone, @"((\(\d{3}\) ?)|(\d{3}-))?\d{3}-\d{4}"))
                ModelState.AddModelError("Phone", "Invalid phone number.");
            if (contactToValidate.Email.Length > 0 && !Regex.IsMatch(contactToValidate.Email, @"^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$"))
                ModelState.AddModelError("Email", "Invalid email address.");
        }

        public ActionResult Index()
        {
            return View(_entities.ContactSet.ToList());
        }

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

        [AcceptVerbs(HttpVerbs.Post)]
        public ActionResult Create([Bind(Exclude = "Id")] Contact contactToCreate)
        {
            // Validation logic
            ValidateContact(contactToCreate);
            if (!ModelState.IsValid)
                return View();

            // Database logic
            try
            {
                _entities.AddToContactSet(contactToCreate);
                _entities.SaveChanges();
                return RedirectToAction("Index");
            }
            catch
            {
                return View();
            }
        }

        public ActionResult Edit(int id)
        {
            var contactToEdit = (from c in _entities.ContactSet
                                   where c.Id == id
                                   select c).FirstOrDefault();

            return View(contactToEdit);
        }

        [AcceptVerbs(HttpVerbs.Post)]
        public ActionResult Edit(Contact contactToEdit)
        {
            ValidateContact(contactToEdit);
            if (!ModelState.IsValid)
                return View();

            try
            {
                var 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();
            }
        }

        public ActionResult Delete(int id)
        {
            var contactToDelete = (from c in _entities.ContactSet
                                 where c.Id == id
                                 select c).FirstOrDefault();

            return View(contactToDelete);
        }

        [AcceptVerbs(HttpVerbs.Post)]
        public ActionResult Delete(Contact contactToDelete)
        {
            try
            {
                var 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();
            }
        }

    }
}

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 Contact Manager de la manière la plus simple possible. Toutefois, le fait de mélanger notre logique de validation à notre logique de contrôleur nous posera des problèmes à long terme. Notre application sera plus difficile à maintenir et à modifier au fil du temps.

Dans l’itération suivante, nous allons refactoriser notre logique de validation et notre 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.