Ferramentas de Usuário

Ferramentas de Site


dev_net:asp.net:estadodevisualizacaoemasp.net

Diferenças

Esta página mostra as diferenças entre as duas revisões da página.

Links para esta vista de comparação

Ambos os lados da revisão anterior Revisão anterior
dev_net:asp.net:estadodevisualizacaoemasp.net [2018/06/17 12:07]
staff Documento automaticamente removido.
— (Atual)
Linha 1: Linha 1:
-====== Estado de Visualização em ASP.NET ====== 
  
-Antes de entrar em pormenores sobre estado de visualização é necessário compreender o que é um controlo e como este funciona em ASP.NET. De certa forma o ASP.NET é uma arquitectura baseada em controlos, já que uma página é um controlo e qualquer controlo pode conter controlos filhos. 
- 
-A arquitectura é semelhante à arquitectura de janelas do Windows, onde o próprio ambiente de trabalho é uma janela, que pode conter janelas filhas. Cada janela é apresentada, apresentando primeiro o seu conteúdo e depois apresentando o conteúdo das janelas filhas. O mesmo se passa em ASP.NET em que cada controlo é apresentado, apresentando primeiro o seu conteúdo e depois apresentando o conteúdo dos seus filhos. A apresentação de uma janela em Windows envolve o desenho de pixeis no ecrã, enquanto que a apresentação de um controlo ASP.NET envolve a geração de HTML para preencher uma parte da resposta a um pedido HTTP. 
- 
-Uma página serve como controlo raiz e tem três controlos filhos imediatos: um controlo literal para gerar o texto de início da página, um controlo do lado do servidor HtmlForm para representar o formulário e todos os seus controlos filho, e por fim outro controlo literal para gerar o texto de fim da página. Todos os controlos adicionados a uma página estarão dentro do formulário e portanto serão filhos do HtmlForm, em que a ordem pela qual estão definidos dentro desse controlo será a ordem pela qual serão apresentados. Cada um destes controlos tem o seu próprio estado de visualização. Todos os controlos que correspondem a elementos de formulário têm a sua manutenção de estado suportada através do envio automático do valor dos elementos quando o formulário é submetido (//post back//). Todos os outros terão que definir o seu mecanismo de persistência de estado e será sobre este assunto que iremos conversar. 
- 
-Em ASP.NET, o estado de visualização entre //post backs// é mantido através de uma colecção de pares nome/valor acessíveis por qualquer controlo a partir da propriedade //ViewState//. Quase todo o estado do controlo, se não todo, fica guardado nesta colecção. Esta propriedade retorna uma instância do tipo //System.Web.UI.StateBag//, que é muito semelhante a uma tabela de //hash// mas tem a capacidade de registar alterações (fazer //tracking//), ou seja, permite que sempre que um valor seja alterado na colecção seja também marcado como “//dirty//”. 
- 
-A função de registo de alterações pode estar ligada ou desligada, mas uma vez ligada não pode ser desligada. De modo a activar a função use o método //TrackViewState()//. Se a função de //tracking// estiver ligada qualquer alteração a um objecto fará com que esse objecto fique marcado como “//dirty//”. Podemos consultar se o objecto está marcado ou não através do método //IsItemDirty(string chave)// ou forçar a marcação através do método //SetItemDirty(string chave)//. O leitor tenha em atenção um pormenor, após a activação de //TrackViewState()// qualquer alteração será marcada, mesmo que o objecto seja alterado para o mesmo estado, como por exemplo: 
-<code csharp> 
-stateBag["nome"] = "valor"; 
-stateBag.IsItemDirty("nome"); // falso 
-stateBag.TrackViewState(); 
-stateBag["nome"] = "valor"; 
-stateBag.IsItemDirty("nome"); // verdadeiro 
-</code> 
- 
-A colecção //ViewState//, como já foi referido, guarda pares nome/valor, os pares podem ser indexados por string e ter qualquer //object// como valor. Exemplo: 
-<code csharp>  
-ViewState["ViewStateVariableName"] = 1; 
-</code> 
- 
-Para ter acesso á variável guardada basta fazer a indexação com a chave e a respectiva conversão. 
-<code csharp> 
-int number = (int) ViewState["ViewStateVariable"]; 
-</code> 
- 
-Esta colecção também permite guardar tipos os nossos próprios tipos quase tão facilmente como os tipos básicos. Para tal basta apenas o tipo ser serializável, ou seja, consegue-se converter uma instância desse tipo para uma sequência de bytes e posteriormente fazer a sua recuperação. Vai compreender a necessidade de o tipo ser serializável mais á frente neste artigo quando falarmos de um campo de input oculto chamado  _//_VIEWSTATE//. 
- 
-<code csharp> 
-[Serializable] 
-public class Pessoa 
-{ 
-    public string _nome; 
-    public int _idade; 
-  
-    public Pessoa(string nome, int idade) 
-    { 
-        _nome = nome; 
-        _idade = idade; 
-    } 
-} 
-</code> 
- 
-Como a classe Pessoa está marcada como serializável pode ser guardada em //ViewState//: 
-<code csharp> 
-Pessoa p = new Pessoa("Vitor", 25); 
-ViewState["Cliente"] = p; 
-</code> 
- 
-Lembre-se que terá de efectuar a respectiva conversão quando necessitar de obter o valor guardado. 
-<code csharp> 
-Pessoa p = (Pessoa) ViewState["Cliente"]; 
-</code> 
- 
-O protocolo HTTP é //stateless//, ou seja, cada pedido é executado independentemente e sem conhecimento de pedidos anteriores. Portanto cada pedido feito á arquitectura ASP.NET será servido por uma instância diferente do controlo e por isso não é possível guardar estado de visualização entre //post backs// em campos de instância. Devido a isso as propriedades em ASP.NET terão um aspecto diferente já que deverão usar a colecção //ViewState// para guardar qualquer valor: 
-<code csharp> 
-public int ValorInteiro 
-{ 
-    get { return (int)ViewState["ValorInteiro"]; } 
-    set { ViewState["ValorInteiro"] = value; } 
-} 
-</code> 
- 
-Nos casos em que é necessário ter um valor por defeito teremos também que ter em conta que estamos a utilizar a colecção //ViewState//. Tal como uma tabela de //hash//, uma //StateBag// irá retornar //null// se a colecção não contém uma entrada com essa chave. Portanto, se o valor retornado for nulo é porque ainda não foi atribuído, então deve retornar o valor padrão, caso contrário, retornar o valor obtido. 
-<code csharp> 
-public string Texto  
-{ 
-    get { return ViewState["Texto"] == null ?  
-          "Valor por Defeito" : (string)ViewState["Text"]; 
-    } 
-    set { ViewState["Texto"] = value; } 
-} 
-</code> 
- 
-Repare que ao afectar com //null// uma propriedade definida com este padrão essa propriedade passará a retornar o valor por defeito e não //null// como acontece com as propriedades ditas normais. Uma alternativa poderá ser afectar a propriedade com //String.Empty// (um campo que representa um string vazia) em vez de //null//. De salientar ainda que cada controlo pode aceder á sua colecção //ViewState// em qualquer momento e por qualquer razão, não apenas através de propriedades. 
- 
-Deve-se utilizar esta colecção quando as propriedades reflectem directamente tipos primitivos. No caso de controlos que têm pretendem manter um estado mais complexo, usando tipos próprios poderá ser mais complicado utilizar a colecção //ViewState//. Como alternativa podemos sobrepor dois métodos virtuais definidos na classe base //Control// sendo eles o //SaveViewState()// e o //LoadViewState()//. Estes métodos permitem escrever e ler manualmente o estado do controlo a partir da //stream ViewState//. Para um objecto poder ser guardado nessa //stream// tem que ser serializável. O método //SaveViewState()//, como o nome indica, permite guardar o estado de visualização. Note que este método também é responsável por chamar o método da base e guardar, no objecto a retornar, o resultado dessa chamada. 
-<code csharp>  
-protected override object SaveViewState() 
-{ 
-    ArrayList OsMeusDados = new ArrayList(); 
-    object[] vState = new object[2]; 
-    vState[0] = base.SaveViewState(); 
-    vState[1] = OsMeusDados; 
-    return vState; 
-} 
-</code> 
- 
-O método //LoadViewState()// permite recuperar o estado de visualização. Note que este método também é responsável por chamar o método da base, passando ao mesmo os dados que lhe pertencem. 
-<code csharp> 
-protected override void LoadViewState(object savedState) 
-{ 
-     if (savedState != null) 
-     { 
-         ArrayList OsMeusDados; 
-         // Obter o array de objectos guardados em SaveViewState 
-         object[] vState = (object[])savedState; 
-  
-         if (vState[0] != null) 
-             base.LoadViewState(vState[0]); 
-         if (vState[1] != null) 
-             OsMeusDados = (ArrayList)vState[1];             
-     } 
-} 
-</code> 
- 
-O leitor certamente reconhece um padrão de recursividade na chamada a estes métodos e é desta forma que a arquitectura ASP.NET constrói uma estrutura de dados com todo o conteúdo de estado de visualização.  
-Como já foi referenciado, o protocolo HTTP não tem memória. Isso significa que o estado da página terá que ser guardado e posteriormente reposto no pedido seguinte. Os pares nome/valor colocados na colecção //ViewState// antes da apresentação da página são armazenados num campo de input oculto, _//_VIEWSTATE//, e quando a página é de novo acedida através de um pedido de POST, o conteúdo do campo _//_VIEWSTATE// é analisado e usado para reconstituir a colecção //ViewState//. 
- 
-Falta-nos agora perceber como é mantido o estado dos controlos de formulário. Como já foi dito anteriormente, todos os controlos que correspondem a elementos de formulário têm a sua manutenção de estado suportada através do envio automático do valor dos elementos quando o formulário é submetido (//post back//). Esta manutenção de estado é realizada através da implementação da interface //IPostBackDataHandler//. 
-<code csharp>  
-public interface IPostBackDataHandler { 
- bool LoadPostBackData(string postDataKey, NameValueCollection postCollection); 
- void RaisePostDataChangedEvent(); 
-} 
-</code> 
- 
-Neste caso a arquitectura faz uma pesquisa no conteúdo do POST de modo a determinar se existem entradas que correspondem a controlos que implementam //IPostBackDataHandler// e de seguida é invocado o método //LoadPostData// para todos esses controlos. A string //postDataKey//, passado como argumento, contém o identificador único associado ao controlo, que pode ser usado para indexar sobre //postCollection// para localizar o valor corrente do controlo dentro da colecção como se pode verificar no seguinte exemplo: 
-<code csharp> 
-public virtual bool LoadPostData(string postDataKey, NameValueCollection postCollection) { 
-    string valorAntigo = Text; 
-    string valorNoPOST = postCollection[postDataKey]; 
-     
-    if (!valorAntigo.Equals(valorNoPOST)){ 
-          Text = valorNoPOST; 
-          return true; 
-    } 
-    return false; 
-} 
-</code> 
- 
-O resultado deste método deve ser //true// se mudou o valor do estado do controlo, caso contrário, o método deve devolver //false//. Para todos os controlos que retornam //true// neste método é chamado o //RaisePostDataChangedEvent// de cada um desses controlos de modo a poderem ser desencadeados eventos de alteração de estado. O leitor repare que o carregamento de dados de POST ocorre em duas fases, o método //LoadPostData// ocorre antes do método de //Load// da página e o método de //RaisePostDataChangedEvent// ocorre depois do método de //Load//. Isto permite que na altura em que as notificações são geradas todos os controlos tenham o seu estado reposto. 
- 
-Note ainda que, para além dos eventos de alteração de estado (eventos //changed//), como por exemplo alterações do texto de uma caixa de texto ou a alteração do índice seleccionado de uma //DropDownList//, também os eventos de reacção utilizam este mecanismo. Por exemplo, o evento de //click// de um botão é detectado e lançado utilizando esta interface.  
-Como se deve ter apercebido, a manutenção de estado de controlos de formulário não usa o campo oculto _//_VIEWSTATE// em nenhuma das suas fases e é completamente independente deste. É por essa razão que, mesmo que o //ViewState// não esteja activo, todos os controlos de formulário têm o seu estado automaticamente reposto. 
- 
-No entanto, na fase //LoadPostData//, é necessário saber o valor antigo de modo a poder compará-lo com o que vem no POST. Uma das formas é usar o //ViewState// para previamente guardar esse valor, que depois será usado na comparação com o valor recebido no POST. Note que, apesar da sua ligação próxima, são funcionalidades independentes. 
- 
-Voltando ao //ViewState//, a estrutura de dados com todo o conteúdo de estado de visualização não é directamente convertida para string e armazenada no campo _//_VIEWSTATE//. Lembra-se de falarmos que uma //StateBag// permitia fazer //tracking//? Ora bem, apenas são salvos no campo oculto as entradas da //StateBag// que estão marcadas como “//dirty//”, ou seja, apenas as entradas em que os seus estados são diferentes do estado estático ou estado por defeito. Não faz sentido guardar estado que será reposto automaticamente assim que exista um novo pedido e seja criada uma nova instância do controlo para atender esse pedido. Neste momento o leitor poderá estar a perguntar-se “então e os controlos definidos declarativamente?” Podemos definir de forma declarativa um controlo, como por exemplo: 
-<code asp> 
-<asp:Label ID="Label1" runat="server" Text="Label"> 
-</code> 
- 
-No momento em que a arquitectura ASP.NET faz //parse// do formulário, ao encontrar o atributo //runat=”server”// cria uma instância desse controlo e tenta corresponder todos os atributos definidos a propriedades publicas do controlo. No exemplo anterior olhando para o atributo Text percebemos que a arquitectura vai afectar a propriedade pública //Text// com o valor //“Label”//. Sabendo nós que quase todo o estado do controlo, se não todo, fica guardado em //ViewState// poderíamos ser levados a pensar que estes dados seriam considerados “//dirty//” visto que estamos a mudar o seu estado. Tal não acontece porque o //TrackViewState()// só é chamado no evento //Init// do ciclo de vida de uma página e todas estas afectações são feitas antes desse momento, ou seja, não serão consideradas “//dirty//”. 
- 
-Como referido, quando o ocorre a fase de //Init// é chamado o //TrackViewState()//. Após o //TrackViewState()// ser chamado para todas as //StateBags// é chamado o //LoadViewState()//, que faz com que todo o estado dinâmico de visualização guardado seja reposto e, mais importante ainda, visto que neste momento o //tracking// já está activo todo o estado dinâmico carregado será considerado “//dirty//”. Esta sequência fará com que o estado dinâmico de visualização seja reposto e fique novamente persistente para futuros post backs, ou seja, faz com que seja novamente seriado para _//_VIEWSTATE// 
-Através deste artigo espero que o leitor fique com uma ideia mais clara de como manter estado nos seus controlos tendo em atenção que quase todo, se não todo, o estado de visualização de um controlo é guardado em //ViewState//, mas apenas é persistido entre //post backs// o estado dinâmico. O estado por omissão que é criado quando é criada uma instância desse controlo (estado estático) não é persistido. 
- 
- 
-====Bibliografia==== 
- 
-Essential ASP.NET with Examples in C# - Fritz Onion - Addison Wesley 
- 
-Understanding ASP.NET View State - http://msdn.microsoft.com/en-us/library/ms972976.aspx 
- 
-ViewState in ASP.NET 2.0 - http://www.beansoftware.com/ASP.NET-Tutorials/ViewState-In-ASP.NET.aspx 
- 
-TRULY Understanding ViewState - http://weblogs.asp.net/infinitiesloop/archive/2006/08/03/Truly-Understanding-Viewstate.aspx 
- 
-IPostBackDataHandler Interface - http://msdn.microsoft.com/en-us/library/system.web.ui.ipostbackdatahandler.aspx 
- 
-StateBag Class - http://msdn.microsoft.com/en-us/library/system.web.ui.statebag.aspx 
- 
- 
-**Autor original**: Vitor Tomaz é estudante de Engenharia Informática e Computadores no ISEL bem como Profissional Independente na área das Tecnologias de Informação. Tem especial interesse por Programação Concorrente, Segurança Informática e Aplicações Web. 
-{{tag>aspnet csharp}}