Compartilhar via


Iteração nº 3 – adicionar validação de formulário (C#)

pela Microsoft

Baixar código

Na terceira iteração, adicionamos validação de formulário básico. Impedimos que as pessoas enviem um formulário sem concluir os campos de formulário necessários. Também validamos endereços de email e números de telefone.

Criando um aplicativo MVC ASP.NET gerenciamento de contatos (C#)

Nesta série de tutoriais, criamos um aplicativo de Gerenciamento de Contatos inteiro do início ao fim. O aplicativo Gerenciador de Contatos permite que você armazene informações de contato - nomes, números de telefone e endereços de email - para uma lista de pessoas.

Criamos o aplicativo em várias iterações. A cada iteração, aprimoramos gradualmente o aplicativo. O objetivo dessa abordagem de iteração múltipla é permitir que você entenda o motivo de cada alteração.

  • Iteração nº 1 – Criar o aplicativo. Na primeira iteração, criamos o Gerenciador de Contatos da maneira mais simples possível. Adicionamos suporte para operações básicas de banco de dados: CRUD (Criar, Ler, Atualizar e Excluir).

  • Iteração nº 2 – Deixe o aplicativo bonito. Nesta iteração, melhoramos a aparência do aplicativo modificando o modo de exibição padrão ASP.NET MVC master página e a folha de estilos em cascata.

  • Iteração nº 3 – Adicionar validação de formulário. Na terceira iteração, adicionamos validação de formulário básico. Impedimos que as pessoas enviem um formulário sem concluir os campos de formulário necessários. Também validamos endereços de email e números de telefone.

  • Iteração nº 4 – acoplar o aplicativo livremente. Nesta quarta iteração, aproveitamos vários padrões de design de software para facilitar a manutenção e a modificação do aplicativo Contact Manager. Por exemplo, refatoramos nosso aplicativo para usar o padrão de repositório e o padrão de injeção de dependência.

  • Iteração nº 5 – Criar testes de unidade. Na quinta iteração, facilitamos a manutenção e a modificação do aplicativo adicionando testes de unidade. Simulamos nossas classes de modelo de dados e criamos testes de unidade para nossos controladores e lógica de validação.

  • Iteração nº 6 – Usar o desenvolvimento controlado por teste. Nesta sexta iteração, adicionamos uma nova funcionalidade ao nosso aplicativo escrevendo testes de unidade primeiro e escrevendo código nos testes de unidade. Nesta iteração, adicionamos grupos de contatos.

  • Iteração nº 7 – Adicionar funcionalidade do Ajax. Na sétima iteração, melhoramos a capacidade de resposta e o desempenho do nosso aplicativo adicionando suporte para o Ajax.

Esta Iteração

Nesta segunda iteração do aplicativo Contact Manager, adicionamos validação de formulário básico. Impedimos que as pessoas enviem um contato sem inserir valores para os campos de formulário necessários. Também validamos números de telefone e endereços de email (consulte a Figura 1).

A caixa de diálogo Novo Projeto

Figura 01: um formulário com validação (clique para exibir a imagem em tamanho real)

Nesta iteração, adicionamos a lógica de validação diretamente às ações do controlador. Em geral, essa não é a maneira recomendada de adicionar validação a um aplicativo MVC ASP.NET. Uma abordagem melhor é colocar a lógica de validação de um aplicativo em uma camada de serviço separada. Na próxima iteração, refatoramos o aplicativo Contact Manager para tornar o aplicativo mais mantenedível.

Nesta iteração, para manter as coisas simples, escrevemos todo o código de validação manualmente. Em vez de escrevermos o código de validação por conta própria, poderíamos aproveitar uma estrutura de validação. Por exemplo, você pode usar o VAB (Microsoft Enterprise Library Validation Application Block) para implementar a lógica de validação para seu aplicativo MVC ASP.NET. Para saber mais sobre o Bloco de Aplicativo de Validação, confira:

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

Adicionando validação ao modo de exibição Criar

Vamos começar adicionando a lógica de validação ao modo de exibição Criar. Felizmente, como geramos o modo de exibição Criar com o Visual Studio, o modo de exibição Criar já contém toda a lógica de interface do usuário necessária para exibir mensagens de validação. O modo de exibição Criar está contido na Listagem 1.

Listagem 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>

Observe a chamada para o método auxiliar Html.ValidationSummary() que aparece imediatamente acima do formulário HTML. Se houver mensagens de erro de validação, esse método exibirá mensagens de validação em uma lista com marcadores.

Observe, além disso, as chamadas para Html.ValidationMessage() que aparecem ao lado de cada campo de formulário. O auxiliar ValidationMessage() exibe uma mensagem de erro de validação individual. No caso da Listagem 1, um asterisco é exibido quando há um erro de validação.

Por fim, o auxiliar Html.TextBox() renderiza automaticamente uma classe Folha de Estilos em Cascata quando há um erro de validação associado à propriedade exibida pelo auxiliar. O auxiliar Html.TextBox() renderiza uma classe chamada input-validation-error.

Quando você cria um novo aplicativo ASP.NET MVC, uma folha de estilos chamada Site.css é criada automaticamente na pasta Conteúdo. Esta folha de estilos contém as seguintes definições para classes CSS relacionadas à aparência das mensagens de erro de validação:

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

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

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

A classe field-validation-error é usada para estilizar a saída renderizada pelo auxiliar Html.ValidationMessage(). A classe input-validation-error é usada para estilizar a caixa de texto (entrada) renderizada pelo auxiliar Html.TextBox(). A classe validation-summary-errors é usada para estilizar a lista não ordenada renderizada pelo auxiliar Html.ValidationSummary().

Observação

Você pode modificar as classes de folha de estilos descritas nesta seção para personalizar a aparência das mensagens de erro de validação.

Adicionando lógica de validação à ação Criar

No momento, o modo de exibição Criar nunca exibe mensagens de erro de validação porque não escrevemos a lógica para gerar mensagens. Para exibir mensagens de erro de validação, você precisa adicionar as mensagens de erro a ModelState.

Observação

O método UpdateModel() adiciona mensagens de erro a ModelState automaticamente quando há um erro ao atribuir o valor de um campo de formulário a uma propriedade. Por exemplo, se você tentar atribuir a cadeia de caracteres "apple" a uma propriedade BirthDate que aceita valores DateTime, o método UpdateModel() adicionará um erro a ModelState.

O método Create() modificado na Listagem 2 contém uma nova seção que valida as propriedades da classe Contact antes que o novo contato seja inserido no banco de dados.

Listagem 2 – Controllers\ContactController.cs (Criar com validação)

//
// 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();
    }
}

A seção validar impõe quatro regras de validação distintas:

  • A propriedade FirstName deve ter um comprimento maior que zero (e não pode consistir apenas em espaços)
  • A propriedade LastName deve ter um comprimento maior que zero (e não pode consistir apenas em espaços)
  • Se a propriedade Phone tiver um valor (tem um comprimento maior que 0), a propriedade Phone deverá corresponder a uma expressão regular.
  • Se a propriedade Email tiver um valor (tem um comprimento maior que 0), a propriedade Email deverá corresponder a uma expressão regular.

Quando há uma violação de regra de validação, uma mensagem de erro é adicionada a ModelState com a ajuda do método AddModelError(). Ao adicionar uma mensagem ao ModelState, você fornece o nome de uma propriedade e o texto de uma mensagem de erro de validação. Essa mensagem de erro é exibida na exibição pelos métodos auxiliares Html.ValidationSummary() e Html.ValidationMessage().

Depois que as regras de validação são executadas, a propriedade IsValid de ModelState é verificada. A propriedade IsValid retorna false quando qualquer mensagem de erro de validação foi adicionada ao ModelState. Se a validação falhar, o formulário Criar será exibido novamente com as mensagens de erro.

Observação

Recebi as expressões regulares para validar o número de telefone e o endereço de email do repositório de expressões regulares em http://regexlib.com

Adicionando lógica de validação à ação editar

A ação Edit() atualiza um Contato. A ação Edit() precisa executar exatamente a mesma validação que a ação Create(). Em vez de duplicar o mesmo código de validação, devemos refatorar o controlador contact para que as ações Create() e Edit() chamem o mesmo método de validação.

A classe de controlador Contact modificada está contida na Listagem 3. Essa classe tem um novo método ValidateContact() que é chamado nas ações Create() e Edit().

Listagem 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();
            }
        }

    }
}

Resumo

Nesta iteração, adicionamos a validação de formulário básico ao nosso aplicativo Do Gerenciador de Contatos. Nossa lógica de validação impede que os usuários enviem um novo contato ou editem um contato existente sem fornecer valores para as propriedades FirstName e LastName. Além disso, os usuários devem fornecer números de telefone e endereços de email válidos.

Nesta iteração, adicionamos a lógica de validação ao aplicativo Contact Manager da maneira mais fácil possível. No entanto, misturar nossa lógica de validação em nossa lógica de controlador criará problemas para nós a longo prazo. Nosso aplicativo será mais difícil de manter e modificar ao longo do tempo.

Na próxima iteração, refatoraremos nossa lógica de validação e a lógica de acesso ao banco de dados de nossos controladores. Aproveitaremos vários princípios de design de software para nos permitir criar um aplicativo mais flexível e mais mantenedor.