ASP.NET Compress ViewState


Short definition of ViewState from MSDN:
Microsoft® ASP.NET view state, in a nutshell, is the technique used by an ASP.NET Web page to persist changes to the state of a Web Form across postbacks. In my experiences as a trainer and consultant, view state has caused the most confusion among ASP.NET developers. When creating custom server controls or doing more advanced page techniques, not having a solid grasp of what view state is and how it works can come back to bite you. Web designers who are focused on creating low-bandwidth, streamlined pages oftentimes find themselves frustrated with view state, as well. The view state of a page is, by default, placed in a hidden form field named __VIEWSTATE. This hidden form field can easily get very large, on the order of tens of kilobytes. Not only does the __VIEWSTATE form field cause slower downloads, but, whenever the user posts back the Web page, the contents of this hidden form field must be posted back in the HTTP request, thereby lengthening the request time, as well.

The Cost of View State and Why we should consider to compress it:
Nothing comes for free, and view state is no exception. The ASP.NET view state imposes two performance hits whenever an ASP.NET Web page is requested:

  1. On all page visits, during the save view state stage the Page class gathers the collective view state for all of the controls in its control hierarchy and serializes the state to a base-64 encoded string. (This is the string that is emitted in the hidden __VIEWSTATE form filed.) Similarly, on postbacks, the load view state stage needs to deserialize the persisted view state data, and update the pertinent controls in the control hierarchy.
  2. The __VIEWSTATE hidden form field adds extra size to the Web page that the client must download. For some view state-heavy pages, this can be tens of kilobytes of data, which can require several extra seconds (or minutes!) for modem users to download. Also, when posting back, the __VIEWSTATE form field must be sent back to the Web server in the HTTP POST headers, thereby increasing the postback request time.

Where is in the Pipeline ?
The view state is serialized to the hidden form field in the Page class’s SavePageStateToPersistenceMedium() method during the save view state stage, and is deserialized by the Page class’s LoadPageStateFromPersistenceMedium() method in the load view state stage. With just a bit of work we can have the view state persisted to the Web server’s file system, rather than as a hidden form field weighing down the page. To accomplish this we’ll need to create a class that derives from the Page class and overrides the SavePageStateToPersistenceMedium() and LoadPageStateFromPersistenceMedium()methods.

After some boring information  lets Compress our  ViewState

First for compressing a byte array add this code to your project.

using System;
using System.Text;
using System.IO;
using System.IO.Compression;
 
public static class MemoryCompressor
{
    /// <summary>
    /// Compress given data with Gzip
    /// </summary>
    /// <param name="unCompressedData">the data to compress as byte array </param>
    /// <returns>Compressed data as byte array </returns>
    public static byte[] Compress(byte[] unCompressedData)
    {
        using (MemoryStream ms = new MemoryStream())
        {
            //Select as compress
            CompressionMode cmode = CompressionMode.Compress;
            //Compress Data dont forget to leave open true..
            using (GZipStream gzip = new GZipStream(ms, cmode, true))
            {
                gzip.Write(unCompressedData, 0, unCompressedData.Length);
            }
            return ms.ToArray(); //Return as byte []
        }
    }
 
    /// <summary>
    /// Decompress given data with Gzip
    /// </summary>
    /// <param name="compressedData">the data to decompress as byte array </param>
    /// <returns>Decompressed data as byte array </returns>
    public static byte[] Decompress(byte[] compressedData)
    {
        GZipStream gzip;
        using (MemoryStream ms = new MemoryStream())
        {
            ms.Write(compressedData, 0, compressedData.Length);
            // Reset the memory stream 
            ms.Position = 0;
            //Decompress
            CompressionMode mode = CompressionMode.Decompress;
            //Get Stream 
            gzip = new GZipStream(ms, mode, true);
 
            using (MemoryStream outMs = new MemoryStream())
            {
                // 4096 bytes as buffer gives you best performance..
                byte[] buffer = new byte[4096];
                int byteReaded = -1;
                byteReaded = gzip.Read(buffer, 0, buffer.Length);
                while (byteReaded > 0)
                {
                    //write to output stream
                    outMs.Write(buffer, 0, byteReaded);
                    //keep going...
                    byteReaded = gzip.Read(buffer, 0, buffer.Length);
                }
                gzip.Close();//Dont forget to close it.
                return outMs.ToArray(); //return as byte array
            }
        }
    }
}

Add this code to your Page or BasePage code

public class BasePage:System.Web.UI.Page
{
    ...
    protected override object LoadPageStateFromPersistenceMedium()
    {
        string viewState = string.Empty;
        // try to get state data form RequestForm.
        viewState = Request.Form["__COMPRESSEDVSTATE"];
        // Decompress the encoded and compressed state data than return it.
        byte[] bytes = Convert.FromBase64String(viewState);
        bytes = Utilities.MemoryCompressor.Decompress(bytes);
        LosFormatter formatter = new LosFormatter();
        return formatter.Deserialize(Convert.ToBase64String(bytes));
    }
    protected override void SavePageStateToPersistenceMedium(object state)
    {
        //Encode state data
        LosFormatter formatter = new LosFormatter();
        StringWriter writer = new StringWriter();
        formatter.Serialize(writer, state);
        string viewStateString = writer.ToString();
        byte[] bytes = Convert.FromBase64String(viewStateString);
        bytes = Utilities.MemoryCompressor.Compress(bytes);
        //Save to page hidden field
        ClientScript.RegisterHiddenField("__COMPRESSEDVSTATE", Convert.ToBase64String(bytes));
    }
    ...
}

Note: You always consider that you need viewstate if not you should disable it or disable controls viewstates that not need to be store data in viewstate. And also there is a better way to use compress data that HttpCompress look for it.
Another artice of mine about storing viewstate data in Session:
http://blog.bugrapostaci.com/2010/02/04/asp-net-store-viewstate-data-in-session/

For more information about viewstate
http://msdn.microsoft.com/en-us/library/ms972976.aspx

May the code be with you..

Advertisements

About bpostaci
Escalation Engineer in Microsoft.

One Response to ASP.NET Compress ViewState

  1. Pingback: ASP.NET store Viewstate data in Session « Bugra Postaci's Blog

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: