ASP .NET MVC 3 - Apresentando os recursos básicos para iniciantes -  II


Este artigo é essencialmente prático e mostra como criar uma aplicação ASP .NET MVC3 usando a ferramenta gratuita Visual Web Developer 2010 Express Edition.

Na primeira parte eu dei uma introdução em alguns aspectos básicos do ASP .NET MVC e neste artigo eu vou mostrar algo mais funcional que nos permita avançar no aprendizado do ASP .NET MVC.

Vamos criar uma aplicação Web para enviar convites. Será uma aplicação simples que terá as seguintes funcionalidades:

Vamos aproveitar a estrutura já criada na primeira parte do artigo (você pode criar outro projeto se desejar);

Abra o Visual Web Developer 2010 Express Editon e no menu File -> Open Project selecione o o projeto Convites;

Vamos começar exibindo a informação sobre a festa e para isso vamos alterar a view index.cshtml que criamos na primeira parte com o seguinte código:


<html>
<head>
    <title>Index</title>
</head>
<body>
    <div>
       <div>
        @ViewBag.Convite Galera , Recordar é viver ! (view)
        <p>Não perca a nossa festa estilo anos 60<br />
       </p>Tire sua fantasia do armário e venha se divertir <br />
</div>
    </div>
</body>
</html>

Ao lado vemos a exibição da informação sobre a festa após a execução do projeto.

Não fizemos nada de novo aqui apenas incluímos um texto sobre a festa.

Definindo o Model

O modelo na arquitetura MVC é a representação dos objetos do mundo real, processos e regras que definem o domínio da nossa aplicação. Ele contém os objetos que compõem o universo da nossa aplicação e os métodos que nos permitem manipulá-los.

As views e os controllers expõem o domínio para os nossos clientes de forma consistente Uma aplicação MVC bem projetada começa com um modelo bem concebido, que é então o ponto focal quando nos vamos adicionar os controllers e as views.

O nosso modelo será bem simples; vamos usar uma classe de domínio chamada RespostaConvite e esse objeto será responsável por armazenar e validar a confirmação do convite.

A convenção MVC é que as classes que compõem um modelo são colocados dentro da pasta ~/Models.

Para incluir um modelo clique com o botão direito do mouse sobre a pasta Model e selecione a opção Add -> Class. A seguir informe o nome RespostaConvite para a classe e define o código abaixo nesta classe:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

namespace Convites.Models
{
    public class RespostaConvite
    {
        public string Nome { get; set; }
        public string Email { get; set; }
        public string Fone { get; set; }
        public bool? VemNaFesta { get; set; }
    }
}
A classe RespostaConvite representa o nosso domínio e contém as propriedades:
Nome, Email, Fone e VemNaFesta

Observe que a propriedade VemNaFesta é do tipo Nullabe e dessa forma
pode receber os valores false, true e null

Note que na janela Solution Explorer na pasta Models vemos a classe
RespostaConvite.cs

Um dos requisitos da nossa aplicação web é apresentar um formulário para que o cliente responda ao convite e para isso vamos incluir um link na view (arquivo index.cshtml) que contém a informação sobre a festa. Altere o código do arquivo index.cshtml conforme abaixo:

@{
    Layout = null;
}
<!DOCTYPE html>
<html>
<head>
    <title>Index</title>
</head>
<body>
    <div>
       <div>
        @ViewBag.Convite Galera , Recordar é viver ! (view)
        <p>Não perca a nossa festa estilo anos 60<br />
       </p>Tire sua fantasia do armário e venha se divertir <br />
        <p>@Html.ActionLink("Responda Agora", "RsvpForm")</p>
       </div>
    </div>
</body>
</html>

Para definir e exibir o link na página incluímos o código: @Html.ActionLink("Responda Agora", "RsvpForm")

Html.ActionLink é um método Helper HTML que permite exibir um  link com um texto.

O framework MVC vem com uma coleção de métodos Helpers (auxiliares) que são convenientes para a renderizar links em HTML, entradas de texto, caixas de seleção, seleções, e até mesmo controles personalizados.

O método ActionLink tem dois parâmetros:

  1. O primeiro é o texto a ser exibido no link;
  2. O segundo é a ação a ser executada quando o usuário clicar no link;

Abaixo vemos a execução do projeto, agora exibindo o link para o formulário de resposta: RsvpForm;

O link aponta para a URL: http://localhost:54649/Home/RsvpForm

O método Html.ActionLink inspecionou a configuração de roteamento URL do nosso aplicativo e concluiu que /Home/RsvpForm é a URL para uma ação chamada RsvpForm em um controlador chamado HomeController.

Observe que, ao contrário dos aplicativos tradicionais ASP.NET, as URLs MVC não correspondem a arquivos físicos. Cada método de Action tem a seu própria URL, e o MVC utiliza o roteamento ASP.NET para traduzir estas URLs em ações.

Criando um método Action

Se você clicar no link vai ser direcionado para uma página de erro visto que ainda não criamos o método Action correspondente a URL /Home/RsvpForm.

Vamos fazer isso incluindo um método chamado RsvpForm a nossa classe HomeController conforme o código a seguir:

using System.Web.Mvc;
using System;

namespace Convites.Controllers
{
    public class HomeController : Controller
    {
        //
        // GET: /Home/

        public ViewResult Index()
        {
            int hora = DateTime.Now.Hour;
            ViewBag.Saudacao = hora < 12 ? "Bom dia" : "Boa tarde";
            return View();
        }

        public ViewResult RsvpForm()
        {
            return View();
        }
    }
}

Incluindo uma View fortemente tipada

Vamos agora adicionar uma view para o nosso método action RsvpForm, mas vamos fazer algo um pouco diferente, vamos criar uma view fortemente tipada.

Uma view fortemente tipada se destina a renderizar uma tipo de domínio específico, e se nós especificamos o tipo com o qual queremos trabalhar (nosso exemplo o tipo é RespostaConvite), o MVC pode criar alguns atalhos úteis para tornar isso mais fácil.

Antes de continuar compile o projeto MVC.

1- Clique com o botão direito do mouse no interior do método Action RsvpForm e selecione Add View;
2- Marque a opção - Create a strongly-typed view e selecione : RespostaConvite (Convites.Models) do menu dropdown;
3- Desmarque a opção Use a layout or master page;
4- Escolha o engine Razor e defina o template Scaffold como Empty;

Clique no botão Add para criar a nova view. O Visual Web Developer irá abrir o arquivo RvspForm.cshtml criado. Você vai ver que ele é um esqueleto de um arquivo HTML com um bloco Razor @model. Esta é a chave para uma visão fortemente tipada e a comodidade que ele oferece.

Construindo o formulário

Agora que criamos a view fortemente tipada podemos construir o conteúdo do RsvpForm.cshtml para torná-lo em um formulário HTML para edição de objetos RespostaConvite.

Para isso altere o código conforme abaixo:

@model Convites.Models.RespostaConvite
@{
    Layout = null;
}
<!DOCTYPE html>
<html>
<head>
    <title>formulário de resposta: RsvpForm</title>
</head>
<body>
    <div>
        @using (Html.BeginForm()) 
        {
            <p>Nome: @Html.TextBoxFor(x => x.Nome) </p>
            <p>Email: @Html.TextBoxFor(x => x.Email)</p>
            <p>Fone: @Html.TextBoxFor(x => x.Fone)</p>
            <p>Você vai vir na festa ?
                @Html.DropDownListFor(x => x.VemNaFesta, new[] {
                new SelectListItem() {Text = "Sim, não vou perder essa....", Value = bool.TrueString},
                new SelectListItem() {Text = "Não, fica para a próxima...", Value = bool.FalseString}
                }, "Escolha a sua opção ")
            </p>
            <input type="submit" value="Submeter Resposta" />
        }
    </div>
</body>
</html>

Para cada propriedade da classe RespostaConvite, usamos um método auxiliar para renderizar um controle de entrada HTML adequado. Estes métodos permitem que você selecione a propriedade com a qual o elemento de entrada se refere usando uma expressão lambda, da seguinte forma : @ Html.TextBoxFor (x => x.Fone)

Na linguagem C# todas as expressões lambda usam o operador lambda =>, que é lido como "vai para".O lado esquerdo do operador lambda especifica os parâmetros de entrada (se houver) e o direito contém a expressão ou o bloco de instruções A expressão lambda x => x * x é lida assim : " x recebe x vezes x. "

O método Helper HTML gera o código HTML que cria um elemento de entrada, define o tipo de parâmetro para texto, e define os atributos id e nome para o telefone e o nome da propriedade da classe de domínio selecionada como se segue: <input id="Fone" name="Fone" type="text" value="" />

Este recurso funciona porque a nossa view RsvpForm é fortemente tipada, e o MVC RespostaConvite é o tipo que nós queremos renderizar com essa view.

Uma alternativa ao uso de expressões lambda é se referir ao nome da propriedade tipo de modelo como uma string, da seguinte forma: @ Html.TextBox ("Email")

Outro método auxiliar é o método Html.BeginForm, que gera um elemento de formulário HTML configurado para um postback para o método action. Uma vez que não se passaram os parâmetros para o método auxiliar, ele assume que queremos dar um postback para a mesma URL. Um truque é usar isso em uma declaração using :

@using (Html.BeginForm()) {
   ...conteúdo do formulario...
   }

Normalmente a instrução using garante que um objeto é descartado quando sai do escopo. Ele é usado para conexões de bancos de dados, por exemplo, para se certificar de que elas serão fechadas assim que uma consulta for concluída.

Em vez de descartar um objeto, o Helper Html.BeginForm fecha o elemento de formulário HTML quando sai do escopo. Isto significa que o método Html.BeginForm cria ambas as partes de um elemento de formulário :

<form action="/Home/RsvpForm" method="post">
...conteudo do formulario...
</form>

Executando o projeto iremos obter os seguintes resultados:

1- O formulário apresentando as mensagens sobre a festa e o link para o formulário de resposta;
2- O formulário de resposta;

Manipulando formulários

Nós não dissemos para o MVC o que queremos fazer quando o formulário for enviado para o servidor. Como as coisas estão, clicando no botão Submeter apenas apaga os valores que você digitou no formulário. Isso ocorre porque o formulário é enviado de volta para o método action RsvpForm no controller Home, o qual apenas faz com que o MVC renderize a view novamente.

Obs: Você pode ficar intrigado pelo fato das informações digitadas serem perdidas quando a view for renderizada novamente. Mas lembre-se que, diferente de uma aplicação Web Form, o MVC não preserva os dados automaticamente.

Para receber e processar os dados do formulário sumbetido temos que incluir mais um método Action RsvpForm afim de criar o seguinte:

Manipulando solicitações GET e POST em métodos separados ajuda a manter o nosso código arrumado, uma vez que os dois métodos têm responsabilidades diferentes. Ambos os métodos action são chamados pela mesma URL, mas o MVC garante que o método apropriado seja chamado, dependendo se estamos lidando com um pedido GET ou POST.

Altere o código da classe HomeController.cs conforme o código abaixo:

using System.Web.Mvc;
using System;
using Convites.Models;

namespace Convites.Controllers
{
    public class HomeController : Controller
    {
        //
        // GET: /Home/
        public ViewResult Index()
        {
            int hora = DateTime.Now.Hour;
            ViewBag.Saudacao = hora < 12 ? "Bom dia" : "Boa tarde";
            return View();
        }

        [HttpGet]
        public ViewResult RsvpForm()
        {
            return View();
        }

        [HttpPost]
        public ViewResult RsvpForm(RespostaConvite respostaConvite)
        {
            // TODO: Enviar um Email para o organizador da festa
            return View("Obrigado", respostaConvite);
        }
    }
}

Nós adicionamos o atributo HttpGet ao nosso método action RsvpForm. Este atributo diz ao MVC que este método deverá usando somente para requisições GET.
A seguir, incluímos uma sobrecarga ao método RsvpForm, que usa um parâmetro e aplica o atributo HttpPost.

O atributo HttpPost diz ao MVC que o método vai lidar com requisições POST. Observe que tivemos que incluir o namespace Convite.Models pois estamos usando o tipo RespostaConvite sem ter que qualificar o nome da classe.

Usando o Model Binding

A primeira sobrecarga do método action RsvpForm renderiza a mesma view de antes. Ela gera a formulário de reposta vazio.

Sobrecarga ou Overloading o que é isso ? Se você esta vindo de uma linguagem procedural como Clipper, Dbase , Basic ou se esta começando agora tendo o C# como sua primeira linguagem de programação pode estranhar o termo. Mas é apenas uma questão de prática.

Sobrecarga é a habilidade de poder definir diversas propriedades , métodos ou procedimentos em uma classe com o mesmo nome e assinaturas diferentes.

A segunda sobrecarga é mais interessante por causa do parâmetro, mas dado que o método action será invocado em resposta a um pedido HTTP POST, e que o tipo RespostaConvite é uma classe C#, como vinculamos os dois ?

A resposta é : usando o model binding.

O model binding é um recurso MVC muito útil no qual os dados de entrada são analisados e os pares chave/valor são usados para preencher propriedades de tipos do modelo do domínio.

Este processo é o oposto à utilização dos métodos Helper HTML, ou seja, ao criar os dados do formulário para enviar para o cliente, geramos os elementos HTML de entrada, onde os valores para os atributos id e nome foram derivados dos nomes das propriedades da classe do modelo.

Usando o model binding, os nomes dos elementos de entrada são utilizados para definir os valores das propriedades em uma instância da classe do modelo, que é então passado para o nosso método action POST.

O Model Binding é um recurso poderoso e personalizável que elimina o trabalho de lidar com solicitações HTTP, permitindo-nos trabalhar com objetos C# em vez de lidar com valores Request.Form[] e Request.QueryString[].

Dessa forma o objeto RespostaConvite é passado como parâmetro para nosso método action sendo automaticamente preenchido com os dados dos campos do formulário.

Renderizando outras Views

A segunda sobrecarga do método action RsvpForm também demonstra como podemos dizer ao MVC para renderizar uma view específica em resposta a um pedido. Aqui está a declaração : return View("Obrigado", respostaConvite);

Esta chamada para o método View diz ao MVC para encontrar e processar uma view chamada Obrigado e passar o objeto respostaConvite para a view.

Para criar a view especificada clique com o botão direito do mouse no interior de um dos métodos da classe HomeController.cs e selecione Add View;

- Defina o nome da View como Obrigado;
- Como vamos criar outra view fortemente tipada marque a opção - Create a Strongly-typed view;
- A classe de dados que selecionamos para view deve corresponder com a classe que passmos para view usando o método View, então selecione a classe RespostaConvite do menu dropdown.;
-
Desmarque a opção Use a layout or master page;
- Escolha o engine Razor e defina o template Scaffold como Empty;

Clique no botão Add para criar a View;

Como a view esta associada com o controller Home o MVC cria a view ~/View/Home/Obrigado.cshtml.

@model Convites.Models.RespostaConvite
@{
Layout = null;
}
<!DOCTYPE html>
<html>
 <head>
   <title>Agradecimento</title>
  </head>
  <body>
  <div>
   <h1>Obrigado, @Model.Nome!</h1>
   @if (Model.VemNaFesta == true)
  {
    @:Você não vai se arrepender. As bebidas já estão na geladeira !
    } else {
    @:Por nos avisar. Lamento por você; quem sabe na próxima....
  }

  </div>
</body>
</html>

A view Obrigado usa o Razor para exibir o conteúdo com base no valor das propriedades RespostaConvite que nós passamos para o método View no método de action RsvpForm.

O operador Razor @model especifica o tipo de modelo de domínio com o qual a view esta fortemente tipada.

Para acessar o valor de uma propriedade no objeto de domínio, usamos Model.PropertyName. Por exemplo, para obter o valor da propriedade Nome, usamos chamamos Model.Nome.

Agora que nós criamos a view Obrigado, temos um exemplo de trabalho.

O resultado obtido é visto na figura abaixo:

1- A página de apresentação;
2- Formulário preenchido;
3- Resposta feita após a submissão do formulário de resposta;

Incluindo validação

Podemos agora adicionar a validação na nossa aplicação. Se não fizermos isso, nossos usuários podem entrar com dados sem sentido ou até mesmo apresentar um formulário vazio.

Numa aplicação MVC a validação é aplicada no modelo do domínio e não na interface do usuário.

Isso significa que nós definimos os nossos critérios de validação em um lugar, e isso produz os efeitos em qualquer lugar que o modelo é usado.

A ASP.NET MVC suporta regras de validação declarativas definidas com atributos do namespace System.ComponentModel.DataAnnotations.

Os atributos Data Annotation foram introduzido no .NET 3.5 como uma forma de adicionar a validação para as classes usadas por aplicações ASP.NET. Desde aquela época, o RIA Services começou a usar anotações de dados e eles agora fazem parte do Silverlight também. No EF 4.0 o Code-First permite que você construa um EDM usando código (C#/VB .NET) e também permite realizar a validação com atributos Data Annotations.

Para este recurso devemos usar o namespace System.ComponentModel.DataAnnotations pois é ele que provê atributos de classes (usados para definir metadados) e métodos que podemos usar em nossas classes para alterar as convenções padrão e definir um comportamento personalizado que pode ser usado em vários cenários.

O código abaixo mostra como esses atributos podem ser aplicado à classe RespostaConvite:

using System.ComponentModel.DataAnnotations;

namespace Convites.Models
{
    public class RespostaConvite
    {
        [Required(ErrorMessage = "Informe o seu nome")]
        public string Nome { get; set; }
       
        [Required(ErrorMessage = "Informe o seu email")]
        [RegularExpression(".+\\@.+\\..+",
        ErrorMessage = "Informe um email válido...")]

        public string Email { get; set; }

        [Required(ErrorMessage = "Informe o seu telefone")]
        public string Fone { get; set; }

        [Required(ErrorMessage = "Informe se você Vai ou Não Vai na festa")]
        public bool? VemNaFesta { get; set; }
    }
}

As regras de validações são exibidas em negrito. O MVC detecta os atributos de validação e os utiliza para validar os dados durante o processo model binding. Repare que nós importamos o namespace que contém as validações, assim podemos nos referir a eles sem precisar qualificar seus nomes.

Podemos verificar para ver se houve um problema de validação usando a propriedade ModelState.IsValid na nossa classe controlador. O código a seguir mostra como fazer isso no nosso método action RsvpForm POST.

using System.Web.Mvc;
using System;
using Convites.Models;

namespace Convites.Controllers
{
    public class HomeController : Controller
    {
        //
        // GET: /Home/
        public ViewResult Index()
        {
            int hora = DateTime.Now.Hour;
            ViewBag.Saudacao = hora < 12 ? "Bom dia" : "Boa tarde";
            return View();
        }

        [HttpGet]
        public ViewResult RsvpForm()
        {
            return View();
        }

        [HttpPost]
        public ViewResult RsvpForm(RespostaConvite respostaConvite)
        {
            if (ModelState.IsValid)
            {
            
   // TODO: Enviar um Email para o organizador da festa
                return View("Obrigado", respostaConvite);
            }
            else
            {
           
    //Ocorreu um erro durante a validação - reexibe o formulário
                return View();
            }

        }
    }
}

Se não houver erros de validação, dizemos MVC para renderizara view Obrigado como fizemos anteriormente. Se houver erros de validação, nós renderizamos novamente a view RsvpForm chamando o método View, sem quaisquer parâmetros.

Precisamos mostrar os erros de validação para o usuário, e podemos fazer isso usando o Método Helper(auxiliar) Html.ValidationSummary na view RsvpForm, como mostrado no trecho de código a seguir do arquivo RsvpForm.cshtml:

...
<body>
@using (Html.BeginForm()) {
@Html.ValidationSummary()
<p>Nome: @Html.TextBoxFor(x => x.Nome) </p>
<p>Email: @Html.TextBoxFor(x => x.Email)</p>
...

Se não houver erros, o método Html.ValidationSummary cria um item de lista oculta como um espaço reservado no formulário. MVC torna espaço reservado visível e adiciona as mensagens de erro definidas pelos atributos de validação conforme mostra a figura abaixo:

O usuário visualizar a view Obrigado até que todos os requisitos de validação aplicados a classe RespostaConvite sejam satisfeitos.

Observe que os dados inseridos no formulário foram preservados e exibidos novamente quando a exibição foi renderizada com o resumo de validação. Este é um benefício que recebemos ao usar model binding (modelo de ligação).

Se você já trabalhou com ASP.NET Web Forms, você sabe que os formulários da Web tem o conceito de "controles de servidor" que mantêm o estado pela serializar dos valores em um campo de formulário oculto chamado __VIEWSTATE. O model binding do ASP.NET MVC não esta relacionado com os conceitos dos controles de servidores, postbacks, ou View State do Web Forms. O ASP.NET MVC não injeta um campo oculto __VIEWSTATE em suas páginas HTML.

Destacando campos inválidos

Os métodos de helper HTML que criam caixas de texto, drop-downs, e outros elementos têm um recurso muito útil que pode ser usado em conjunto com a model binding. O mesmo mecanismo que preserva os dados que um usuário introduziu em um formulário pode também ser utilizado para destacar campos individuais que falharam durante as verificações de validação.

Quando uma propriedade do modelo falhar na validação, os métodos helper HTML irão gerar um HTML um pouco diferente. Como exemplo, aqui está o código HTML que uma chamada para Html.TextBoxFor (x => x.Nome) gera quando não há erro de validação:

<input data-val="true" data-val-required="Informe o seu nome" id="Nome" name="Nome" type="text" value="" />

E abaixo temos o HTML gerado quando o usuário não fornece um valor causando um erro de validação quando aplicamos o atributo necessário na propriedade Nome do modelo RespostaConvite:

<input class="input-validation-error" data-val="true" data-val-required="Informe o seu nome" id="Nome" name="Nome" type="text" value="" />

Destacamos a diferença em negrito. Este método helper incluiu uma classe CSS chamada inputvalidation-error.

Diferentes métodos auxiliares aplicam diferentes classes CSS, mas todos eles podem ser encontrados no arquivo de estilo ~/Content/Site.css que é adicionado a todos os projetos MVC. Para usar esta folha de estilo, adicionamos uma nova referência para a seção de head da view RsvpForm da seguinte forma:

<link rel="Stylesheet" href="@Href("~/Content/Site.css")" type="text/css"/>

Após fazer isso teremos o seguinte resultado quando ocorrer um erro de validação:

Enviando um Email

Para encerrar o exemplo vamos implementar a funcionalidade para enviar um email para o organizador da festa.

Nós poderíamos fazer isso adicionando um método action para criar e enviar uma mensagem de e-mail usando as classes do Framework. NET. Em vez disso, vamos usar o método auxiliar WebMail. Ele não é parte do framework MVC, mas não vamos concluir o exemplo sem sem nos preocupar com detalhes para o envio de e-mail.

Queremos que a mensagem de email seja enviada quando renderizarmos a view Obrigado. Para isso vamos fazer as seguintes alterações no arquivo Obrigado.cshtml :

@model Convites.Models.RespostaConvite
@{
Layout = null;
}
<!DOCTYPE html>
<html>
 <head>
   <title>Agradecimento</title>
  </head>
  <body>

  @{
    try {
            WebMail.SmtpServer = "smtp.exemplo.com";
            WebMail.SmtpPort = 587;
            WebMail.EnableSsl = true;
            WebMail.UserName = "meu_Smtp_Username";
            WebMail.Password = "meu_Smtp_Password";
            WebMail.From = "macoratti@exemplo.com";
            WebMail.Send("organizador@exemplo.com", "Notificação de resposta: ",
            Model.Nome + " é " + ((Model.VemNaFesta ?? false) ? "" : "não")
            + "atendida");
        } catch (Exception) {
            @:<b>Não foi possível enviar o e-mail para confirmar sua resposta.</b>
    }
    }


  <div>
   <h1>Obrigado, @Model.Nome!</h1>
   @if (Model.VemNaFesta == true)
  {
    @:Você não vai se arrepender. As bebidas já estão na geladeira !
    } else {
    @:Por nos avisar. Lamento por você; quem sabe na próxima....
  }
  </div>
</body>
</html>

Adicionamos um bloco de código Razor que usa o helper WebMail para configurar os detalhes de nosso servidor de e-mail, incluindo o nome do servidor, se o servidor requer conexões SSL, e detalhes da conta.

Uma vez que você configurou todos os detalhes, usamos o método WebMail.Send para enviar o e-mail. Colocamos todo o código e-mail em um bloco try ... catch para que possamos alertar o usuário se o e-mail não for enviado. Fazemos isso adicionando um bloco de texto para a saída da view Obrigado. Uma abordagem melhor seria apresentar uma view de erro separada quando a mensagem de e-mail não puder ser enviada, mas para ficar mais simples usamos este recurso.

Dessa forma criamos um projeto MVC que foi usado para criar uma aplicação simples de entrada de dados, abordando os recursos básicos da arquitetura do Framework MVC.

Aguarde em breve mais artigos sobre o assunto.

Pegue o projeto completo aqui: Convites_MVC.zip

João 3:19 E o julgamento é este: A luz veio ao mundo, e os homens amaram antes as trevas que a luz, porque as suas obras eram más.
João 3:20
Porque todo aquele que faz o mal aborrece a luz, e não vem para a luz, para que as suas obras não sejam reprovadas.
João 3:21
Mas quem pratica a verdade vem para a luz, a fim de que seja manifesto que as suas obras são feitas em Deus.

Referências:


José Carlos Macoratti