Compressing ViewState in ASP.NET using AJAX

Compressing ViewState in ASP.NET using AJAX

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. 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.

Here's an interesting, odd, but obvious idea. If you're not able to use some kind of the HttpCompression module you can "zip" up the ViewState.

Using Zipped ViewState

public class DefaulPage : CompressedPage 

Just derive class CompressedPage from System.Web.UI.Page as usual:

public class CompressedPage : System.Web.UI.Page

The "trick" is pretty simple. There are little-known virtuals in Page that you can override - specifically LoadPageStateFromPersistanceMedium (where that persistance medium is a hidden input box) and SavePageStateToPersistenceMedium.

When it's time to load view state, we pull it out of the form and un-base64 the string into a byte array, un-zip the bytes, then deserialize the ViewState. When it's time to save, reverse the process - Serialize, zip, store. There's some overhead, certainly. The amount of compression is usually about 50%, but your mileage may vary (YMMV).

Note that this sample uses SharpZipLib from ICSharpCode, but I assume you could use others, and I'd probably use System.IO.Compression if I was using .NET 2.0. The buffer sizes are hard-coded, but the only one that really matters it the one in Compress(). Again, salt to taste.

using System.IO;
using Zip = ICSharpCode.SharpZipLib.Zip.Compression;

/// 
/// Summary description for vioZip
/// 
public class CompressViewState
{
    public static byte[] Compress(byte[] bytes)
    {
           using (MemoryStream memory = new MemoryStream())
            {
                using (Zip.Streams.DeflaterOutputStream stream = new Zip.Streams.DeflaterOutputStream(memory, new Zip.Deflater(Zip.Deflater.BEST_COMPRESSION), 131072))
                {
                    stream.Write(data, 0, data.Length);
                    stream.Close();
                    return memory.ToArray();
                }
            }

    }

    public static byte[] Decompress(byte[] bytes)
    {
        Zip.Streams.InflaterInputStream stream = new Zip.Streams.InflaterInputStream(new MemoryStream(bytes));
        MemoryStream memory = new MemoryStream();
        byte[] writeData = new byte[4096];
        int size;
        while (true)
        {
            size = stream.Read(writeData, 0, writeData.Length);
            if (size > 0)
            {
                memory.Write(writeData, 0, size);
            }
            else
            {
                break;
            }
        }
        stream.Close();
        return memory.ToArray();
    }
}

Now create a base class for a page just as below

using System;
using System.Web;
using System.IO;
using Zip = ICSharpCode.SharpZipLib.Zip.Compression;
using System.Web.UI;
/// 
/// Summary description for PageViewStateZip
/// 
public class CompressedPage : System.Web.UI.Page
{
protected override object LoadPageStateFromPersistenceMedium()
{
            string vsString = Request.Form["__COMPRESSEDVIEWSTATE"];
            byte[] bytes = Convert.FromBase64String(vsString);
            bytes = CompressViewState.Decompress(bytes);
            return _formatter.Deserialize(Convert.ToBase64String(bytes));
}
protected override void SavePageStateToPersistenceMedium(object state)
{
            MemoryStream ms = new MemoryStream();
            _formatter.Serialize(ms, state);
            byte[] viewStateArray = ms.ToArray();
            //ClientScript.RegisterHiddenField("__COMPRESSEDVIEWSTATE", Convert.ToBase64String(CompressViewState.Compress(viewStateArray)));
            ScriptManager.RegisterHiddenField(this, "__COMPRESSEDVIEWSTATE", Convert.ToBase64String(CompressViewState.Compress(viewStateArray)));
}

Inherit this CompressedPage as the base page for all the webpages in your application.

public class DefaultPage : CompressedPage

Use the ScriptManager to register ViewState inside hidden field, especially if you are using AJAX.

For more information, refer to the SCOTT HANSELMAN Blog.

Posted by Ingenium Web

Ingenium Web

iNGENIUM Ltd. is an software development company from EU which delivers a full range of custom .NET, web and mobile solutions for different business to meet partner's demand.

The Power of Imagination Makes Us Infinite

Related Posts

Comments

comments powered by Disqus