Rui Quintino

.Net & afins

My Links

News



Reading...

Favorites

Archives

Post Categories

Image Galleries

Login

Blog Stats

KISS AJAX III - O código

Ok, aqui fica então uma explicação do conceito e do código... algo sucinta que o tempo não estica. :) Todo o código está disponível aqui.

Portanto, a ideia inicial, tal como demonstrada no exemplo, era implementar um mecanismo que permitisse, usando "ajax" (passe a publicidade), fazer refresh assincronamente apenas a determinadas áreas da página que fossem modificadas num postback.

Além disto o ideal era ser o menos "intrusivo" possível mantendo todo o conceito asp.net e evitando ter que manipular o DOM em javascript (até pq o intellisense não é grande coisa, e aqui entre nós... eu sem intellisense não sou coisa nenhuma :) ). A complexidade é um dos grandes problemas nas implementações de Ajax que vejo normalmente, tal como mencionou,e bem, o Pedro Sousa.

A ideia que surgiu então foi aproveitar o mecanismo de rendering do asp.net de forma a que quando detectássemos um pedido ajax fosse feito apenas o render dos controlos alterados. Aqui parti do principio que tinha que nos caber a nós programadores saber quais os controlos a necessitar de refresh.... isto pq detectar isto em runtime....bem... duvido (era a cereja!).

Este mecanismo é de certa forma usado no GMail e foi já implementado em Java de forma semelhante à que aqui descrevo, In Place Update" da Simple Web Framework . O conceito é exactamente o mesmo.

Adiante, do que precisava eu então?

  • Ter uma forma de registar quais os controlos a renderizar na resposta,
  • Ter uma forma de marcar determinados controlos para fazerem o postback em modo ajax
  • Alterar o render da página de forma a gerar apenas o html dos controlos alterados,
  • Mecanismo que fizesse o post via xmlhttp do form actual (equivalendo portanto a um postback normalissimo, mas mexer na página),
  • Com base na response do xmlhttp afectar os controlos necessários, não esquecendo de actualizar o viewstate.

Com a lógica de implementar a ideia da forma mais rápida possível....afinal o que queria era ver até que ponto seria usável, usei algumas técnicas dificilmente suportadas oficialmente... invocação de métodos privados, desactivação de validações asp.net, enfim, uma desgraça! Estou já a avisar. :)

Ter uma forma de registar quais os controlos a renderizar na resposta:
Nada que um arraylist não resolvesse:
ArrayList changedControls= new ArrayList();
void AddChangedControl(Control ctl)
{
changedControls.Add(ctl);
}
Ter uma forma de marcar determinados controlos para fazerem o postback em modo ajax:
Usando o attributes, algo como:

public void EnableAjaxOnControl(LinkButton btn)
{
btn.Attributes.Add("onclick","AjaxPostBack(this);return false;");
}

Nota: No exemplo estou a ser mais drástico, altero a função __dopostback de forma a que todos os linkbutons, dropdowns,etc herdam o comportamento automaticamente, paginação e sorting de datagrids,etc.

Alterar o render da página de forma a gerar apenas o html dos controlos alterados:

Ok, aqui apanhei o 1o problema dado que por default o asp.net não permite fazer o render de um elemento se não estiver dentro de uma form (coisa que eu não queria fazer). A StackTrace apontava o método culpado de forma que fiz override do mesmo desactivando a validação:

public override void VerifyRenderingInServerForm(Control ctl)
{
//Ignore base server form validation
}

Tirando isto, a implementação foi fácil, override ao método render e:

if (EnableAjaxPostBack && IsAjaxPostBack )
{
foreach (WebControl ctl in
changedControls)
{
StringWriter sw= new StringWriter();

HtmlTextWriter ht= new HtmlTextWriter(sw);

ctl.RenderControl(ht);

Response.Write(string.Format("RefreshElement('{0}','{1}');",
ctl.ClientID,EscapeJavascript(sw.ToString())));
}

}
else
base.Render(html);

Mecanismo que fizesse o post via xmlhttp do form actual (equivalendo portanto a um postback normalissimo) :

Ok, aqui confesso que desanimei dado que não me apetecia nada ter que implementar isto de raiz.... o mais certo era pegar nisto noutro dia (daqui a muitos anos). Mas recuperei os excelentes artigos de Bill Pierce (saga AJAX was here), exactamente o que precisava! As rotina ajax dele faziam ja o postback correcto do form actual via xmlhttp. Siga! :)

Com base na response do xmlhttp afectar os controlos necessários, não esquecendo de actualizar o viewstate:
Com o viewstate tive que recorrer à obtenção de um campo privado (shame on me).... dado que se o viewstate tivesse a verificação activa batia no check do hash. E a criação do losformatter com esse constructor não tinha eu acesso. Entretanto não fui reconfirmar isto... deve haver uma forma decente de o fazer, devo ter visto mal.

protected
override void SavePageStateToPersistenceMedium(object
viewState)
{
if (EnableAjaxPostBack && IsAjaxPostBack)
{

FieldInfo los=typeof(Page).GetField("_formatter",
BindingFlags.NonPublic | BindingFlags.GetField | BindingFlags.Instance);

LosFormatter l=(LosFormatter) los.GetValue(this);

StringWriter viewStateStr= new StringWriter();

l.Serialize(viewStateStr,viewState);

Response.Write(string.Format("RefreshElementValue('__VIEWSTATE','{0}');",
viewStateStr.ToString()));

}
else
base.SavePageStateToPersistenceMedium(viewState);

}

Dito isto faltava apenas passar o viewstate e o html dos controlos do response do xmlhttp para o dom do form corrente. Estava já a desesperar novamente, a pensar em parsers e xml.... quando atalhei, "vergonhosamente", caminho .. mais uma vez. :) E se passasse javascript? Dito e feito.

Response.Write(

string.Format("RefreshElement('{0}','{1}');",
ctl.ClientID,EscapeJavascript(sw.ToString())));

para os controlos e

Response.Write(string.Format("RefreshElementValue('__VIEWSTATE','{0}');",

para o viewstate.

A versão inicial usava o document.getelementbyid directamente, a nova utiliza funções localizadas no ficheiro kissajax.js, é bem mais fácil de trabalhar e melhorar.

E prontos, acho que não me esqueci de nada. Bastou isto, o resto foram ligeiros ajustes. Toda esta implementação migrou para a classe base KissAjaxPage. A implementação da página de exemplo em si não tem quase nada que lhe diga (bastam os AddChangedControl nos sítios correctos), podendo funcionar no modo normal ou via ajax postbacks.

Algumas notas soltas:

  • Se um controlo a que queremos fazer update não existe no DOM não é possível fazer o refresh, de forma que nessas alturas uso paineis (o IPU da Simple Web Framework referida atrás usa regiões prov. pela mesma razão).
  • Penso que há ainda um problema com o formato do post em botões normais e image buttons. Não deve ser difícil de detectar e corrigir, coisa para a qual não tenho é grande paciência.
  • Validators,etc, devem trazer as suas dores de cabeça.
  • Dores de cabeça, aqui e ali, com uma mudança drástica destas é certo :)
  • Combinação com eventos onkeyup (filtragem na hora), mto fácil, mas retirei do sample online dado que a performance era sofrível
  • KISS- ora bem KISS pq enquanto ia marinando a ideia forçava-me a recordar as famosas palavras "Keep It Simple Stupid" :)
  • Só para que fique bem claro, não sou defensor do Ajax, nem opositor (obviamente). Tal como muitas outras técnicas tem as suas vantagens e desvantagens. Isto é apenas uma prova de conceito. Estamos no campo da especulação pura. O mesmo para o conceito já falado de "In Place Update".
  • Funciona.... estranho... :)

Obrigado pelo feedback, um abraço!


RQ

posted on Wednesday, June 08, 2005 2:00 AM

Feedback

# re: KISS AJAX III - O código 6/8/2005 12:43 PM Pedro Sousa

Está muito bom :D

Relativamente ao que dizes de não seres nem defensor nem opositor da tecnologia Ajax, eu estou mais ou menos como tu... mas cada vez mais me inclino para ser um defensor.
Nos tempos em que um gajo fazia aplicações a utilizar o XmlHttp e grandes código em Javascript, com parsings Xml intermináveis e Debug incerto... aí inclinava-me para opositor. Agora com estas metodologias menos intrusivas (tipo Ajax.NET e a tua) parece-me q vamos no bom caminho... pq é fácil ver que não faz sentido um postback total de uma página para mudar o texto de uma label.
Agora com o novo mecanismo de Client Callbacks do 2.0 poderemos talvez avançar mais neste sentido (off topic: já há release date do VS 2005 - semana de 7 Novembro) e estas abordagens deixem de ser "proof of concept" :)

Abraços

# re: KISS AJAX III - O código 6/8/2005 1:08 PM RQ

Mil desculpas Pedro, tinha-me enganado no nome. Corrigido. :)

Estou como tu,no meio de todo este hype acho que se vai tirar alguma coisa de útil... tal como disseste, é irreal de facto que se ande com todo o html para a frente e para trás para mudar uma simples label. Tem de haver melhores soluções. Que não passem por reinventar a roda e pôr de parte html/http.

Mesmo o callback do asp.net 2.0, parece-me algo complexo para o fim pretendido:

public string RaiseCallbackEvent(string eventArgument) ???

Não me convenço muito em usar isto de forma massiva. :)

# re: KISS AJAX III - O código 6/8/2005 2:45 PM Pedro Sousa

Olha, queres ver uma cena Ajax com bom aspecto? Vai aqui:

http://www.dart.com/powerweb/livecontrols_included.asp

Esta empresa desenvolveu um conjunto de controls para ASP.NET que implementam o Ajax implicitamente. Estive a experimentar e funcionam muito bem mesmo. Colocas o control no form, crias um event handler qq, e as propriedades q tenhas alterado são reflectidas em client-side. Em algumas partes isto deverá ter uma implementação semelhante à tua, embora seja uma abordagem um bocadinho diferente. Aqui o Ajax está ao nível do controlo, na tua está ao nível da página

# re: KISS AJAX III - O código 6/8/2005 11:32 PM RQ

Revivas,

Acho que o nome de Live Controls não me é estranho mas ainda não tinha visto. Outra implementação interessante, tb transparente qb.

Penso que a forma como indicam a necessidade do refresh (em controls normais asp.net) é com um atributo extra, LiveControlUpdate (embora não perceba a lógica de o ter a true no aspx e não o manipular em code behind). Depois devem usar o attributes.

Tb herdam de um liveusercontrol, provavelmente devido ao render.

Uma nota, e por certo devem ter tb esta feature algures mas não a notei nos exemplos: qd n é visivel que um postback está a decorrer a experiência "ajax" torna-se extremamente confusa.

PS-Corrigi o problema do download do código. Uma valiação extra do brinkster de que não me lembrei.

# re: KISS AJAX III - O código 7/17/2005 1:28 AM zzz

dfsf

Title  
Name  
Url
Box Code
Protected by FormShield
Comments