Performance - Compactando ViewState

<< Click to Display Table of Contents >>

Navigation:  ASP.NET > Dicas avançadas > Performance >

Performance - Compactando ViewState

Previous pageReturn to chapter overviewNext page

Explicação 

 

Antes de iniciarmos esse artigo, irei explicar de forma rápida o que seria um ViewState.

"A grosso modo", ViewState é uma string que armazena informações sobre o estado da página em um campo oculto dentro da mesma.

Para ver o tamanho do ViewStatus, abra o fonte do seu site no browser.

 

É algo como isso

 

<input type="hidden" name="__VIEWSTATE" id="__VIEWSTATE" value="lYR+mupdIgw6/Ffwq8IxfYona/dklWa3vEvTa8NNaPq3I0N0ZvMlPWYcNK5J0raDg5Gaug7v29RGMQhWI3cVmglU+eHixRRIJsvVu5orVCmCljxU7uXb0ZbNVIoKJHadiF3ncx+xVvU6LUSrXTmr50bVfR3OW7C9Sl9rSseraYcegtbtgpr/Y0tcLTSgow+jsp4PUOrx9MHpwi4oSdf3UC5dyCwUmC+CpDf1gdyJ+4Mj/wgo5L7f+A7G70valqZB0diKjZ5L9qDNwh3j1mF/zBhhUPkGiNoYWtBl5vFTJZtag2HNFpvQAvcX3MrSnue8rDyxp7NS4WsnamI/kHIVdT1bl4rg7b4DZlq/7LAuISdu8ifYthD2ZjF7CRzHFCYRVDF+yft3t54dg6a9FPRmcxam97zMcTpYBBDPd2m0Ew7IFMt3IcxL1KdChC2Pc2IRlzDWKWgg4SFW72zaJOP0SDHK3gpaZCTgST1zbJ/mep1dICxI+Y8S4RPOjDp1qVgjm/x/14TDtqlsM0YnwJabpU1Ee1UdCKpgjE72IbvhrkQaqdQr1yEJOmBdlx9BTQYewE4JKa44pCVD00g1xTTWaNueWojTUs2nqzxic76JdhJAI2+SgjcAtUGPfScV9UTDGR+ziG+8l6oje9zwMymf65Y+uMvff7+u6fXhqNJdODyVsqHoallsOekucSdwUVb5SJ28uzuMdwEc+jWGkBRiXI9jUoQZ4dFcmSztJc2iRxCtY7DxvernHggE5k2zy9N++Hl+Eigdwo1mbQezPURinAz5lJP6aqUk9to78HJQseUjQKXesweRuNiLhERmor1lQJc" />

 

Geralmente quanto maior a complexibilidade de uma página, maior será as informações armazenadas em seu ViewState. Chegando a um ponto em que o ViewState prejudica o carregamento de nossa página.

Antes a solução seria eliminar o ViewState, mas agora poderemos partir para outra solução.

Ao usarmos a lib GZipStream podemos compactar o viewstate e com isso reduzir em 45% o tamanho do ViewState.

Veremos a partir de agora como compactar e descompactar dados na memória.

Nossa Classe de compactação usará System.IO.Compression e System.IO.

 

CompactadorViewState

 

Essa classe possui 2 métodos que recebem um array de byte e devolve outro array só que compactado/descompactado

Ela é relativamente simples, na mais que compactar e descompactar arrays.

 

using System.IO;

using System.IO.Compression;

 

  public class CompactadorViewState

   {

      public CompactadorViewState()

       {

          //

          // TODO: Add constructor logic here

          //

       }

 

      public static byte[] CompactarViewState(byte[] bytes)

       {

          MemoryStream MSsaida = new MemoryStream();

          GZipStream gzip = new GZipStream(MSsaida, CompressionMode.Compress, true);

           gzip.Write(bytes, 0, bytes.Length);

           gzip.Close();

 

          return MSsaida.ToArray();

       }

 

      public static byte[] DescompactarViewState(byte[] bytes)

       {

          MemoryStream MSentrada = new MemoryStream();

           MSentrada.Write(bytes, 0, bytes.Length);

           MSentrada.Position = 0;

          GZipStream gzip = new GZipStream(MSentrada, CompressionMode.Decompress, true);

 

          MemoryStream MSsaida = new MemoryStream();

 

          byte[] buffer = new byte[64];

          int leitura = -1;

           leitura = gzip.Read(buffer, 0, buffer.Length);

 

          while (leitura > 0)

           {

               MSsaida.Write(buffer, 0, leitura);

               leitura = gzip.Read(buffer, 0, buffer.Length);

           }

 

           gzip.Close();

          return MSsaida.ToArray();

       }

   }

 

Default.aspx.cs

 

Você deve criar estes 2 métodos após o PageLoad do seu aspx

 

      protected override object LoadPageStateFromPersistenceMedium()

       {

          string viewState = Request.Form["__VSTATE"];

          byte[] bytes = Convert.FromBase64String(viewState);

           

          // descompactar ViewState

           bytes = CompactadorViewState.DescompactarViewState(bytes);

          LosFormatter formatter = new LosFormatter();

          return formatter.Deserialize(Convert.ToBase64String(bytes));

       }

 

      protected override void SavePageStateToPersistenceMedium(object viewState)

       {

          LosFormatter formatter = new LosFormatter();

          StringWriter writer = new StringWriter();

           formatter.Serialize(writer, viewState);

          string viewStateString = writer.ToString();

          byte[] bytes = Convert.FromBase64String(viewStateString);

 

          // compactar ViewState

           bytes = CompactadorViewState.CompactarViewState(bytes);

           ClientScript.RegisterHiddenField("__VSTATE", Convert.ToBase64String(bytes));

       }

 

Para saber se está funcionando

 

Isto (Ver código fonte):

 

<input type="hidden" name="__VIEWSTATE" id="__VIEWSTATE" value="ksTDLG3c//UYrhwRHnL07uoCImO5t4/JjDchgOA97bK6/BeHUzBSt9hGeA1FpxW3Q+Jr0QdZNE3RIhJhAuIFpCRdZ6PHxV2UbNb0q+j.......

 
Vira isto:

 

<input type="hidden" name="__VSTATE" id="__VSTATE" value="H4sIAAAAAAAEAOS9B5wkxZkvuNPTY5hhLMMMIAlyF612eNsSGWkiM1fv7l52VXZ3DlWVrTK9Ys7s8TSsljsEehJ6/vihSz4go4C/v/wMrvwK.....
<input type="hidden" name="__VIEWSTATE" id="__VIEWSTATE" value="" />

 

 

Redução 

 

Num exemplo com GridView com 9 colunas e 1000 registros

O original tinha: 5,79 mb

Após compactação: 5,43 mb

7% menos.

 

Conclusão

 

Ao testar essa classe em uma página que gera pouca informação no ViewState, não será notado nenhuma diferença, mas caso seja alocado em uma página mais complexa a diferença será muito significativa. Eu fiz alguns testes e numa página com uma GridView e alguns Comboboxes o tamanho do html gerado caiu de 35kb para 27kb. 30% a menos.