Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

ViewState: Various ways to reduce performance overhead

0.00/5 (No votes)
19 Aug 2010 1  
This article discuss about the Viewstate and also several ways to reduce the performance hit caused by it, with a sample application.

Table of Contents

Introduction:

In this Article, I am going to explore the View State. View state is one thing that always I liked to use. It makes our life easier. As we all know that Viewstate is one way of maintaining the states in the web applications.

As we know, a web page is created every time when a page is posted to the server.It means The values that user entered in the webpage is going to be vanished after the postback or submit. To get rid of this problem, ASP.NET framework provides a way to maintain these values by virtue of View State. When we enable the viewstate of any control, the value is going to be maintained on every postbacks or server roundtrips.

But how these values get maintained? It doesn't come free.View State uses hidden variable that resides on the page to store the controls values. It means that if a page have lots of controls with viewstate enabled the page size would become heavy, in several of kilobytes ie it will take longer time to download.And also on every postback all the data is posted to the server i e increasing the network traffic as well.

As in new era application, we use lots of heavy controls like gridview etc, on our page which makes page size exponentially heavy.It is always recommended to use View State judiciously and even some programmers try to avoid using this cause of performance overhead.

Here , I am going to discuss how we can reduce the performance overhead caused by View State.

What is View State:

As we know Web is stateless medium ie states are not maintained between the requests by default.A web page is created every time when a page is posted to the server. ASP.NET framework provides us several ways to maintain the state.These are

States.JPG

Fig: Various State Management technique in ASP.NET

Here we going to discuss the one of the ClientState management technique ViewState.We can persist the data during the postback with the help of viewstate. Why we call viewstate as clientside? because the data is going to be stored on the page, if we move from one page to another the data would be lost.

So where the view state gets stored?

View state is stored on the page in form hidden field named as __viewstate

Here I will not discuss the basics of view state in detail, for detail have a look to one of the very good article on cp itself. That is

Beginner's Guide To View State [^]

Problems with View State:

In our new era application, we generally have lots of rich and heavy controls on our page and also provide lots of functionality on the page with the help of few latest technology AJAX etc. To accomplish our task we use View State a lot but as we know it doesn't come free it has a performance overhead.

As we know viewstate is stored on the page in form of hidden variable. Its always advised to use viewstate as less as possible. we have also other ways to reduce the performance overhead. So we have several ways,here I am going to discuss the following ways

  • By compressing decompressing the viewstate
  • Another way to store the view state at some other server say on web server.

We will see all these with an example.

So here I will be taking an example and will show you, How we can achieve better performance with the help of above techniques

First lets see a normal scenario!!

Here, I have a webpage a gridview which is showing a lot of data (16 no of rows).I have enabled the viewstate so that I dont need to repopulate the whole grid on every postback. But what I am paying for that? Let's see the example.

First lets see the pagesize on postback with enableviewstate true which is true by Default.

Page with View State enabled

Fig: Page with View State enabled

Here we can see the request size 4.9 k. Also we can see the viewstate of the page by viewing the viewsource. Let's see it

gridwithviewstatesrc.JPG

Fig: __Viewstate hidden form field with Viewstate enabled

So you can see the __viewstate variable on the screen and the amount of data it has. Now we can imagine, if we have several control like this what will your page size .

But the benefit, we dont need hit the database to fetch the data and bind it on every postback.

Now lets see what happens when we disable the viewstate ie setting the enableviewstate false. Here I clicked on postback,

gridviewwithoutviewstate.JPG

Fig:"Page with Viewstate disabled

and there is no data on page because I have loaded the data first time on page load on subsequent postbacks I didn,t bind it that's why when I click on PostBack the data got lost but the page size is here is just 773 B. Also lets examine the viewsource of the page

gridwithoutviewstatesrc.JPG

Fig: __Viewstate hidden form field with Viewstate disabled

Here we also see __viewstate variable but with very less data. But this much also.I'll answer it, Although we have disabled the viewstate, ASP.NET uses viewstate some data to maintain the page state but this is very less not going to cause performance overhead.

But what we get from the viewstate? we didn't need to repopulate the grid again. Just bind it on first pageload and on rest postbacks the data got populated from viewstate. Note: Here I am using Firebug for the analysis purpose.

So Now we can imagine, the overhead of viewstate.Even you can check of your application (if you are using viewstate), and check the page size increased by the viewstate. So, here I am going to discuss one way to reduce the page size.

View State Compression/Decompression:

We can compress the viewstate to reduce the pagesize. By compressing the viewstate we can reduce the viewstate size by more than 30%. But here the question arises, where to compress and decompress the viewstate. For that we have to dig into the Page life cycle. As we know, viewstate is used by the ASP.NET to populate the controls. So we should compress the viewstate after all the changes are done in the viewstate and saving it after compression and we have to decompress the viewstate just before it is used by asp.net to load all the controls from viewstate . So lets jump to thepage life cycle and see our we can fit our requirement.

pagelifecycle.JPG

Fig: ASP.NET: Page Life Cycle

As we can see there are two methods,One SaveViewState that is responsible for collecting the view state information for all of the controls in its control hierarchy in this method and persist it it in __viewstate hiddenform field. The view state is serialized to the hidden form field in the SavePageStateToPersistenceMedium() method during the save view state stage, and is deserialized by the Page class's LoadPageStateFromPersistenceMedium() method in the load view state stage. So here in these methods we can compress and decompress the viewstate. Lets take a pictorial view.

viewstate.JPG

Fig: ASP.NET: How viewstate gets maintained

So here, we need to override the methods SavePageStateToPersistenceMedium()for compressing the viewstate and SavePageStateToPersistenceMedium() for decompressing the viewstate. Here I am going to use GZip for compression that is provided by the .NET itself.And this is available in th namespace System.IO.Compression. So Lets jump to the code

I have made one Class CompressViewState that is inherited from System.Web.UI.Page. Here I have overridden the above said two methods. I also made two private methods one for compressing a byte stream and another for decompressing it. Lets have a look for the compressing one:

    /// This Method takes the byte stream as parameter 
    /// and return a compressed bytestream.
    /// For compression it uses GZipStream
    private byte[] Compress(byte[] b)
    {
        MemoryStream ms = new MemoryStream();
        GZipStream zs = new GZipStream(ms, CompressionMode.Compress, true);
        zs.Write(b, 0, b.Length);
        zs.Close();
        return ms.ToArray();
    }
       

As you can see the Compress method is taking a byte array as a parameter and returning compress data in byte array form.In the method, I have used GZipStream for compressing the data.Now lets have a look for the decompressing one

    /// This method takes the compressed byte stream as parameter
    /// and return a decompressed bytestream.

    private byte[] Decompress(byte[] b)
    {
        MemoryStream ms = new MemoryStream();
        GZipStream zs = new GZipStream(new MemoryStream(b), CompressionMode.Decompress, true);
        byte[] buffer = new byte[4096];
        int size;
        while (true)
        {
            size = zs.Read(buffer, 0, buffer.Length);
            if (size > 0) 
                ms.Write(buffer, 0, size);
            else break;
        }
        zs.Close();
        return ms.ToArray();
    }
        

As you can see, this method is taking compressed data as a parameter and returning decompressed data.

Now lets have look to the overridden methods. First LoadPageStateFromPersistenceMedium

protected override object LoadPageStateFromPersistenceMedium()
{
    System.Web.UI.PageStatePersister pageStatePersister1 = this.PageStatePersister;
    pageStatePersister1.Load();
    String vState = pageStatePersister1.ViewState.ToString();
    byte[] pBytes = System.Convert.FromBase64String(vState);
    pBytes = Decompress(pBytes);
    LosFormatter mFormat = new LosFormatter();
    Object ViewState = mFormat.Deserialize(System.Convert.ToBase64String(pBytes));
    return new Pair(pageStatePersister1.ControlState, ViewState);
}
        

So you can see, in this method we have taken the viewstate in a string variable from PageStatePersister Decompressed it(As it is compressed in saveviewstate stage, we'll discuss after this) and deserialized it in an object and returned the new Pair.

Now moving to the SavePageStateToPersistenceMedium.

protected override void SavePageStateToPersistenceMedium(Object pViewState)
{
      Pair pair1;
        System.Web.UI.PageStatePersister pageStatePersister1 = this.PageStatePersister;
        Object ViewState;
        if (pViewState is Pair)
        {
            pair1 = ((Pair)pViewState);
            pageStatePersister1.ControlState = pair1.First;
            ViewState = pair1.Second;
        }
        else
        {
            ViewState = pViewState;
        }
        LosFormatter mFormat = new LosFormatter();
        StringWriter mWriter = new StringWriter();
        mFormat.Serialize(mWriter, ViewState);
        String mViewStateStr = mWriter.ToString();
        byte[] pBytes = System.Convert.FromBase64String(mViewStateStr);
        pBytes = Compress(pBytes);
        String vStateStr = System.Convert.ToBase64String(pBytes);
        pageStatePersister1.ViewState = vStateStr;
        pageStatePersister1.Save();
}
        

So Here, what we are doing, we are reading the viewstate information from pageStatePersister and then serialize it and finally after compressing it, saved it in page persister.

So this is all about the compressing and decompressing the viewstate. I have put the class in the App_Code folder so that it is available to entire application. And where ever we need to use it we should inherit it from CompressViewState By this although we can not remove the viewstate size fully but we can reduce it size significantly and making our application's performance much better :).

Now Lets move to the Another methodology That is Saving the viewstate into the file system.

Points to remember:

-This methodology should be used only you have enough data in viewstate else you will be more time in compressing and decompressing the viewstate between request without much gain.

Saving View State on server:

Here I am going to explan two approach.

Using Session

Using Hidden Field:

Using Session:

This way we can reduce the viewstate size to zero now you can assume still you are using the viewstate significantly there is no performance overhead on round trip to server.Still there is bit overhead to reading and saving the viewstate in file system. We'll discuss it later.

Now in this methodology also, we need to use the two methods

-LoadPageStateFromPersistenceMedium

-SavePageStateToPersistenceMedium

Here we are going saving to save the viewstate in file system. But how we'll save.What would be the name of the file? (As it has to be unique for every user? Do we need multiple files for the same user session.

There are a lot of questions.One answer, we dont need multiple for the same user at the same time because viewstate is confined to every page and when user moves to other page, earlier page's View State get ripped off. So at a time we just need to save the current page View State.

As sessionid is unique for every user, so why should we not use the sessionid in the file to make it unique and whenever we'll need to get the file we'll just pick by session id.

So lets jump to the code.

Here I have a file name PersistViewStateToFileSystem that is inherited from System.web.UI.Page and residing in the App_code folder so that it is available through the whole application. Here we have a property which returns the full path of the viewstate file. Here I have used the sessionid as a name of the file and .vs as a extension. here we have a property that returns the path of the viewstate file, that is

public string ViewStateFilePath
    {
        get
        {
            if (Session["viewstateFilPath"] == null)
            {
                string folderName = Path.Combine(Request.PhysicalApplicationPath, "PersistedViewState");
                string fileName = Session.SessionID + "-" + Path.GetFileNameWithoutExtension(Request.Path).Replace("/", "-") + ".vs";
                string filepath = Path.Combine(folderName, fileName);
                Session["viewstateFilPath"] = filepath;
            }
            return Session["viewstateFilPath"].ToString();
        }
    }
       

Again here we have implemented both the function

LoadPageStateFromPersistenceMedium is loading the file from the View State file if it exists. So lets have a look for the code for LoadPageStateFromPersistenceMedium

 protected override object LoadPageStateFromPersistenceMedium()
{
    // determine the file to access
    if (!File.Exists(ViewStateFilePath))
        return null;
    else
    {
        // open the file
        StreamReader sr = File.OpenText(ViewStateFilePath);
        string viewStateString = sr.ReadToEnd();
        sr.Close();

        // deserialize the string
        LosFormatter los = new LosFormatter();
        return los.Deserialize(viewStateString);
    }
}
        
and SavePageStateToPersistenceMedium is saving the file in file system instead of pagepersister . So moving to the code of LoadPageStateFromPersistenceMedium
  
protected override void SavePageStateToPersistenceMedium(object state)
{
    LosFormatter los = new LosFormatter();
    StringWriter sw = new StringWriter();
    los.Serialize(sw, state);

    StreamWriter w = File.CreateText(ViewStateFilePath);
    w.Write(sw.ToString());
    w.Close();
    sw.Close();

}
      

We need to inherit our page from the class PersistViewStateToFileSystem to use it.

Removing View State file from server:

What is the best place to remove the viewstate file from server? Our requirement is to remove the file at session end.So we can use Application level Session_End(that is defined in Global.asax file) to remove the file from webserver.I have saved the viewstate file path in session and accessing the file path from there. Lets see the code of Session_End
  void Session_End(object sender, EventArgs e) 
    {
        //Deleting the viewstate file
        string filePath = Session["viewstateFilPath"] as string;
        if (!string.IsNullOrEmpty(filePath) && File.Exists(filePath))
        {
            File.Delete(filePath);
        }
    }
 

You can get the full sample application in the attachment.

Now lets move to our example. Lets see the request size .

gridonserver.JPG

Fig: Viewstate saved on server

Ohh its just 2.5 K. Now we can see our page size reduced dramatically.Now lets see the view source of the page

viewstateserver.JPG

Fig:__Viewstate hidden form field with Viewstate saved on server

Cool!!!. There is no data in the viewstate variable.

Points to remember:

-This methodolgy only works, if cookies are not disabled on client machines.

-We need to remove the viewstate file after using it.Here I have taken the approach to remove it at Session_End which works only in InProc mode

-Only use if viewstate size is heavy else no need. Because it will take more to save the viewstate in file system and on reading.

-We can also compress the viewstate while saving viewstae on server.

- This option might not work on webfarm and webgarden scenario.

Using Hidden Field:

First I would say thanks all who shared their valuable feedback. I am adding section because of them.
As Session Id approach has many limitation as I mentioned in Points to remember section. So I have added the following New Approach
Using hidden field
We can use GUID instead of session Id to uniquely identify the View State file.And to get the GUID we will be using a hiddenfield to store the guid, so that we can get file name as n when we require. So now here, we only need to change the View State File path property and need to have a hidden field on every page.The hidden field on the page can be as
<asp:hiddenfield runat="server" id="hfVSFileName">
So actually, In my demo application, I have added a key isSessionId in app.config section of web.config, if it set true then we are using SessionId approach else HiddenField Approach for making it configurable. So now lets see the property Code
  public string ViewStateFilePath
    {

        get
        {
            bool isSessionId = Convert.ToBoolean(System.Configuration.ConfigurationManager.AppSettings["isSessionId"]);
            string folderName = Path.Combine(Request.PhysicalApplicationPath, "PersistedViewState");
            string fileName = string.Empty;
            string filepath = string.Empty;
            if (!isSessionId)
            {
                HiddenField hfVSFileName = null;
                string VSFileName = "";

                // Get the HiddenField Key from the page
                hfVSFileName = FindControl(this, "hfVSFileName") as HiddenField;

                // Get the HiddenField value from the page
                string hfVSFileNameVal = GetValue(hfVSFileName.UniqueID.ToString());
                if (!string.IsNullOrEmpty(hfVSFileNameVal))
                {
                    VSFileName = hfVSFileNameVal;
                }

                if (!Page.IsPostBack)
                {
                    VSFileName = GenerateGUID();
                     hfVSFileName.Value = VSFileName;

                    //Removing files from Server
                    RemoveFilesfromServer();
                }

                fileName = VSFileName + "-" + Path.GetFileNameWithoutExtension(Request.Path).Replace("/", "-") + ".vs";
                filepath = Path.Combine(folderName, fileName);

                return filepath;
            }
            else
            {
                if (Session["viewstateFilPath"] == null)
                {

                    fileName = Session.SessionID + "-" + Path.GetFileNameWithoutExtension(Request.Path).Replace("/", "-") + ".vs";
                    filepath = Path.Combine(folderName, fileName);
                    Session["viewstateFilPath"] = filepath;
                }
                return Session["viewstateFilPath"].ToString();
            }
        }
    }
 
Here in the code, you can see that based on the configuration, I am using Hiddenfield or sessionId approach.In hiddenfield approach, I am creating a GUID for uniqueness of the filename and also that is created only once on Pageload.

Removing ViewState files from server:

Also a change I have made regarding removing files from server. Here, I am removing files from the server which is older than 3 days.Lets see the code
  private void RemoveFilesfromServer()
    {
        try
        {
            string folderName = Path.Combine(Request.PhysicalApplicationPath, "PersistedViewState");
            DirectoryInfo _Directory = new DirectoryInfo(folderName);
            FileInfo[] files = _Directory.GetFiles();
            DateTime threshold = DateTime.Now.AddDays(-3);
            foreach (FileInfo file in files)
            {
                if (file.CreationTime <= threshold)
                    file.Delete();
            }
        }
        catch (Exception ex)
        {
            throw new ApplicationException("Removing Files from Server");
        }
    }
 
I am calling this method from once on every new page request. You can call this method based on your design. We can also make the number of days configurable.

Conclusion:

At last, I just want to say, we generally use lots of viewstae controls on our page so at least we should use one of the discussed approach.

Feedback and Suggestions:

Feedback is the key for me. Feedback is the key for me.I would request to you all to share your feedback and give me some suggestions, which which would encourage and help in more writing.

History:

First Posted: 15 Aug 2010

Added Section 'Removing ViewState file from server': 17 Aug 2010

Added Section 'Using Hiddden Field': 20 Aug 2010

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here