web 2.0

Compression du ViewState ASP.NET avec prise en charge d'Ajax

Bonjour,

Aujourd'hui en relation avec mon article sur la compression du Cache et de la Session, je vous propose de voir la compression du ViewState.

Le ViewState est un élément qui peut être très coûteux pour les performance d'ouverture d'une page lorsque l'on utilise des Contrôles qui utilisent beaucoup le ViewState (GridView, DataList etc..)

Pour ce faire nous allons créer une classe permettant de gérer cette compression nommée ViewStateCompression qui sera héritée de PageStatePersister ainsi qu'une classe de base pour nos page web afin d'utiliser cette implémentation de compression de ViewState.

 

Dans notre classe ViewStateCompression qui hérite de PageStatePersister nous allons simplement implémenter deux méthodes afin de compresser et décompresser notre ViewState.

  • public override void Load()
  • public override void Save()
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.IO;
using System.IO.Compression;

namespace ViewStateCompression
{
    public class ViewStateCompression : PageStatePersister
    {
        #region Private Fields
        
        private LosFormatter _stateFormatter; 

        #endregion

        #region Protected Properties
        
        protected LosFormatter StateFormatter
        {
            get
            {
                if (_stateFormatter == null)
                    _stateFormatter = new LosFormatter();
                return _stateFormatter;
            }
        } 

        #endregion

        #region Constructors
        
        public ViewStateCompression(Page page)
            : base(page)
        {
        }

        #endregion

        #region Public PageStatePersister Overrides Methods
        
        public override void Load()
        {
            byte[] bts = Convert.FromBase64String(base.Page.Request.Form["__VSTATE"]);
            byte[] uncompressed = Decompress(bts);

            Pair p = (Pair)StateFormatter.Deserialize(Convert.ToBase64String(uncompressed));
            base.ViewState = p.First;
            base.ControlState = p.Second;
        }
        public override void Save()
        {
            TextWriter sw = new StringWriter();
            StateFormatter.Serialize(sw, new Pair(base.ViewState, base.ControlState));
            byte[] bts = Convert.FromBase64String(sw.ToString());
            byte[] compressed = Compress(bts);
            ScriptManager sm = ScriptManager.GetCurrent(base.Page);
            if (sm != null)
            {
                ScriptManager.RegisterHiddenField(base.Page, "__VSTATE", 
                    Convert.ToBase64String(compressed));
            }
            else
            {
                Page.ClientScript.RegisterHiddenField("__VSTATE", 
                    Convert.ToBase64String(compressed));
            }
        } 

        #endregion

        #region Private Static Methods

        private byte[] Compress(byte[] data)
        {
            using (MemoryStream output = new MemoryStream())
            {
                using (DeflateStream def = new DeflateStream(output, CompressionMode.Compress))
                {
                    def.Write(data, 0, data.Length);
                }
                return output.ToArray();
            }
        }
        private byte[] Decompress(byte[] data)
        {
            using (MemoryStream input = new MemoryStream())
            {
                input.Write(data, 0, data.Length);
                input.Position = 0;
                using (DeflateStream def = new DeflateStream(input, CompressionMode.Decompress))
                {
                    using (MemoryStream output = new MemoryStream())
                    {
                        byte[] buff = new byte[64];
                        int read = -1;
                        read = def.Read(buff, 0, buff.Length);
                        while (read > 0)
                        {
                            output.Write(buff, 0, read);
                            read = def.Read(buff, 0, buff.Length);
                        }
                        def.Close();
                        return output.ToArray();
                    }
                }
            }
        } 

        #endregion
    }
}
Rien de très compliqué dans cette classe, nous utilisons pour la compression la classe DeflateStream suite au retours de performances que j'avais décris dans mon article précédent.

Vous remarquez cependant dans la méthode Save() le code suivant

ScriptManager sm = ScriptManager.GetCurrent(base.Page);
if (sm != null)
{
    ScriptManager.RegisterHiddenField(base.Page, "__VSTATE", Convert.ToBase64String(compressed));
}
else
{
    Page.ClientScript.RegisterHiddenField("__VSTATE", Convert.ToBase64String(compressed));
}

Il s'agit en effet de la prise en charge d'Ajax dans le cas ou nous avons un ScriptManager présent dans nos pages.

 

Passons maintenant a notre classe de base pour nos pages web.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;

namespace ViewStateCompression
{
    public class BasePage : Page
    {
        #region Private Fields
        
        private ViewStateCompression _persister = null; 

        #endregion

        #region Constructors
        
        public BasePage()
        {
            _persister = new ViewStateCompression(this);
        }

        #endregion

        #region Protected Overrides Properties
        
        protected override PageStatePersister PageStatePersister
        {
            get
            {
                return _persister;
            }
        } 

        #endregion
    }
}

Nous y instancions donc  notre classe ViewStateCompression et nous modifions la propriété PageStatePersister afin d'utiliser notre propre Persister.

 

Maintenant vous allez me dire "oui mais quels en sont les résultats?"

Et bien les voici par un exemple simple. Nous allons créer une Web Form qui hérite de notre BasePage et y ajouter deux boutons

  • Création d'un objet "lourd" et enregistrement dans le ViewState
  • Lecteur du ViewState
protected void Populate_Click(object sender, EventArgs e)
{
    byte[] bts = new byte[20000];
    for (int i = 0; i < bts.Length; i++)
    {
        bts[i] = 0x45;
    }
    ViewState["Data"] = bts;
}

 

et

protected void ReadViewState_Click(object sender, EventArgs e)
{
    foreach (byte b in ViewState["Data"] as Byte[])
    {
        Response.Write(b.ToString());
    }
}

 

Nous obtenons les résultats suivants.

Sans ViewStateCompression : Fichier de 56 KB

Avec ViewStateCompression : Fichier de 4 KB

 

Sympa non? :)

Download Solution - ViewStateCompression.zip

 

yield return this;



Views(1023)

kick it on DotNetKicks.com

Share/Save/Bookmark Subscribe

Currently rated 2.0 by 1 people

  • Currently 2/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Tags: , , ,

ASP.NET | C#

Comments

Add comment


 

biuquote
Loading



Technorati Profile