Dev (Back & Front)ARTIGO

Passando um Dataset do ASP.NET para o JavaScript

O Ajax.net é uma biblioteca fantástica e possui recursos muito interessantes. Como, por exemplo, o updatepanel que só precisamos colocar dentro a parte da página que precisa ser atualizada dinamicamente e ele faz todo o resto automaticamente. Mas quando precisamos desenvolver uma aplicação com um grande número de acesso e de tráfego de dados não seria uma boa prática de desenvolvimento usar o updatepanel.

Um dos conceitos do Ajax é a de que o browser não seja usado apenas para exibir informações, mas sim que ele seja usado como uma extensão da aplicação. E quando desenvolvemos uma aplicação utilizando o updatepanel do AJAX.NET toda a lógica de negócio fica no servidor – contrariando assim o conceito do Ajax – e perdendo desempenho. Pois, ao invés de retornar apenas os dados, o .NET retorna o HTML pronto para exibição e atualiza tudo o que esta dentro do updatepanel. Só que por outro lado não podemos simplesmente passar os dados para o JavaScript. Você não pode simplesmente passar um dataset do .net para o JavaScript.

Aqui iremos desenvolver uma pequena aplicação que contém uma função que consegue fazer exatamente isso, na verdade iremos transformar o dataset em uma estrutura de dados que pode ser passada para o JavaScript. E veremos as diferença entre usar o updatepanel e deixar o JavaScript preencher a página.

Vamos ao trabalho

Para desenvolver este exemplo, utilizarei a Microsoft Visual Web Developer 2005 Express Edition com o Ajax control toolkit instalado e um banco de dados ACCESS.

Iremos começar pelo banco de dados. Crie um banco do ACCESS chamado “teste.mdb” e dentro dele devemos criar uma tabela chamada “clientes”, com três campos:

  • codCliente – numeração automática
  • Nome – texto
  • Telefone – texto

Insira alguns dados no banco de dados que criamos.

Primeiro crie um novo web site e escolha o template Ajax Control Toolkit Web Site e escolha a linguagem C#.

No HTML abaixo não há nada demais. Basicamente ele é composto de um scriptmanager que registra um JavaScript um detalhe muito importante, o parâmetro enablepagemethods=”true” pois ele é quem habilita a página para chamar os métodos assincronamente, uma div que receberá as informações dos clientes, uma div que é preenchida com a data atual todas as vezes que é feito um postback e de três botões:

  • btnClientSide – Que preenchera o formulário assincronamente.
  • btnServerSide – Que chamara uma função no servidor para preencher o formulário através de um updatepanel.
  • Limpar – Que limpa o formulário.

Abra a página Default.aspx e codifique o HTML da seguinte maneira:

<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">

<link href="css/StyleSheet.css" rel="stylesheet" type="text/css" />


<html xmlns="http://www.w3.org/1999/xhtml">
    
<head id="Head1" runat="server">
    <title>Passando Dataset para o javascript</title>
</head>

<body>

    <form id="Form1" runat="server">
        
        <asp:scriptmanager id="scriptmanager1" 
         runat="server" enablepagemethods="true">
         <Scripts>
         <asp:ScriptReference Path="scripts.js" />
         </Scripts>
         </asp:scriptmanager>
         
         <div class="content">
            
            <fieldset>
            <legend>Horário do último Postback</legend>
                <div id="dvPost" runat="server">
                        
                </div>
            </fieldset>
         
            
            <asp:[i]updatepanel[/i] runat="server" ID="up1">
            <ContentTemplate>
            <fieldset>
            <br />
                <legend>Clientes cadastrados</legend>
                    <div id="dvResult" runat="server">
                            <span>Click em preencher para baixar os dados.</span>
                    </div>
             </fieldset>
            </ContentTemplate>
          <Triggers>
          <asp:AsyncPostBackTrigger ControlID="btnServerSide" EventName="ServerClick" />
          </Triggers>
            </asp:[i]updatepanel[/i]>
            
            <br />
            <br />
            <div class="buttons">
                <input type="button" id="btnClientSide" onclick="preencheTable()" value="Preencher Client Side" />
                <input type="button" id="btnServerSide" runat="server"  value="Preencher Server Side" onserverclick="btnServerSide_ServerClick" />
                <input type="button" id="btnLimpar" onclick="Limpar()" value="Limpar" />
            </div>            
            
            
         </div>
         
         
    </form>
</body>

</html>

Os comentários sobre o codefile foram colocados diretamente no código.

Agora abra o arquivo Default.aspx.cs e o codifique da seguinte maneira:

using System;
using System.Data;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using System.Web.Services;
using System.Collections.Generic;
using System.Collections;
using System.Data.OleDb;

public partial class _Default : System.Web.UI.Page 
{
    /* Preenche a div dvPost com a data atual para demonstrar que a página é atualizada sem postback*/
    protected void Page_Load(object sender, EventArgs e)
    {
        dvPost.InnerHtml = DateTime.Now.ToString();
    
    }
	
    /* Método com a tag [WebMethod] que habilita o método a ser       chamado assincronamente este metodo
    lê os dados dos clientes e chama o método se realiza para poder         
mandar os dados para o javascript*/
    [WebMethod]
    public static IDictionary<string, object> getClientes()
    {
        OleDbDataAdapter da = new OleDbDataAdapter("Select * from clientes", "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" + HttpContext.Current.Server.MapPath("~/teste.mdb;"));
        DataSet ds = new DataSet();

        try
        {
            da.Fill(ds, "clientes");
        }
        catch (Exception e)
        {
            Dictionary<string, object> result = new Dictionary<string, object>();
            result["error"] = e.Message;
        }

        return Serializa(ds);

    }

    /* O principal método de nossa classe, pois é ele que transforma o *dataset em uma estrutura de dados que pode ser enviada ao javascript.*/
    private static IDictionary<string, object> Serializa(DataSet obj)
    {
        if (obj != null)
        {
            Dictionary<string, object> result = new Dictionary<string, object>();
            Dictionary<string, object> dicDS = new Dictionary<string, object>();
            Dictionary<string, object> dicDT = new Dictionary<string, object>();
            Dictionary<string, object> dicColum = new Dictionary<string, object>();

            ArrayList ListRow = new ArrayList();


            foreach (DataTable dt in obj.Tables)
            {
                ListRow = new ArrayList();
                foreach (DataRow row in dt.Rows)
                {
                    dicColum = new Dictionary<string, object>();
                    foreach (DataColumn dc in dt.Columns)
                    {
                        dicColum.Add(dc.ColumnName, row[dc]);
                    }
                    ListRow.Add(dicColum);
                }
                dicDT["Rows"] = ListRow;
                dicDS.Add(dt.TableName, dicDT);
            }
            result["Tables"] = dicDS;
/*Note que estamos inserindo algumas informações a mais *fora os dados em si, como por exemplo o count que nos *informara quantas tabelas contém o dataset, aqui se *necessário vocês podem colocar outras informações*/
            result["count"] = obj.Tables.Count;
            result["error"] = null;
            
            return result;
        }
        return new Dictionary<string, object>();
    }

/*Método que é chamado ao click do botão btnServerSide ele le os *dados dos clientes e preenche a div dvResult*/
    protected void btnServerSide_ServerClick(object sender, EventArgs e)
    {
        OleDbDataAdapter da = new OleDbDataAdapter("Select * from Tabela1", "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" + HttpContext.Current.Server.MapPath("~/teste.mdb;"));
        DataSet ds = new DataSet();

        try
        {
            da.Fill(ds, "Tabela1");
        }
        catch (Exception ex)
        {

        }

        string strAux = string.Empty;
        for (int i = 0; i < ds.Tables[0].Rows.Count; i++)
        {
            strAux = strAux + "<span>Cliente: " + ds.Tables[0].Rows[i]["Nome"].ToString();
            strAux = strAux + " Telefone: " + ds.Tables[0].Rows[i]["Telefone"].ToString();
            strAux = strAux + "<span><br/>";
        }
        dvResult.InnerHtml = strAux;
    }
}

Agora iremos criar o arquivo que terá o JavaScript. Assim como o codefile. Coloquei os comentários diretamente no código. Clique no botão Add New Item, escolha a opção JScript file de o nome de scripts.js e codifique igual ao exemplo abaixo:

// scripts.js

/* Função chamada ao clique do botão btnClienteSide ela chama o webmethod getClientes e passa como parâmetro a função preencheTable_callback que receberá os dados retornados.*/

function preencheTable()
{

    PageMethods.getClientes(preencheTable_callback);

}

/*Apenas limpa a div dvResult para melhor comparar o preenchimento client-side e server-side*/
function Limpar()
{

    document.getElementById("dvResult").innerHTML = 'Click em preencher para baixar os dados.';

}
 
/*Recebe os dados enviados pela função .NET e preenche a div*/
function preencheTable_callback(res)
{

    if (res.error == null)
    {
            var strAux = "";
            var dt = res.Tables.Tabela1;
            for(i=0;i<dt.Rows.length;i++)
            {
                strAux = strAux + "<span>Cliente: " + dt.Rows[i].Nome;
                strAux = strAux + " Telefone: " + dt.Rows[i].Telefone;
                strAux = strAux + "<span><br/>";
            }
            document.getElementById("dvResult").innerHTML = strAux;
    }

}

Agora criaremos um arquivo css apenas para deixar a página mais apresentável, crie uma nova pasta chamada CSS e crie um arquivo Style Sheet chamado StyleSheet.css e codifique da seguinte maneira:

body {
}

.content
{
	text-align:center;
}

fieldset
{
	border:10;
	border-color:Black;
	width:500px;
	text-align:center;
	font-style:oblique;
}
.buttons
{
	width:500px;
	text-align:center;
}

Pronto. Agora que já temos todos os arquivos necessários para a nossa aplicação, poderemos debugá-la. Tudo rodou como esperado?

Agora que já está tudo certo poderemos testar a aplicação. Aqui na minha máquina tenho instalado um programa que todos já devem conhecer chamado “httpWatch”. Com ele poderemos ver, entre outras coisas, a quantidade de dados que estão sendo enviados (send), recebidos (Received) e o tempo que isto leva a cada requisição da aplicação.

Rodei minha aplicação, e coloquei o “httpWatch” para registrar os dados trafegados. Quando cliquei no botão “Preencher Client Side” e obtive os seguintes resultado, veja na figura1, time 0.159 segundos (circulado de vermelho) foram enviados Send 452 bytes (circulado em azul) e foram recebidos Received 493 bytes(em verde).

Figura 1Figura 1

Logo em seguida, cliquei no botão “Preencher Server Side”, o qual vai atualizar tudo que estiver dentro do updatepanel e obtive os seguintes resultados. Veja na figura2, time 0.242 segundos (circulado de preto) foram enviados(Send) 1032 bytes circulado em lilás. E foram recebidos(Received) 1555 bytes em marrom.

Note que em nenhuma das vezes o horário do último postback foi alterado provando que realmente estamos trabalhando assincronamente.

Figura 2Figura 2

Conclusão

Como vimos, é muito mais fácil desenvolver utilizando os componentes do Ajax.net, pois apenas arrastamos um updatepanel para a página, colocamos os componentes dentro dele e pronto. Já temos algumas chamadas assíncronas.

Por outro lado, para passar os dados para o JavaScript, temos que, não só criar os componentes, como também desenvolver o script que irá preencher a tela. Aí fica a dúvida em quais situações devo usar o updatepanel e em qual não devo usá-lo.

Quando você está desenvolvendo uma tela simples com um cadastro ou exibição de poucos dados, é mais fácil e ágil usar o updatepanel. Agora, se você está desenvolvendo um website robusto com muitas informações que terá um grande número de acessos e uma intensa transferência de dados, não aconselho o uso do updatepanel pois, como podemos ver, ele aumenta muito a quantidade de dados transferidos entre o cliente e o servidor e com isso perdemos muita performance, podendo até tornar inviável o funcionamento do site.

Espero que esse artigo seja útil e que ajude a internet se tornar cada vez mais útil e criativa.

Até o próximo artigo.

Veja mais em http://pt.wikipedia.org/wiki/AJAX_%28programa%C3%A7%C3%A3o%29

é estudante de Ciência da Computação e trabalha com .net desde 2006.

Ver perfil