First of all, I will say hi to all. It is my very first attempt to write an article on any forum. I read somewhere that you can check that whether you are learning or not if "you are making mistakes provided everytime you make a new mistake". Well, I make lots of mistakes more than normal people . Anyway in this article, if you see some area of improvement, then please let me know so that next time I just make a new mistake .
Basically, this article will talk about
VIEWSTATE and server response customization techniques. Well, you know what is
VIEWSTATE and why ASP.NET introduced it.
VIEWSTATE (as the name tells) keep the state of the controls rendered by the server on client agents (e.g. Web Browsers, etc.) so that on next postback, it can inform the server about the previous state of the page control hierarchy, etc. All in all, what we can say is that it is a very important page element to keep state information as well as some other information to server (e.g. whether page is POSTBACK, etc.).
There are some other ways to keep the state information like server session but this consumes the server resources and may not be scalable solutions. Lots of people use the first option that is
VIEWSTATE to maintain the state information of server controls.
VIEWSTATE is saved in a hidden field named
One of the big problems with
VIEWSTATE is that it travels with each request and response and consumes precious bandwidth. So, in this article, we will look around for a way to minimize the
VIEWSTATE size. I have developed a little
HTTPMODULE to customize the Page rendered content.
It is better that you just have a look at these to better understand what I am trying to do here
Let's Have A Look Inside Page Class
In order to fully understand the concept and use it in your own scenario, I feel it is important to give you some inside idea how
Page class is maintaining
VIEWSTATE. If you are already familiar with it, you can skip this section.
Page class provides a number of virtual functions and properties to override. In our case, we just need to override one such property of
Page class, i.e.
PageStatePersister. Internal Implementation of
PageStatePersister property is shown below:
1 2 load controls state (VIEWSTATE/CONTROLSTATE)
3 protected virtual PageStatePersister PageStatePersister
7 if (this._persister == null)
9 PageAdapter pageAdapter = this.PageAdapter;
10 if (pageAdapter != null)
12 this._persister = pageAdapter.GetStatePersister();
14 if (this._persister == null)
16 this._persister = new HiddenFieldPageStatePersister(this);
19 return this._persister;
As highlighted in the above code snippet,
PageAdapter is used to get
PageStatePersister. Default persister is
1 2 public virtual PageStatePersister GetStatePersister()
4 return new HiddenFieldPageStatePersister(base.Page);
As far as my knowledge is concerned, there are two
Page State Persisters provided by the ASP.NET FCL (Framework Class Library).
It will use a hidden field such as
_VIEWSTATE to keep the state in
SessionPageStatePersister: It is used to save the state in
Session by using server resources.
How to Use this Code
Here in this section, I will give you a step by step demo about how we can achieve our final goal, i.e., to build custom State Persister to save and load compressed
1 public class ZipPageStatePersister : PageStatePersister
3 public ZipPageStatePersister(Page _page);
5 public static string CompressData(byte data);
6 public static byte Decompress(byte data);
7 public override void Load();
8 public override void Save();
In the above code snippet, I just gave you an outline of my custom
PageStatePersister Type. It has two
abstract methods, Load and Save implementation along with two
DeCompression methods. Let's have a look at each one by one...
1 public override void Save()
3 if (this.ViewState != null || this.ControlState != null)
5 using (StringWriter _writer = new StringWriter())
7 Pair _pair = new Pair(this.ViewState, this.ControlState);
9 LosFormatter _formatter = new LosFormatter();
10 _formatter.Serialize(_writer, _pair);
12 string _zippedData =
16 , _zippedData);
In the above code, we are checking that
ControlSate are not both
null. And we are using
LOSFormatter for serialization of our states. One of the very important points to note is that we are registering hidden fields to our page instance, the first parameter is the name of that hidden field and the second parameter is value (in our case, it custom serialize state compressed and then encoded in
1 public override void Load()
3 if (!string.IsNullOrEmpty(this.Page.Request.Form["_VSTATE"]))
5 byte bytes =Convert.FromBase64String(this.Page.Request.Form[
8 byte _decompressed = Decompress(bytes);
9 StringReader _reader = new
12 LosFormatter _formatter = new LosFormatter();
13 Pair _pair = _formatter.Deserialize(_reader.ReadToEnd()) as Pair;
15 if (_pair != null)
17 this.ViewState = _pair.First;
18 this.ControlState = _pair.Second;
When our page is loaded (in the case of
POSTBACK), then hidden field "
_VSTATE" (first argument of
RegisterHiddenField method described above); is keeping the state of our
Page. What is your guess - how we will load that state, you are guessing hmmmmm.... yes, you are right. It is
load method that will do the trick this time. In the above code, you can see that we are doing exactly the opposite of what we did in the
save method. First, we are decoding state information from
Base64 to byte array and decompressing it using
GzipCompressor. And the next few lines, I don't think need explanation. Quite simple, ahhhhhhha?
OK, I am not showing compression and decompression code here because in those methods, I am just using
GZipCompressor class. Anyway, now we are ready to override
PageStatePersister. And here is the code...
1 public partial class WebForm1 : System.Web.UI.Page
3 private ZipPageStatePersister _zipperPSP;
5 protected WebForm1()
7 this._zipperPSP = new ZipPageStatePersister(this);
10 11 12 13 protected override PageStatePersister PageStatePersister
17 return _zipperPSP;
18 19 }
We are creating a
private member of our newly created State Persister class and returning it in
PageStatePersister instead of default
HiddenFieldPageStatePersister; Well we are done here. Now when you will view your page in browser, you can see a hidden field name
_VSTATE containing the state information. But you will probably notice that old
_VIEWSTATE hidden field is still there, but empty in this case.
Getting Rid of _VIEWSTATE Field
When I saw this behavior, then the first solution that came into my mind was to use
HTTPHANDLER. But we cannot write to
HttpApplication.Context.Resoponse.OutputStream. Fortunately, I found somebody has already encountered it. The solution is to keep the client stream and then create own customized stream to write the output. I will not explain the whole procedure here as you can find, but I will just explain what I did to remove
StdViewStateRemover is implementing IHttpModule and VSStream is nested type extending Stream class to customize the output in its write method
Here is the
write method that I used to get rid of standard
1 public override void Write(byte buffer, int offset, int count)
3 System.Text.UTF8Encoding utf8 = new System.Text.UTF8Encoding();
4 System.Text.StringBuilder strBuff = new
7 8 Regex reg =
9 new Regex("<input type=\"text\" name=\"__VIEWSTATE\"[\\w\\W]* />");
11 string _temp = reg.Replace(strBuff.ToString(), string.Empty);
12 strBuff.Remove(0, strBuff.Length - 1).Append(_temp);
HTTPModule Registering in web.config
In order to
HttpModule, you have to register module in web.config:
2 <add type="WebApplication1.StdViewStateRemover, WebApplication1 "
Now when you view the page in browser, then in source, you can easily verify that
_VSTATE exists with compressed
Points of Interest
OK. That's it for now. But you have got an idea how you can extend this
HttpModule to customize page response. If you don't want to extend
PageStatePersister, then you can also compress
Write method of custom output stream.
Now, I am trying to find out how much this solution is promising for me to utilize in large
VIEWSTATE case and how much it has an impact on my server's performance while compressing/decompressing.