Dev (Back & Front)ARTIGO

Criando uma enquete com LINQ e AJAX

Neste artigo eu mostro como criar
uma enquete simples usando os recursos do LINQ to SQL e do AJAX. Se você não conhece as tecnologias
LINQ nem AJAX sugiro que você viste os links das referências
para uma introdução ao assunto.

Vou começar mostrando uma visão do
projeto em tempo de desenho:

Podemos identificar os seguintes
recursos no projeto:

  1. Os arquivos criado pelo LINQ to
    SQL
    para mapeamento OR/M;
  2. O banco de dados Pesquisas.mdf
    do SQL Server 2005 Express;
  3. As páginas do projeto e o
    arquivo web.config;
  4. O layout da página da enquete
    com os controles usados;
  5. O componente LinqDataSource;
  6. O ScriptManager para usar os
    recursos do AJAX;

Para acompanhar o construção do
projeto usarei os seguintes recursos:

  • Visual Web Developer 2008
    Express(VWD 2008)
    ou Visual Studio 2008;
  • SQL Server 2005 Express
    Edition;

O objetivo do web site será efetuar
uma enquete sobre quem será o campeão Paulista de 2009. Estou
colocando as 4 opções existentes atualmente: Corinthians,
Palmeiras, Santos e São Paulo (até o dia 18 de abril de 2009 essas eram as
opções).

Ao acessar a página da enquete o
usuário pode selecionar uma opção e ao clicar no botão Vote
será enviado para a página de resultado onde será exibida uma
mensagem de agradecimento ou um aviso de que o usuário já
votou. A página também possui um botão que permite visualizar
o resultado em votos e percentuais.

Vamos iniciar criando um novo web
site abrindo o VWD 2008 e no menu File selecionando new web site;

Selecione o template ASP .NET Web
Site usando a linguagem C# e informe o nome enquete09;

Quando criamos um novo web site na
versão 3.5 da plataforma .NET, leia-se VS 2008 ou VWD 2008, já temos
incluídos de forma automática os registros necessários ao uso do AJAX no
arquivo web.config e os principais controles
ASP .NET AJAX
estarão na ToolBox na guia AJAX Extensions.

A versão do ASP.NET AJAX da versão 3.5 da
plataforma .NET possui diversas melhorias como o suporte da utilização do
UpdatePanel com WebParts,
o suporte para WCF baseado em
JSON, etc., além das correções de diversos
bugs
da versão anterior.

Na página Default.aspx, a partir da ToolBox,
inclua o componente ScriptManager usado para gerenciar os
recursos do AJAX.(A função do Script Manager é gerenciar
a ação de todos os controles AJAX na página.)

Agora vamos criar o banco de dados
clicando no menu WebSite -> Add New Item e selecionando o template
SQL Server DataBase e informando o nome Pesquisas.mdf;

O arquivo Pesquisas.mdf será criado
na pasta App_Data do web site;

Clique duas vezes sobre o banco de
dados e o mesmo será aberto na janela DataBase Explorer;

Expanda os objetos do banco de dados
e clique com o botão direito sobre o item Tables e selecione Add
new Table
;

A seguir vamos definir uma tabela
chamada Paulista com os campos : id , campeao e ip;

O campo id é uma chave primária do
tipo identity(auto-numeração), o campo campeao registra o voto
do usuário e o campo ip registra o ip do usuário permitindo que
o voto seja feito uma única vez. A seguir o leiaute da tabela :

Devemos agora incluir uma
referência ao LINQ to SQL para poder efetuar o mapeamento OR/M;

No menu WebSite clique na opção
Add New Item e em Templates selecione
LINQ to SQL Classes e
informe o nome Paulista.dbml e clique em Add;

Será criado o arquivo Paulista.dbml na pasta
App_Code. Selecionando o arquivo Paulista.dbml na janela
Solution Explorer iremos ver:

A tabela Paulista do banco de
dados será mapeada como uma classe (campos como propriedades, procedures e
funções como métodos
) e você terá no Descritor a classe que representa os
objetos do banco de dados; Cada propriedade definida no objeto Paulista
está mapeada para cada coluna da tabela Paulista (o
nome pode ser alterado
).

O arquivo Paulista.dbml
contém o arquivo XML com informações sobre o leiaute das
tabelas que foram mapeadas e também o descritor contendo as
classes geradas pelo mapeamento. Após encerrar o mapeamento
você já terá acesso aos recursos do LINQ To SQL com
direito a intellisense completo das informações referente as
tabelas mesmo sem conhecer nada sobre elas.

Se você observar as propriedades do
DataContext gerado irá perceber que o nome dado ao
contexto é PaulistaDataContext e verá também
a conexão com o banco de dados Pesquisas.mdf

O Banco de dados é mapeado em um
objeto DataContext permitindo acesso a tabelas de forma
transparente sem termos que nos preocupar com conexão. Teremos
que apenas usar os recursos do LINQ To SQL.

O DataContext é o
responsável por gerar as instruções SQL da sua linguagem de
consulta e então mapear as linhas de dados retornadas a partir
do seu banco de dados para objetos.

Vamos agora efetuar a vinculação
dos objetos com os dados e a interface; a partir da ToolBox, na
aba Data, selecione, arraste e solte o componente
LinqDataSource para o formulário Default.aspx.

A seguir em LinqDataSource Tasks,
marque o item Enable Insert e a seguir clique no link
Configure
Data Source;

Na janela Configure Data Source
aceite a seleção para PaulistaDataContext e clique em Next>;

A seguir defina todos os campos da
tabela Paulista e clique em Finish;

Com isso já podemos usar os
recursos do link para incluir dados na tabela Paulista
registrando assim o voto dos usuários.

Vamos cuidar da interface…

A página para registrar os votos –
Default.aspx

Selecione o arquivo Default.aspx e a
partir da ToolBox, aba AJAX Extensions, inclua um componente
UpdatePanel no formulário web logo abaixo do componente
ScriptManager;

A seguir vamos incluir os
componentes: RadioButtonList , Button e Label no interior do
UpdatePanel conforme o leiaute abaixo:

Vamos agora tratar do código da
página Default.aspx. No evento Click do botão – Vote – inclua o
código abaixo:

protected void butVote_Click(object sender, EventArgs e)<br />    {<br /><br />        //REMOTE_ADDR nem sempre fornece o ip do usuário<br />        //mas o endereço ISP por isso primeiro verifique<br />        //HTTP_X_FORWARDED_FOR para obter o ip real do usuário<br />        <br />        string ip = HttpContext.Current.Request.ServerVariables["HTTP_X_FORWARDED_FOR"];<br /><br />        if (ip == null || ip == string.Empty)<br />        <b>    ip = HttpContext.Current.Request.ServerVariables["REMOTE_ADDR"];</b><br />        <br />        if (ipJaVotou(ip))<br />        {<br />            lblStatus.Text = "Você ja votou !!!.";<br />            Response.Redirect("resultado.aspx?v=ok");<br />        }<br />        else<br />        {<br />            if (radVote.SelectedItem == null)<br />            {<br />                lblStatus.Text = "Informe o seu voto.";<br />            }<br />            else<br />            {<br />                contaVoto(radVote.SelectedItem.ToString(), ip);<br />            }<br />        }<br />    }

Este código obtém o ip do usuário
através de :
HttpContext.Current.Request.ServerVariables[“REMOTE_ADDR”];

Para
recuperar informações dos usuários que acessam um sistema WEB, usamos a
coleção ServerVariables do objeto Request.

A coleção ServerVariables contém
todas as informações geradas a partir de uma determinada requisição WEB
combinada com variáveis do servidor.

Podemos usar duas varíaveis:
HTTP_X_FORWARDED_FOR
e REMOTE_ADDR.


  • HTTP_X_FORWARDED_FOR : recupera
    o IP do HOST caso a conexão à Internet for feita usando um Proxy.
  • REMOTE_ADDR
    : recupera o IP do
    HOST  caso a conexão à internet for feita sem usar um Proxy.

A seguir chama a função ipJaVotou(ip) passando o ip do usuário para verificar se o
usuário já votou.

Se usuário não votou ainda obtemos
o valor do voto e chamamos a rotina contaVoto passando o valor do
voto registrado. Se o usuário já votou chamamos a página
resultado.aspx passando o parâmetro v=0k que indica que o ele
já votou.

O código da função ipJaVotou que
verifica se o usuário já votou é dado a seguir:

 protected Boolean ipJaVotou(string enderecoIP)<br />    {<br />        //não votou<br />        Boolean valor = false;<br />        <br />        PaulistaDataContext db = new PaulistaDataContext();<br /><br />        //verifica quantas vezes o valor ip aparece na tabela<br />        //se for maior que zero significa que o ip ja votou<br />        int contador = (from c in db.Paulistas where c.ip == enderecoIP select c.ip).Count();<br /><br />        if (contador > 0)<br />            //ja votou<br />            valor = true;<br /><br />        // true -> ja votou   <br />        // false -> nao votou<br />        return valor;<br />    }

Neste código eu estou criando uma
instância do DataContext e em seguida usando uma consulta LINQ
com expressão lambda para verificar quantos valores com o ip
fornecido já existem gravados. Se o valor for maior que zero
temos que este ip já foi registrado, neste caso o retorno será
true.

O que são Expressões Lambda ?

As expressões lambda foram incluídas no VS/VB 2008 para dar suporte a consultas LINQ. As cláusulas Where são assim compiladas como expressões lambdas e chamadas em itens aplicáveis do seu dataset. Podem ser consideradas uma forma de delegate que pode passar ou retornar outra função.

Nota: Delegates permitem que uma classe use métodos de outra classe. Para saber mais sobre delegates leia o meu artigo: Usando Delegates

No LINQ as expressões lambda são usadas para realizar ações sobre listas de objetos e com extensões de métodos.

Uma expressão lambda é então uma função sem nome que calcula e retorna um valor único e pode ser usada em qualquer lugar que um tipo delegate for válido.

fonte:  ASP .NET – Usando LINQ – Expressões Lambada

Nota: Em
produção, a rotina para verificação de ip teria que ser mais
bem elaborada.

O código da função contaVoto
usada para registrar o voto é o seguinte:

protected void contaVoto(string voto,string ip)<br />    {<br />        try<br />        {<br />            PaulistaDataContext context = new PaulistaDataContext();<br /><br />            Paulista pt = new Paulista();<br />            pt.campeao = voto;<br />            pt.ip = ip;<br />            context.Paulistas.InsertOnSubmit(pt);<br />            context.SubmitChanges();<br />            lblStatus.Text = "Obrigado por participar.";<br /><br />            Response.Redirect("resultado.aspx");<br />            //lerDados();<br />        }<br />        catch<br />        {<br />            lblStatus.Text = "Erro ao processar o seu voto, tente novamente.";<br />        }<br />    }

Neste código criamos uma instância
do datacontext e da classe Paulista e a seguir atribuímos o voto
e o ip aos campos campeao e ip do objeto pt que é uma instância
da classe Paulista.

Em seguida usamos o método
InsertOnSubmit() do DataContext e para salvar os dados o método
SubmitChanges().

  • InsertOnSubmit() – inclui
    um novo objeto a coleção de Votos incluindo uma entidade em um
    estado pendente de inclusão para esta tabela Paulista;
  • SubmitChanges() – este
    método efetiva a inclusão atual feita pelo InsertOnSubmit()
    na tabela do banco de dados. Deve ser chamado após o método InsertOnSubmit();

Nota: Quando SubmitChanges() é
invocado o LINQ To SQL automaticamente gera e executa comandos
SQL a fim de transmitir as alterações de volta ao banco de
dados. Você pode no entanto sobrescrever este comportamento
chamando uma stored procedure.

Notou que não nos preocupamos com
string de conexão, comandos SQL, criação de objetos para
incluir o registro na tabela, etc.

Exibindo o resultado

A página resultado.aspx tem duas
funções: exibir uma mensagem ao usuário e exibir o resultado
da votação.

Ela é composta pelos controles Label, Button e Literal
conforme o leiaute abaixo:

Vejamos a seguir o código desta
página:

1. No evento Load da página temos:

protected void Page_Load(object sender, EventArgs e)<br />    {<br />        if ( Request.QueryString["v"].Equals("ok"))<br />        {<br />            Label1.ForeColor = System.Drawing.Color.Red;<br />            Label1.Text = " VOCÊ JÁ VOTOU ";<br />        }<br />        else<br />        {<br />            Label1.ForeColor = System.Drawing.Color.Blue;<br />            Label1.Text = " OBRIGADO POR PARTICIPAR DA NOSSA CONSULTA ";<br />        }<br />    }

O código verifica se o usuário já votou exibindo
uma mensagem apropriada.

No evento Click do botão Exibir Resultado
apenas chamamos a rotina lerDados();

protected<br />        void btnResultado_Click(object sender, EventArgs e)<br />
        {<br />
             lerDados();<br />
        }

A rotina lerDados() mostrada a seguir usa
uma consulta LINQ para obter os votos para cada opção e em seguida efetua
os cálculos para exibir o resultado:

protected void lerDados()<br />    {<br />        PaulistaDataContext context = new PaulistaDataContext();<br /><br />        Paulista pt = new Paulista();<br /><br />        var votos = <b>from campeao in context.Paulistas select campeao;</b><br /><br />        int gamba = 0;<br />        int porco = 0;<br />        int peixe = 0;<br />        int santo = 0;<br /><br />        foreach (var voto in votos)<br />        {<br />            if (voto.campeao == "Corinthians")<br />                gamba++;<br />            else if (voto.campeao == "Palmeiras")<br />                porco++;<br />            else if (voto.campeao == "Santos")<br />                peixe++;<br />            else if (voto.campeao == "São Paulo")<br />                santo++;<br />        }<br /><br />        double Total = 0;<br />        Total = gamba + porco + peixe + santo;<br />        double gamba_percentual = 0;<br />        double porco_percentual = 0;<br />        double peixe_percentual = 0;<br />        double santo_percentual = 0;<br /><br />        gamba_percentual = (gamba / Total) * 100;<br />        porco_percentual = (porco / Total) * 100;<br />        peixe_percentual = (peixe / Total) * 100;<br />        santo_percentual = (santo / Total) * 100;<br /><br />        litResultado.Visible = true;<br />        litResultado.Text = "Corinthians: " + gamba + " votos (" + gamba_percentual + "%).<br />";<br />        litResultado.Text = litResultado.Text + "Palmeiras: " + porco + " votos (" + porco_percentual + "%).<br />";<br />        litResultado.Text = litResultado.Text + "Santos: " + peixe + " votos (" + peixe_percentual + "%).<br />";<br /><br />litResultado.Text = litResultado.Text + "São Paulo: " + santo + " votos<br />(" + santo_percentual + "%).<br /><br />";<br />    }

Executando o projeto teremos a página Default.aspx
sendo apresentada;

Após selecionar uma opção e clicar no botão Vote
teremos a página Resultado.aspx exibindo a mensagem e o resultado, se o
usuário clicar no botão Exibir Resultado;

Para perceber a utilização AJAX o correto seria
colocar o botão de resultado na mesma página de votação, esses detalhes e também
o tratamento de erros eu deixo para você se exercitar.

Este é um exemplo básico de utilização do
LINQ to SQL em combinação com
AJAX em uma aplicação ASP .NET útil que pode ser incrementada e usada em
seus projetos.

Pegue o projeto completo aqui:

enquete09.zip

Eu sei é apenas ASP .NET mas eu gosto…

é referência em Visual Basic no Brasil e autor dos livros "Aprenda Rápido: ASP" e "ASP, ADO e Banco de Dados na Internet". Mantenedor do site macoratti.net.

Ver perfil