Skip to main content

ViewState Compression and AJAX, ASP.NET


I have found many articles and blog posts out there that talk about ViewState and how to handle it when it becomes too large. A large ViewState slows down your user’s browsing experience due to larger page sizes. There are many ways to address this issue: decreasing your use of ViewState, storing the ViewState in Session or elsewhere, HTTP compression, and the topic of my post, compressing the ViewState hidden field value.
At my last project we had been using ViewState compression, and it had worked just fine for them for a couple of years. The client was using the same solution that I’m sure 90% of the community was, where you override the two Page methods:
LoadPageStateFromPersistenceMedium
SavePageStateToPersistenceMedium
and store the compressed ViewState in a hidden form field. Here’s an example from one such article:

public partial class MyPage : System.Web.UI.Page
{
protected override object LoadPageStateFromPersistenceMedium()
{
string viewState = Request.Form["__VSTATE"];
byte[] bytes = Convert.FromBase64String(viewState);
bytes = Compressor.Decompress(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);
bytes = Compressor.Compress(bytes);
ClientScript.RegisterHiddenField("__VSTATE", Convert.ToBase64String(bytes));
}
}
Note that Compressor is a custom class that you would write to do the compression/decompression. See the article above for sample code using Microsoft’s built-in compression libraries.
On our new endeavor of using third-party controls that used AJAX we noticed a problem. It seems these controls do not like the ViewState being ‘moved’ to a different form field (here it was moved to __VSTATE instead of the standard __VIEWSTATE). There must be some hard-coded references to this field name, and they cannot properly track their own state. The controls loaded fine but most of the AJAX calls would not run all of the correct events on the server.
After some searching I came across a solution that still compresses the ViewState but does so in an AJAX-friendly manner by leaving it in the __VIEWSTATE field. Since it was a hard-to-find forum post I thought it warranted a little more visibility and discussion.
In ASP.NET 2.0, Microsoft added a class called PageStatePersister, which is also exposed a property on the Page class itself. The page events mentioned above are still there and used, but now they hand off the dirty work to the PageStatePersister. The PageStatePersister is responsible for loading and saving ViewState.
There are a couple of ways you can implement ViewState compression using these events and/or PageStatePersister. One way is that you could you write your own persister and override the PageStatePersister property on the Page to use your class instead.
In my case I decided to override the two Page events above and now work with the PageStatePersister within the events. First, let’s look at the LoadPageStateFromPersistenceMedium event:

protected override object LoadPageStateFromPersistenceMedium()
{
String alteredViewState;
byte[] bytes;
Object rawViewState;
LosFormatter fomatter = new LosFormatter();
this.PageStatePersister.Load();
alteredViewState = this.PageStatePersister.ViewState.ToString();
bytes = Convert.FromBase64String(alteredViewState);
bytes = Compressor.Decompress(bytes);
rawViewState = fomatter.Deserialize(Convert.ToBase64String(bytes));
return new Pair(this.PageStatePersister.ControlState, rawViewState);
}
You see we first tell the PageStatePersister to Load itself with the ViewState. We then decode it as a base64 string and decompress. It is then deserialized and placed into a Pair object with current control state. The Pair is what is returned.
And now for the SavePageStateToPersistenceMedium event:

protected override void SavePageStateToPersistenceMedium(object viewStateIn)
{
LosFormatter fomatter = new LosFormatter();
StringWriter writer = new StringWriter();
Pair rawPair;
Object rawViewState;
String rawViewStateStr;
String alteredViewState;
byte[] bytes;
if (viewStateIn is Pair)
{
rawPair = ((Pair)viewStateIn);
this.PageStatePersister.ControlState = rawPair.First;
rawViewState = rawPair.Second;
}
else
{
rawViewState = viewStateIn;
}
fomatter.Serialize(writer, rawViewState);
rawViewStateStr = writer.ToString();
bytes = Convert.FromBase64String(rawViewStateStr);
bytes = Compressor.Compress(bytes);
alteredViewState = Convert.ToBase64String(bytes);
this.PageStatePersister.ViewState = alteredViewState;
this.PageStatePersister.Save();
}
Here we take the viewStateIn, which is the normal ViewState and instead compress it before saving to the PageStatePersister.
Now our ViewState is compressed and stored in the standard __VIEWSTATE field and our AJAX-enabled controls should be happy!

Comments

Popular posts from this blog

ASP.NET MVC - Set custom IIdentity or IPrincipal

Here's how I do it. I decided to use IPrincipal instead of IIdentity because it means I don't have to implement both IIdentity and IPrincipal. Create the interface interface ICustomPrincipal : IPrincipal { int UserId { get ; set ; } string FirstName { get ; set ; } string LastName { get ; set ; } } CustomPrincipal public class CustomPrincipal : ICustomPrincipal { public IIdentity Identity { get ; private set ; } public bool IsInRole ( string role ) { return false ; } public CustomPrincipal ( string email ) { this . Identity = new GenericIdentity ( email ); } public int UserId { get ; set ; } public string FirstName { get ; set ; } public string LastName { get ; set ; } } CustomPrincipalSerializeModel - for serializing custom information into userdata field in FormsAuthenticationTicket object. public class CustomPrincipalSerializeMode...

Validate credit card number with Mod 10 algorithm in C#

Introduction All you know what information contains in your NIC number. But do you know what information contains in the Credit Card Number? Following article provides brief details about what information contain in your credit card and demonstrates to how to validate credit card number using mod 10 (Luhn) algorithms with C#. Background  Card Length   Typically, credit card numbers are all numeric and the length of the credit card number is between 12 digits to 19 digits.  14, 15, 16 digits – Diners Club 15 digits – American Express 13, 16 digits – Visa 16 digits - MasterCard   For more information please refer  http://en.wikipedia.org/wiki/Bank_card_number . Hidden information  Major Industry Identifier (MII)   The first digit of the credit card number is the Major Industry Identifier (MII). It designates the category of the entry which issued the card.     1 and 2 – Airlin...

Web Services Description Language Tool (Wsdl.exe)

Ref:  https://msdn.microsoft.com/en-us/library/7h3ystb6(VS.80).aspx The Web Services Description Language tool generates code for XML Web services and XML Web service clients from WSDL contract files, XSD schemas, and .discomap discovery documents. wsdl [options] {URL | path} Argument Description URL The URL to a WSDL contract file (.wsdl), XSD schema file (.xsd), or discovery document (.disco). Note that you cannot specify a URL to a .discomap discovery document. Path The path to a local WSDL contract file (.wsdl), XSD schema file (.xsd), or discovery document (.disco or .discomap). Option Description /appsettingurlkey: key or /urlkey: key Specifies the configuration key to use in order to read the default value for the URL property when generating code. When using the   /parameters   option, this value is the   <appSettingUrlKey>   element and contains a string. /appsettingbaseurl: baseurl or /baseurl:...