Iteração nº 3 – adicionar validação de formulário (VB)
pela Microsoft
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 de gerenciamento de contatos ASP.NET MVC (VB)
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: CRIAR, Ler, Atualizar e Excluir (CRUD).
Iteração nº 2 – deixe o aplicativo bonito. Nesta iteração, melhoramos a aparência do aplicativo modificando o padrão ASP.NET exibição MVC master página e 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 de forma flexível. 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 de nosso aplicativo adicionando suporte ao Ajax.
Esta iteração
Nesta segunda iteração do aplicativo Contact Manager, adicionamos validação de formulário básica. 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).
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 escrever o código de validação nós mesmos, 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 ASP.NET MVC. 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 à 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="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>
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 ao ModelState.
Observação
O método UpdateModel() adiciona mensagens de erro ao 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.vb (Criar com validação)
<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
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 (tiver 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 ao 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á reproduzido 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 Criar(). Em vez de duplicar o mesmo código de validação, devemos refatorar o controlador de contato 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.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
Resumo
Nesta iteração, adicionamos a validação de formulário básico ao nosso aplicativo do Contact Manager. 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.