Ciclo de Vida da Página no ASP.Net

Objetivo

O objetivo deste artigo não é novamente citar quais são todos os métodos virtuais que são chamados pelo ASP.Net no momento que está servindo uma página. Já existe uma tonelada desses na internet, no msdn nos forums e tudo o mais.

Quando estava escrevendo meu último server control, deparei com uma série de situações que na prática não tinham solução descrita de uma forma direta na internet. Por isso resolvi escrever esse artigo, simplificar o ciclo de vida da página para “o que interessa”.

Entenda por “o que interessa”, “por que a minha página vive perdendo o estado?”.

O “Control Tree”

Em muitos lugares fala-se sobre a árvore de controles de uma página, mas por que ela é tão importante?

  • A árvore de controles é quem determina como o ViewState vai ser salvo e carregado.
  • A árvore de controles é quem determina a relação de qual página é “dona” do controle (alguns dependem disso para “renderizar-se”)
  • A grande maioria dos problemas ao se escrever uma página, principalmente relacionados a perda de estado estão relacionadas com manipulação incorreta do control tree.

Suponhamos uma página com um Panel (panel1) e dentro desse panel outro panel (panel2) e dois textbox (textbox1 e textbox2). Dentro do panel2 ainda ganhamos um outro textbox (textbox3). A coisa é chamada de “control tree” pq a estrutura da collection “Controls” de cada um dos controles contendo outros controles, forma uma árvore (como um treeview e seus nós, ou um XML como seus nós). Desenhando fica mais fácil de entender:

  • Página
    • panel1
      • panel2
        • textbox3
      • textbox1
      • textbox2

O ciclo de vida da página

Esse artigo do MSDN mostra de uma forma clara como o Runtime do ASP.Net processa o request. É uma boa referência: http://msdn.microsoft.com/en-us/library/aa479328.aspx

Início do processamento

No início o ASP.Net pega o processamento do request e direciona para o aspx equivalente. Uma instância da classe gerada pelo aspx é criada para o request e começa o ciclo de vida.

Nesse momento o ASP.Net determina se o request é um postback ou não e se é um request assíncrono ou não (AJAX).

Em seguida, o aspx é parseado e o Control Tree é criado. Os componentes tem suas propriedades criadas com valor default e em seguida sobrescritas com os valores informados no aspx.

Inicialização

Na etapa de inicialização a primeira coisa que acontece é “OnPreInit”, depois “Init”. Neste momento, ainda não foram carregadas as informações do ViewState.

A única diferença perceptível entre PreInit e Init (caso alguém saiba mais alguma, ficarei feliz em saber também) é que em PreInit ainda não foi carregado o tema da página, ainda não foi aplicada a MasterPage, nem os control skins.

Load

Nessa etapa, é carregado o ViewState, através do método virtual “LoadViewState”. LoadViewState na verdade apenas carrega as informações do view state de um meio persistente (No caso padrão, do campão hidden escondido na página). Ele na verdade não joga esses valores no componente.

ProcessPostData é um método interno do ASP.Net runtime. Não encontrei nenhuma documentação “oficial” da Microsoft sobre o que esse método faz, o fato é que baseado numa série de testes, pude perceber que uma das responsabilidades dele é pegar os valores do ViewState e jogar nos componentes. A confusão é que, isso é feito mais de uma vez.

Após o carregamento das informações, acontece OnPreLoad e OnLoad. OnPreLoad, na documentação do msdn fala sobre “uma segunda chance para carregar informação do ViewState”. Pra mim não faz muito sentido, enfim… Se alguém tiver mais sugestões sobre diferenças de OnPreLoad e OnLoad, por favor, me conte.

O OnLoad na minha opinião é o lugar ideal (talvez o único) para tratar criação de componentes dinâmicos, pegar informações do Request e outros tratamentos, pois logo após o OnLoad é executado novamente o ProcessPostData. Dessa forma, se um componente dinâmico for criado no on-load, ele vai manter estado se na hora de executar ProcessPostData o Control Tree estiver no mesmo estado em que foi salvo.

Processar eventos de Postback

A próxima etapa é cair nos eventos de postback dos controles. Acontece logo após o OnLoad.

O próximo evento chamado é o “OnPreRender”, segundo o msdn, a última chance de manipular o Control Tree antes de salvar o estado.

Salvar ViewState

O ViewState é salvo, baseado no Control Tree. Isso é muito importante.

Significa que para o estado ser mantido corretamente, no próximo postback, no momento de carregar o ViewState (antes e após o OnLoad, no ProcessPostData) a estrutura do Control Tree precisa ser idêntica à que foi usada para salvar o ViewState.

Aqui moram a maioria dos problemas. Se está perdendo estado, é porque provavelmente a estrutura do Control Tree está diferente da que foi salva na hora de carregar.

Render

Nesse momento a página “desenha-se” chamando recursivamente o Render de todos os componentes filhos.

Nem adianta mais manipular o Control Tree aqui, pois o estado não vai ser salvo mais e provavelmente vai gerar um monte de outros problemas.

O ciclo de vida e o ViewState

Uma coisa muito importante sobre o ViewState que confunde a maioria das pessoas (já me confundiu muito). O ViewState guarda o “estado” de “algumas” propriedades do componente na página e recupera os mesmos valores no próximo postback. O ViewState **não** serializa as instâncias dos controles inteira e recupera no próximo PostBack. São duas coisas completamente diferentes.

Quando o postback acontece, os controles são re-instanciados baseados no aspx e as informações do ViewState carregadas pra dentro. Isso significa q se um componente foi criado dinamicamente, por default, ele não reaparece magicamente no postback, ele precisa ser re-criado.

Se ele precisa ser re-criado, como eu faço pra ele manter estado? A resposta é: “Re-crie o componente na mesma posição em que ele estava na hora que o ViewState foi salvo na hora certa”. A hora certa é: No OnLoad.

Aqui é que entra toda a complicação.

Tem dois pontos CRUCIAIS para se entender o ViewState. Um é o momento que os valores lidos são jogados para dentro do componente, ou seja, ProcessPostData. Isso acontece duas vezes. Uma antes do OnLoad, outra depois.

Outro ponto crucial é quando o ViewState é salvo, ou seja, entre o PreRender e o Render.

No momento de carregar o ViewState, a página respeita **exatamente a estrutura do Control Tree**. O que isso significa na prática? Se eu tinha a estrutura:

  • Página
    • TextBox
    • DropDownList
    • TextBox

No momento de salvar o ViewState e no postback subsequente, no momento de carregar o ViewState eu tenha a estrutura

  • Página
    • TextBox
    • TextBox

O segundo TextBox perde o estado.

Referências

Alguns lugares de onde tirei informações para esse artigo (interessante é que eles são bem diferentes):

Anúncios

Deixe um comentário

Preencha os seus dados abaixo ou clique em um ícone para log in:

Logotipo do WordPress.com

Você está comentando utilizando sua conta WordPress.com. Sair / Alterar )

Imagem do Twitter

Você está comentando utilizando sua conta Twitter. Sair / Alterar )

Foto do Facebook

Você está comentando utilizando sua conta Facebook. Sair / Alterar )

Foto do Google+

Você está comentando utilizando sua conta Google+. Sair / Alterar )

Conectando a %s