domingo, setembro 13, 2009

Deferred Load ASP.NET/JQuery


Hoje vou descrever uma técnica de como carregar o conteúdo  dinâmico após a pagina ser carregada, isso pode aumentar bastante a experiência com o usuário se você tem que exibir uma quantidade grande de dados, ou pegar algum conteúdo de um servidor externo. A técnica consiste em baixar todo o conteúdo estático, e após o documento estar pronto (ready), fazer uma requisição em AJAX para baixar o conteúdo dinâmico.






Temos dois exemplos um pegando o conteúdo de RSS e montando uma lista via javascript, no segundo caso que renderiza o HTML é um WebControl contendo um Repeater, então vamos para o código.

Antes de mais nada crie um novo projeto Web e monte o mesmo com a estrutura abaixo.




O  FeederLoader.cs representa o Proxy entre a fonte de dados e a requisição AJAX, nela usamos o WebClient para baixar um RSS e devolvemos para o navegador, e o código dela e este:


public class FeederLoader
{
    public FeederLoader()
    {
    }

    public string Load(string url)
    {
        WebClient client = new WebClient();
        byte[] buffer = client.DownloadData(url);

        return UTF8Encoding.UTF8.GetString(buffer);
    }

O método Load baixa o conteúdo da url usando o WebClient e devolve como uma String UTF-8.
Partimos agora para o Handler FeederJS.ashx


public void ProcessRequest (HttpContext context) {
        context.Response.ContentType = "text/xml";
        FeederLoader Loader = new FeederLoader();
        
       System.Threading.Thread.Sleep(1000); //só pra ficar cool

        string rss = Loader.Load("http://newbie-x11.blogspot.com/feeds/posts/default?alt=rss");
        context.Response.Write(rss);
        context.Response.End();
        
    }

No método ProcessRequest usamos o FeederLoad pra baixar o RSS deste blog :-] , e devolver para o XML navegador.
Agora a página Web, EmJavaScript.aspx


<style type="text/css">
        
        .Loading
        {
            background-image: url('images/loader.gif');
            background-repeat:no-repeat;
        }
        
    </style>

  <div id="master">
            <div id="static">
                Como as vezes tenho uma alta enorme de creatividade não vou escrever nada aqui.
            </div>
            <div id="dynamic">
            </div>
        </div>
        <div>

            <script type="text/javascript" src="js/jquery-1.3.2.min.js"></script>
            <script type="text/javascript">
            $(document).ready(function(){
            var ajaxOption = {
                        type: "GET",
                        url: "handlers/FeederJS.ashx",
                        dataType : "xml",
                        success : function(data){
                            var html = "<ul>"
                            $(data).find('item').each(function(){
                                var titulo = $(this).find('title').text();
                                html += "<li>"+titulo+"</li>";
                            });
                            
                            html += "</ul>";
                            
                            $("#dynamic").append(html);
                            $("#dynamic").attr("class","");
                        }
                    };
                    
                    $("#dynamic").attr("class","Loading");
                    
                    $.ajax(ajaxOption);
                    
            });
            
          
            </script>

        </div>

Acima antes de fazer a requisição em AJAX , mudamos o CSS do elemento que abriga o conteúdo dinâmico para a classe que contem a imagem carregando, na Requisição (success), fazemos o loop no xml e montamos uma lista, preenchemos o conteudo carregado no elemento, e removo a classe de CSS .Loading, e Badabum..

Agora se você não quer ficar montando conteudo via JavaScript demonstro abaixo com poucas modificações, fazemos a mesma coisa só que usando o um Repeater e um User Control, vamos lá crie o Controle, então adicione um novo Web User Control com o nome de Listageml.ascx, e o código dele segue abaixo.


<%@ Control Language="C#" AutoEventWireup="true" CodeFile="Listageml.ascx.cs" Inherits="controles_Listageml" %>
<div>
    <asp:Repeater ID="Repeater1" runat="server">
        <HeaderTemplate>
            <ul>
        </HeaderTemplate>
        <ItemTemplate>
            <li>
                <%# Eval("title") %>
            </li>
        </ItemTemplate>
        <FooterTemplate>
            </ul></FooterTemplate>
    </asp:Repeater>
</div>

O .cs:


protected void Page_Load(object sender, EventArgs e)
    {
        XmlTextReader reader = new XmlTextReader("http://g1.globo.com/Rss2/0,,AS0-5597,00.xml");

        DataSet ds = new DataSet();

        ds.ReadXml(reader);
        Repeater1.DataSource = ds.Tables["item"];
        Repeater1.DataBind();
    }

Creio que não seja necessário comentar o bloco acima, agora vamos ao Handler FeederASP.ashx, que tem modificações significativas:


public void ProcessRequest (HttpContext context) {
        
        Page page = new Page();
        UserControl ctl = (UserControl)page.LoadControl("~/controles/Listageml.ascx");
        StringWriter writer = new StringWriter();

        System.Threading.Thread.Sleep(1000); //só pra ficar cool
        
        page.Controls.Add(ctl);
        HttpContext.Current.Server.Execute(page, writer, false);

        context.Response.ContentType = "text/plain";
        context.Response.Write(writer.ToString());
        context.Response.End();
    }

Acima usamos estas linhas malucas para renderizar o HTML do controle, se tiver a necessidade de passar parâmetros para o controle pode usar os atributos, mas compensa dar um passeio pelo Google e ler sobe WebControls.
Passamos agora para o arquivo EmASP.aspx, a única mudança é no Java script:


<script type="text/javascript">
            $(document).ready(function(){
            var ajaxOption = {
                        type: "GET",
                        url: "handlers/FeederASP.ashx",
                        dataType : "text",
                        success : function(data){
                         
                            
                            $("#dynamic").append(data);
                            $("#dynamic").attr("class","");
                        }
                    };
                    
                    $("#dynamic").attr("class","Loading");
                    
                    $.ajax(ajaxOption);
                    
            });
</script>

Simplificou bastante, aqui só pegamos o conteúdo pronto e colocamos no elemento.
Pronto é isso, pode baixar o código fonte aqui.

2 comentários:

Anónimo disse...

nossa boss muito bom isso um tem poa trás tava procurando isso ai acabei que num fiz nada nem um gambi mais digna uhauhauhauhuha fazer em php agora

Gabriel disse...

:-), fica fácil portar pra PHP.