10

What are the latest and greatest ways to compress the ASP.NET ViewState content?

What about the performance of this? Is it worth it to keep the pages quick and minimize data-traffic?

How can I make:

<input type="hidden" name="__VIEWSTATE" id="__VIEWSTATE" 
value="/wEPDwUKMTM4Mjc3NDEyOWQYAQUeX19Db250cm9sc1JlcXVpcmVQb3N0QmFja0tleV9fFgkFLGN0b
DAwJENvbnRlbnRQbGFjZUhvbGRlcl9NYWluQ29udGVudCRSYWRCdXQxBSxjdGwwMCRDb250ZW50UGxhY2VIb
2xkZXJfTWFpbkNvbnRlbnQkUmFkQnV0MQUsY3RsMDAkQ29udGVudFBsYWNlSG9sZGVyX01haW5Db250ZW50J
FJhZEJ1dDIFLGN0bDAwJENvbnRlbnRQbGFjZUhvbGRlcl9NYWluQ29udGVudCRSYWRCdXQyBSxjdGwwMCRDb
250ZW50UGxhY2VIb2xkZXJfTWFpbkNvbnRlbnQkUmFkQnV0MwUsY3RsMDAkQ29udGVudFBsYWNlSG9sZGVyX
01haW5Db250ZW50JFJhZEJ1dDQFLGN0bDAwJENvbnRlbnRQbGFjZUhvbGRlcl9NYWluQ29udGVudCRSYWRCd
XQ0BSxjdGwwMCRDb250ZW50UGxhY2VIb2xkZXJfTWFpbkNvbnRlbnQkUmFkQnV0NQUsY3RsMDAkQ29udGVud
FBsYWNlSG9sZGVyX01haW5Db250ZW50JFJhZEJ1dDXz21BS0eJ7991pzjjj4VXbs2fGBw==" />

Into sometning like this:

<input type="hidden" name="__VIEWSTATE"  id="__VIEWSTATE" 
value="/wEPDwUKMTM4Mjc3N==" />
Seb Nilsson
  • 26,200
  • 30
  • 103
  • 130

8 Answers8

8

The simple answer might not be what you want to hear. Too often, controls on the page have viewstate by default when they really don't need it. It's a good idea to switch off viewstate until you know you're going to need it, and only switch it on for the (hopefully) few cases where you actually want to keep the view state.

Bernhard Hofmann
  • 10,321
  • 12
  • 59
  • 78
  • 3
    +1 I think we are all guilty of not checking our pages for this. – IrishChieftain Mar 04 '10 at 15:10
  • +0.5, but there are too many cases where ASP.Net controls require ViewState even when they have no legitimate reason to require it. For example, if I recall correctly, events raised from controls within DataGrid/DataView/DataList won't correctly get called if the datagrid has viewstate disabled (even though the postback with correct parameters is still done on the client side) – ckarras Apr 08 '10 at 23:21
7
  1. Avoid using ViewState
  2. Use compression on the IIS server.
  3. You can wireup something that will compress the viewstate into and out of a page by doing something like:
public abstract class PageBase : System.Web.UI.Page
{
    private ObjectStateFormatter _formatter = new ObjectStateFormatter();

    private static byte[] Compress( byte[] data )
    {
            var compressedData = new MemoryStream();
            var compressStream = new GZipStream(output, CompressionMode.Compress, true);
            compressStream.Write(data, 0, data.Length);
            compressStream.Close();
            return compressedData.ToArray();
    }
    private static byte[] Uncompress( byte[] data )
    {
            var compressedData = new MemoryStream();
            input.Write(compressedData, 0, compressedData.Length);
            input.Position = 0;
            var compressStream = new GZipStream(compressedData, CompressionMode.Decompress, true);
            var uncompressedData = new MemoryStream();
            var buffer = new byte[64];
            var read = compressStream.Read(buffer, 0, buffer.Length);

            while (read > 0)
            {
                uncompressedData.Write(buffer, 0, read);
                read = compressStream.Read(buffer, 0, buffer.Length);
            }
            compressStream.Close();
            return uncompressedData.ToArray();
    }
    protected override void SavePageStateToPersistenceMedium(object viewState)
    {
        var ms = new MemoryStream();
        _formatter.Serialize(ms, viewState);
        var viewStateBytes = ms.ToArray();
        ClientScript.RegisterHiddenField("__COMPRESSED_VIEWSTATE"
            , Convert.ToBase64String( Compress(viewStateArray)) );
    }
    protected override object LoadPageStateFromPersistenceMedium()
    {
        var compressedViewState = Request.Form["__COMPRESSED_VIEWSTATE"];
        var bytes = Uncompress( Convert.FromBase64String( compressedViewState ) );
        return _formatter.Deserialize( Convert.ToBase64String( bytes ) );
    }
}
Thomas
  • 63,911
  • 12
  • 95
  • 141
  • Presumably if you use this you'll also need to delete the original Viewstate hidden field as well? – Graham Clark Mar 08 '10 at 10:00
  • In the Save...() method, I'd check whether viewStateBytes or Compress(viewStateBytes) is smaller, and then either write a __VIEWSTATE (with uncompressed), or __COMPRESSED_VIEWSTATE. No point sending the compressed version if it turns out to be larger. – Damien_The_Unbeliever Mar 08 '10 at 10:29
  • @Graham - Actually no. You are intercepting the calls that would save to the normal hidden __VIEWSTATE field so it will be empty. – Thomas Mar 08 '10 at 15:57
  • @Damien - That's not a bad idea. I'd be interesting to determine if there is a significant performance difference. It is also possible that if the data is small enough that the compressed version will come out larger than the uncompressed version. In some cases I've implemented an abstract "EnableViewStateCompression" property that derived pages can override and set to false if desired. – Thomas Mar 08 '10 at 16:00
  • 1
    If your ViewState is encrypted, I would expect no gain at all. – Dave Van den Eynde Nov 26 '10 at 15:13
  • @Dave Van den Eynde - Compression happens before the ViewState is encrypted. – Thomas Nov 26 '10 at 18:43
  • @Thomas in this example, no encryption is performed at all, it seems. – Dave Van den Eynde Nov 26 '10 at 19:48
  • 1
    Do not do this. This will expose your application to remote code execution vulnerabilities via unsafe object deserialization. – OJ. Jun 01 '23 at 01:47
  • @OJ. - If people are still using webforms in 2023, they have other code vulnerabilities with which to contend beyond compressed ViewState. By far the best answer is my first one: don't use ViewState and the best way to do that is to stop using webforms which isn't even supported by MS any longer. – Thomas Jun 13 '23 at 14:41
6

I realize this is an old thread, but we have been using Telerik's RadCompression HttpModule for a while now and it works incredibly well at compressing ViewState, AJAX and Web Service responses. You can also cheat and save ViewState in session - good for low traffic sites.

http://www.telerik.com/help/aspnet-ajax/radcompression.html

Rob Lauer
  • 3,075
  • 1
  • 32
  • 44
2

Again, after some research into this I summarized my findings in a blog-post about Compressing View State.

To save a compressed View State, this is what I did:

protected override void SavePageStateToPersistenceMedium(object state) {
    SaveCompressedPageState(state);
}

private void SaveCompressedPageState(object state) {
    byte[] viewStateBytes;
    using(MemoryStream stream = new MemoryStream()) {
        ObjectStateFormatter formatter = new ObjectStateFormatter();
        formatter.Serialize(stream, state);
        viewStateBytes = stream.ToArray();
    }

    byte[] compressed = CompressionHelper.Compress(viewStateBytes);
    string compressedBase64 = Convert.ToBase64String(compressed);

    ClientScript.RegisterHiddenField(ViewStateFieldName, compressedBase64);
}

And for the loading-part, this code made it work for me:

protected override object LoadPageStateFromPersistenceMedium() {
    return LoadCompressedPageState();
}

private object LoadCompressedPageState() {
    string viewState = Request.Form[ViewStateFieldName];
    if(string.IsNullOrEmpty(viewState)) {
        return string.Empty;
    }

    byte[] decompressed = CompressionHelper.Decompress(viewState);
    string decompressedBase64 = Convert.ToBase64String(decompressed);

    ObjectStateFormatter formatter = new ObjectStateFormatter();
    return formatter.Deserialize(decompressedBase64);
}
Seb Nilsson
  • 26,200
  • 30
  • 103
  • 130
  • 2
    Interestingly, by creating your instance of ObjectStateFormatter, it does not get a reference to the Page it's used in, and therefore will not attempt to encrypt viewstate. In this way, your serialized viewstate is much easier to compress, although it will never be encrypted regardless of your configuration. – Dave Van den Eynde Nov 26 '10 at 15:16
  • 1
    Do not do this. This will expose your application to remote code execution vulnerabilities via unsafe object deserialization. – OJ. Jun 01 '23 at 01:47
1

Seb, ViewState is already compressed... that is what you are seeing... a compressed version of your controls. If you want less overhead, then don't use viewstate :)

Viewstate use should be kept to a minimum!

Seb Nilsson
  • 26,200
  • 30
  • 103
  • 130
DigitalZebra
  • 39,494
  • 39
  • 114
  • 146
  • 8
    ViewState is only base-64 encoded. It is not "compressed"unless you consider base-64 compression. – Thomas Mar 04 '10 at 16:01
  • 1
    That's true, but his overall point isn't wrong either. Base64's composition is very difficult to compress with standard algorithms. Trying to gain significant ViewState savings through compression is futile. – Dave Ward Mar 04 '10 at 17:34
  • 1
    The ViewState string cannot be easily compressed, but not because it's base64 encoded. In reality, it's encrypted before it's encoded, and anything encrypted is by definition hard to compress. You should add compression before encryption. – Dave Van den Eynde Nov 26 '10 at 15:10
1

This is an XML-lized visualization of your posted viewstate:

<viewstate>
  <Pair>
    <Pair>
      <String>1382774129</String>
    </Pair>
  </Pair>
</viewstate>
<controlstate>
  <HybridDictionary>
    <DictionaryEntry>
      <String>__ControlsRequirePostBackKey__</String>
      <ArrayList>
        <String>ctl00$ContentPlaceHolder_MainContent$RadBut1</String>
        <String>ctl00$ContentPlaceHolder_MainContent$RadBut1</String>
        <String>ctl00$ContentPlaceHolder_MainContent$RadBut2</String>
        <String>ctl00$ContentPlaceHolder_MainContent$RadBut2</String>
        <String>ctl00$ContentPlaceHolder_MainContent$RadBut3</String>
        <String>ctl00$ContentPlaceHolder_MainContent$RadBut4</String>
        <String>ctl00$ContentPlaceHolder_MainContent$RadBut4</String>
        <String>ctl00$ContentPlaceHolder_MainContent$RadBut5</String>
        <String>ctl00$ContentPlaceHolder_MainContent$RadBut5</String>
      </ArrayList>
    </DictionaryEntry>
  </HybridDictionary>
</controlstate>

Basically just a few radiobuttons which like to know of their existance. (browsers don't send an <input type="radio"> field with the postdata if it is not checked). This is pretty minimal already.

It can likely be compressed by hooking in the load/save methods or HTTP modules, but this may not be really practical nor really needed.


In case the viewstate is much bigger in your real app, avoid getting objects in the viewstate at all. This can be achieved by initializing the controls in the OnInit() or Page_Init() methods instead of the default Page_Load().

The rationale behind this can be found at http://weblogs.asp.net/infinitiesloop/archive/2006/08/03/Truly-Understanding-Viewstate.aspx and http://msdn.microsoft.com/en-us/library/ms972976.aspx

A quick summary:

  • ViewState is just the backing store for almost all control properties, including defaults.
  • After the defaults are set by OnInit(), the TrackViewState() method will is called.
  • Any subsequent changes (e.g. by Page_Load()) or an eventhandler, will be tracked and submitted to the client. This way those controls can restore their state at the next request.
  • Instead of relying at the framework to restore objects, restore objects in OnInit() when needed. (e.g. repopulating the options of a DropDownList from the database).

One exception:

If a control is dynamically added to the control tree, it plays a catch-up. Their OnInit() method may run at a later moment, causing those properties to end up in the viewstate after all. If the initialization of the control can't happen in OnInit(), setting EnableViewState="false" can be used as workaround.

Each time my viewstate grows unexpectedly, I'm using the "ViewState Decoder 2.2" app to find out what ended up in the viewstate. Often, it's not needed for the data to be there.

And a final word:

The viewstate is not used for repopulating forms!! Those values are already submitted with the postdata.

vdboor
  • 21,914
  • 12
  • 83
  • 96
1

Compressing view state fails in certain cases: - If you are using update panel on page don’t use compression mode. - If somehow you are changing the view state in result of ICallBack code don’t use compression mode, as this will don’t reflect the correct view state on post back.

Matloob Ali
  • 719
  • 8
  • 9
0

The best way to minimize the view state is just to not use it. It will cause you to do some extra work programming (repopulating control values etc on post back, but it will save you on the amount of information you send to the browser). You can't tamper with it.

Here is a link to the view state on MSDN:

http://msdn.microsoft.com/en-us/library/ms972976.aspx

Here is a link describing some best practices:

http://mnairooz.blogspot.com/2007/01/aspnet-20-viewstate-and-good-practices.html

And One on disabling the ViewState:

http://www.codeproject.com/KB/aspnet/ASPNET_Best_Practices.aspx

kemiller2002
  • 113,795
  • 27
  • 197
  • 251
  • 1
    If one is going to repopulate controls, then why even bother using the ASP.NET Web form abstraction in the first place? Obviously, since Seb tagged this as asp.net-webforms" this is not an option. – IrishChieftain Mar 04 '10 at 15:09
  • 3
    You can use web forms without the view state. People do it all the time. There are a ton of tings that the controls handle for you without even touching the viewstate. – kemiller2002 Mar 04 '10 at 15:24
  • Repopulating controls is not one of them - that's why we use Web forms in the first place. I think the point is to turn it off selectively for controls that do not need it. – IrishChieftain Mar 04 '10 at 16:06
  • 1
    Actually, you can repopulate controls without the view state. – kemiller2002 Mar 04 '10 at 17:11
  • A form's data can be kept in the Viewstate without stashing it in the session, thus it's held by the user's browser, not the server - particularly useful for 'wizard' or secure applications. – GlennG Aug 04 '13 at 22:12