ViewState Compression

Introduction

Recently, I developed a huge ASP.NET page, with more than 30 controls. As we all know, it's a good idea to disable the ViewState for the controls that don't actually need it, say Literals or Labels. After doing that, I noticed that the hidden ViewState field was still a few KBs big. This is obviously a big problem for the users that still don't have a broadband connection, because uploading 40 KB to the server is really a bad issue, especially when they begin to click the "Submit" button again and again because they don't notice any response. So, after a few searches through the Internet, I built a simple solution to compress the ViewState and therefore save a rough 50% of the bandwidth. This post by Scott Hanselman has been particularly useful. Although it's possible to use external libraries to perform compression tasks, I think the better solution is to use the GZipStream or DeflateStream that the .NET Framework 2.0 includes.

Compressing and Decompressing Data in Memory

First of all, we need a way to compress and decompress an array of bytes in memory. I put together this simple static class that exposes two methods: Compress and Decompress. The two available classes, GZipStream and DeflateStream, according to MSDN, use the same algorithm, so it's irrelevant which one you choose.

The code below is really simple, and doesn't need further explanation:

You need to save this class in a .cs file and put it in the App_Code directory of your ASP.NET application, making sure it's contained in the proper custom namespace (if you don't specify any namespace, the class will be available in the built-in ASP namespace).

Compressing the ViewState

Now, we can actually compress the ViewState of the page. To do that, we have to override the two methods LoadPageStateFromPersistenceMedium and SavePageStateToPersistenceMedium. The code simply uses an additional hidden field, __VSTATE, to store the compressed ViewState. As you can see, by viewing the HTML of the page, the __VIEWSTATE field is empty, while our __VSTATE field contains the compressed ViewState, encoded in Base64. Let's see the code.

In the first method, we just decode from Base64, decompress and deserialize the content of the __VSTATE, and return it to the runtime. In the second method, we perform the opposite operation: serialize, compress, and encode in Base64. The Base64 string is then saved into the __VSTATE hidden field. The LosFormatter object performs the serialization and deserialization tasks.

You may also want to create a new class, for example, CompressedPage, inheriting from System.Web.UI.Page, in which you override the two methods and then inherit your page from that class, for example MyPage : CompressedPage. Just remember that .NET has only single inheritance, and by following this way, you "spend" your only inheritance chance to use the ViewState compression. On the other hand, overriding the two methods in every class is a waste of time, so you have to choose the way that best fits your needs.

Performances and Conclusions

After a few tests, I noticed that the ViewState has been reduced from 38 KB to 17 KB, saving 44%. Supposing you have an average of 1 postback per minute per user, you could save more than 885 MB of bandwidth per month on every single user. That's an excellent result: you save bandwidth (and therefore money), and the user notices a shorter server response time.

I wanted to point out that this solution has a performance hit on the server's hardware. Compressing, decompressing, encoding, and decoding data is quite a heavy work for the server, so you have to balance the number of users with your CPU power and RAM.

Comments and Discussions

Nicely written article, but for solving this problem you should investigate http compression. All newer browsers support this, and IIS6 includes it (but its off by default). This will compress your entire page, not just the viewstate. I've frequently seen 70-80% compression on pages. Google httpzip for more information. It won't compress the upload upon a submit, though, but in general I think its preferable this solution.

I'm investigating HTTP compression too, but what I wanted in the first instance was a small ViewState because even on my DSL line the postback was really slow.
HTTP compression is nice, but needs that the client as well as the server supports it.
Anyway, I'm searching a way to enable HTTP compression on aspx pages via code, so it can also be enabled or disabled when needed without touching IIS (on most shared hosting plans you haven't access to IIS, for instance).

Yes, its all about trade-offs. I don't know the details of your app, but there have been several articles about storing viewstate on the server, either in session state or sql server. On a hosted server session state may be your only choice. Not sending the viewstate at all is the best compression! But it has its drawbacks too.

I didn't say that.
I said that you can use #ZipLib to do the same in .NET 1.1, but I never tried that. I never tried to use #ZipLib at all.
The post I mentioned at the beginning of the article uses #ZipLib, so you may find it useful.

The concern I have with this approach is that the viewstate will not be compressed until after it is base-64 encoded. I don't have any specific evidence but I suspect that the viewstate is much more compressible before being encoded, as is suggested in this article, so using HTTP compression would not provide as much compression.

Hey, I'm liking the concept but you didnt tell what all changes we require to do on page, e.g. __VIEWSTATE will still be used or not? I understand that we need to inherit all code behinds from the class you created instead of System.Web.UI.Page but what else changes do we need to do or will just inheriting sufficize compression need?

As I say in the article, __VIEWSTATE will be in the page, but it will be always empty. Instead, the new __VSTATE will contains the compressed data.

To enable compression, just include in the project the Compression class, and override the two methods described in the article in the pages in which you want to compress the ViewState.

You can also create a new class (say CompressedPage : System.Web.UI.Page) inheriting, in which override the two methods and then using it as a base class for your pages instead of the usual Page class (MyPage : CompressedPage).

I didn't apply the second way because in my project I already had to inherit MyPage from another class, and as you know .NET has only simple inheritance and because I had to enable or disable compression following the configuration options.

Anyway, thanks for your feedback. I'll update the article, specifying the two different ways to enable compression.