Store View State in a Persistent Medium, the Proper Way
page 4 of 6
by Bilal Haidar
Feedback
Average Rating: This article has not yet been rated.
Views (Total / Last 10 Days): 66981/ 740

Implementing Scott’s proposed solutions

In this section we will implement Scott’s recommendations for a better solution for storing the view state in a persistent medium.

The property that was used in the above referenced article to generate the file name is shown in Listing 1 below.

Listing 1

/// <summary>
/// The path for this user's/page's view state information.
/// </summary>
public string ViewStateFilePath
{
  get
  {
    string folderName = Path.Combine(Request.PhysicalApplicationPath,
      "PersistedViewState");
    string fileName = Session.SessionID + "-" +
     Path.GetFileNameWithoutExtension(Request.Path).Replace("/""-"+ ".vs";
 
    return Path.Combine(folderName, fileName);
  }
}

The enhancements on the above property are shown in Listing 2.

Listing 2

/// <summary>
/// The path for this user's/page's view stateinformation.
/// </summary>
public string ViewStateFilePath
{
  get
  {
    string folderName = Path.Combine(Request.PhysicalApplicationPath,
      "PersistedViewState");
    string _FileName = VsKey + "-" + Path.GetFileNameWithoutExtension
      (Request.Path).Replace("/""-"+ ".vs";
 
    return Path.Combine(folderName, fileName);
 
  }
}

You can notice that we have replaced the Session.SessionID with the VsKey.  VsKey is nothing but a public property that is used to retrieve the GUID created and stored in a hidden field in the page.

The hidden field is added to the page as follows.

Listing 3

<asp:HiddenField ID="vsKey"runat="server" />

The VsKey property is shown in Listing 4.

Listing 4

/// <summary>
/// Stores the HiddenField key representing the GUID-FileName of the ViewState of the current page
/// </summary>
public string VsKey
{
  get
  {
    HiddenField _VsHiddenKey = null;
    string _VsKey = "";
 
// Get the HiddenField Key from the page
    _VsHiddenKey = FindControlRecursive(this"vsKey")as HiddenField;
 
// Get the HiddenField value from the page
    string _VsHiddenKeyValue = GetControlValue(_VsHiddenKey.UniqueID.ToString());
    if (_VsHiddenKeyValue != null)
    {
      _VsKey = _VsHiddenKeyValue;
    }
 
// First time access, generate a key for the ViewState file
    if (!Page.IsPostBack)
    {
      _VsKey = GenerateGUID();
      _VsHiddenKey.Value = _VsKey;
    }
 
// Return the VS key
    return _VsKey;
  }
}

The first time this property is accessed, a new GUID is created and assigned to the value property of the Hidden field and then used to construct the file name to hold the view state of the current page being executed.

On a post back, the GUID will be retrieved from the hidden field on the page and will be used to construct the file where the view state is stored.  Then a simple access to read the text file is done and the page’s view state is there!

The first improvement as Scott specified is accomplished.

Now we need a mechanism to help us clean up the file system from the view state files that are no longer needed.

I decided to add a key to the AppSettings section in the web.config as follows:

Listing 5

<!-- specifies the days before which we shoulddelete the ViewState -->
<add key="vsDays"value="1"/>

The algorithm works as follows.  Inside the LoadPageStateFromPersistentMedium() method implementation given by Scot, I will add a call to a new method called CleanupFiles().  This method is shown in Listing 6.

Listing 6

/// <summary>
/// Clean up files to gain some space
/// </summary>
private void CleanupFiles()
{
  try
  {
// Create a reference to the folder holding all viewstate files
    string _FolderName = Path.Combine(WebUtils.PhysicalAppPath,
      "PersistedViewState");
 
// Create a reference to the VS directory
    DirectoryInfo _Directory = new DirectoryInfo(_FolderName);
 
// Create an array representing the files in the current directory.
    FileInfo[]_Files = _Directory.GetFiles();
 
// Delete all files whose CreationTime is > Xdays.
// By default its 7 days, 1 week.
    DateTime _Threshold = DateTime.Now.AddDays( - 7);
 
    if (WebConfigurationManager.AppSettings["vsDays"] != null)
    {
      if(WebConfigurationManager.AppSettings["vsDays"].ToString() != "")
      {
        int _vsDays = Convert.ToInt32(WebConfigurationManager.AppSettings[
          "vsDays"].ToString()) * ( - 1);
        _Threshold = DateTime.Now.AddDays(_vsDays);
      }
    }
 
    foreach (FileInfo _File in _Files)
    {
      if (_File.CreationTime <= _Threshold)
        _File.Delete();
    }
  }
  catch (Exception ex)
  {
    throw new ApplicationException("CleanupFiles in BasePage");
  }
}

This method will read the vsKey in the web.config.  The vsKey represents the number of days that will be subtracted from today’s date, thus forming a DateTime threshold.  Each view state file’s creation date will be compared to that threshold; any file whose creation date is less than or equal to that threshold will be deleted.  This way we will be freeing up some memory space to hold new view state files.

You can check the updated LoadPageStateFromPersistentMedium() method in which we specify a call to the method responsible for cleaning up the files from the file system.

Listing 7

/// <summary>
/// Loads the page's view state from the Webserver's file system.
/// </summary>
protected override object LoadPageStateFromPersistenceMedium()
{
// determine the file to access
  if (!File.Exists(ViewStateFilePath))
    return null;
  else
  {
// Remove all files that have been there for X days!
    CleanupFiles();
 
// open the file
    StreamReader _StreamReader = File.OpenText(ViewStateFilePath);
    string viewStateString = _StreamReader.ReadToEnd();
    _StreamReader.Close();
 
// deserialize the string
    LosFormatter _LostFormatter = new LosFormatter();
 
    return _LostFormatter.Deserialize(viewStateString);
  }
}

As a result, we have implemented two improvements Scott mentioned in his article to make the solution he proposed to store the view state into a persistent medium- a better and robust solution. The improvements are:

·         Use a GUID value to construct the view state file name per page.

·         A Hidden field is used to keep track of each page’s GUID.

A simple technique is added to clean up unused view state files to save memory disk space.


View Entire Article

User Comments

Title: Great Article   
Name: Clever Name
Date: 3/30/2012 12:33:16 PM
Comment:
I used your method and it worked great. About a month later someone told me about Page Adapters. Instead of using the default HiddenFieldPageStatePersister you can use a SessionPageStatePersister or develop your own Persister.
While the way listed in the article works using this way probably is better.

http://msdn.microsoft.com/en-us/library/system.web.ui.sessionpagestatepersister.aspx
Title: Cleanup Viewstate Files on Session End   
Name: Mariner
Date: 10/14/2010 12:14:38 PM
Comment:
I like the cleanup file method that you are doing, however, I am not looking for a cleanup method that deletes the files based on a timestamp, but rather on a session end.
The reason for this is there are thousands of users accessing the site daily and there will be many viewstate files as a result. It is time and memory consuming to keep the files around based on DateTime methods.

Thank you very much for your time.

Mariner
Title: HiddenField not populated on postback   
Name: M
Date: 10/5/2010 11:20:57 AM
Comment:
Hi I am trying to implement your idea in my project. However I have a problem whereby the HiddenField (vsKey) loses its value (the key GUID) when the page is posted back. Because of this the LoadPageStateFromPersistenceMedium function fails as it is returned a blank value from the vsKey HiddenField. Any ideas on this?

Your time is much appreciated. M.
Title: Re: Rudolf   
Name: Bilal Haidar
Date: 6/11/2008 3:15:17 PM
Comment:
Hi Rudolf,
I am glad you liked my article!

Check the following links for compressing VS:
1. http://www.techtoolblog.com/archives/compressing-aspnet-20-viewstate

2. http://www.hanselman.com/blog/ZippingCompressingViewStateInASPNET.aspx

3. http://www.dotnetcurry.com/ShowArticle.aspx?ID=67&AspxAutoDetectCookieSupport=1


Hope they help!
Regards
Title: Viewstate with compresseion   
Name: Rudolf terppe
Date: 6/11/2008 2:59:47 PM
Comment:
Hi Bilal

A perfect articel
I installedand works well.
Do you have an Idea to include compression of Viewstate?

Rudolf terppe from Germany
Title: * shudder *   
Name: foobar
Date: 7/29/2006 11:17:25 PM
Comment:
There are far better ways to do this.

Go here: http://msdn2.microsoft.com/en-us/library/system.web.ui.pagestatepersister.aspx
Title: Checking for the deletion of files on every postback is bad   
Name: Shoaib
Date: 7/29/2006 10:31:46 AM
Comment:
I completely agree with Kevin.

Looping through the files for deletion on every postback is bad idea. I suggest you to create a separate service for that purpose and if you have any problem working with the services, then u should use some folder hierarchy to store files like:

Year/Month/Day

so that u can delete all the folders except the one created today.
Title: Feedback on Above article   
Name: Kishore
Date: 7/22/2006 8:14:20 AM
Comment:
The technique used in above article is very good but clean up files procedure is calling whenever request comes from client. I think to suggest/adopt other way around.
Title: Re:   
Name: Bilal Haidar
Date: 7/19/2006 10:04:14 AM
Comment:
Keven : Marco:
Looks you two new ways which are nice too, in addition to this one.
Why don't I have a look at them both? bilal@bhaidar.net

Thanks.
Title: Don't rely on session or page to clean up files   
Name: Kevin
Date: 7/19/2006 10:00:35 AM
Comment:
I think it's a very bad idea to have the page look for files to clean up and then cross its fingers and start deleting.

I also think that relying on session events at all for this is a bad idea since part of the value of ViewState is not having to rely on session at all.

Instead, you should use an HTTPModule with a Threading Timer to look for files to delete every now and again. This way, you get great reliability and you don't loop through every freakin' persisted viewstate file on every page postback.
Title: Performance Improvement   
Name: Marco Dissel
Date: 7/19/2006 9:58:22 AM
Comment:
i've created i slightly different implementation:

- create GUID and store it in hidden field
- add viewstate to Cache with timespan of x minutes (no LosFormatter)
- setup delegate to cache deletion of the Cache item
- in delegate store viewstate from cache in file

on retrieval first check if viewstate still in Cache, if so return the viewstate and clear the cache for that item. If not fount load the viewstate form the file and delete the file..

Cleanup process can be done with some timer in another (new) thread..

What do you think of my approach?
Title: Atlas Ajax   
Name: dadvav
Date: 7/19/2006 2:53:53 AM
Comment:
Hi, I have problem with with Atlas toolkit. I think better solution to save Viewstate ID is to use original hidden field and not own vsKey
Title: Re:   
Name: Bilal Haidar
Date: 7/6/2006 12:33:07 PM
Comment:
I had several incidents where the Session_End was not fired on my machine, maybe because of VS or so, have no idea.

Thanks
Title: SessionEnd not fired   
Name: Alain
Date: 7/6/2006 10:58:19 AM
Comment:
The sessionEnd event is only fired if the sessions are managed "in process" (InProc param), but not if the sessions are manages out of process (ASP.NET State Service or SQL database)
Title: Re:   
Name: Bilal Haidar
Date: 6/29/2006 6:04:06 AM
Comment:
Hello:
I do use sometimes that method of having the CleanupFiles in the SessionEnd(). But sometimes it doesn't work!! Something goes wrong and the session end doesn't get fired!
That is why, to be on the safe side, I decided to place it there!

Thanks.
Title: Performance improvment   
Name: Pravin Singh
Date: 6/29/2006 5:52:39 AM
Comment:
I think it is better to move the function CleanupFiles() from LoadPageStateFromPersistenceMedium() to Session_End(). In Session_End() we can find all the files with file names having the Session ID assigned to the user whose session just ended and delete them all. Because right now CleanUp() function gets called on page load of all the web forms.
Title: New Approach in ASP .NET 2.0   
Name: Juan
Date: 6/27/2006 10:30:49 AM
Comment:
Check out a new article on MSDN at http://msdn.microsoft.com/msdnmag/issues/06/07/WebAppFollies/default.aspx#S4

.NET 2.0 offers an out-of-the-box way to save viewstate to session, then you could persist it in a database or in session server if you want to or just use the inproc session provider. Either way it manages the viewstate on the server for you.

Product Spotlight
Product Spotlight 





Community Advice: ASP | SQL | XML | Regular Expressions | Windows


©Copyright 1998-2014 ASPAlliance.com  |  Page Processed at 10/31/2014 12:01:49 AM  AspAlliance Recent Articles RSS Feed
About ASPAlliance | Newsgroups | Advertise | Authors | Email Lists | Feedback | Link To Us | Privacy | Search