AspAlliance.com LogoASPAlliance: Articles, reviews, and samples for .NET Developers
URL:
http://aspalliance.com/articleViewer.aspx?aId=911&pId=-1
Store View State in a Persistent Medium, the Proper Way
page
by Bilal Haidar
Feedback
Average Rating: This article has not yet been rated.
Views (Total / Last 10 Days): 47829/ 60

Introduction

In his article, Understanding ASP.NET View State, Scott presented a section about storing the ASP.NET view state into a persistent medium, instead of storing it in the page itself.  He used the system file system, mainly a simple text file to store the page’s view state.  However, Scott did mention a few weaknesses in his approach and proposed some ideas on how to improve his method.

The following is quoted from Scott Mitchell’s article.

"There are two main challenges with this approach:

1.      Coming up with an acceptable file naming scheme.  Since the view state for a page will likely vary based on the user's interactions with the page, the stored view state must be unique for each user and for each page.

2.      Removing the view state files from the file system when they are no longer needed."

To tackle the first challenge, we will name the persisted view state file based on the user's SessionID and the page's URL.  This approach will work beautifully for all users whose browsers accept session-level cookies.  Those that do not accept cookies, however, will have a unique session ID generated for them on each page visit, thereby making this naming technique unworkable for them.  For this article I am just going to demonstrate using the SessionID / URL file name scheme, although it will not work for those whose browsers are configured not to accept cookies.  Also, it will not work for a Web farm unless all servers store the view state files to a centralized location.

Note: One workaround would be to use a globally unique identifier (GUID) as the file name for the persisted view state, saving this GUID in a hidden form field on the ASP.NET Web page.  This approach, unfortunately, would take quite a bit more effort than using the SessionID / URL scheme, since it involves injecting a hidden form field into the Web Form.  For that reason, I will stick to illustrating the simpler approach for this article.

The second challenge arises because each time a user visits a different page, a new file holding that page's view state will be created.  Over time this will lead to thousands of files.  Some sort of automated task would be needed to periodically clean out the view state files older than a certain date.  I leave this as an exercise for the reader.

In this article we are going to improve the method presented by Scott.  The improvement will include the following two sections.

First, we will use a GUID to name the text file used to store the view state.  This GUID will be generated per page and stored in a hidden field inside the page.

Second, we will be adding a semi-scheduler for deleting the view state files based on a certain threshold that we can control by having a key inside the Web.config.

What Scott did?

In his article, Scott based his solution on overriding two main methods to be able to store the view state into a persistent medium.

·         SavePageStateToPersistentMedium()

·         LoadPageStateFromPersistenceMedium()

The former is used to serialize the view state of the page to a hidden form field during the save view state stage.  The later is used to de-sterilize the view state from the hidden form field during the load view state stage.

Therefore, the above two methods were overridden in a sense to serialize the view state, not to store it in a hidden form field, but instead store it in the system’s file system.  In the load view state stage, instead of reading the view state from the hidden field, view state was read from the same text file that it was written to.  Then it is de-serialized.

Scott used a simple technique to name the view state file that was used to store the view state. He based his solution on the Session ID and the page’s name.  This way, in the same session there will be only one file used to store/load the view state of a specific page.

Problems with Scott’s method

Scott did mention in his article some drawbacks for his method.  Mainly, he pointed to the fact of using the Session ID to determine the file name used to store the view state.  This solution will work fine in browsers that do accept session-level cookies.  However, it will fail in browsers that do not support cookies because on each visit to the page a new Session ID is generated for them and this technique will break down.

However, he did mention a solution to this problem.  The solution would consist of generating a GUID for each page and using the GUID together with the page name as the file name used to store the view state.  Then to make sure the same GUID is used for the same page, we need to store the GUID in a hidden field inside the page.

Another challenge Scott mentioned was removing the view state files from the file system when they are no more used.  He left this challenge for the readers to figure out.

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.

Downloads
Conclusion

We have presented Scott Mitchell’s solution that he used to store the page’s view state into a persistent medium.  We pointed out two weaknesses that Scott himself did mention in his article at MSDN and implemented a solution to those problems according to the recommendations given by Scott.

Hope you enjoyed this article.

Happy Dot Netting!!


Product Spotlight
Product Spotlight 

©Copyright 1998-2024 ASPAlliance.com  |  Page Processed at 2024-04-27 9:37:47 AM  AspAlliance Recent Articles RSS Feed
About ASPAlliance | Newsgroups | Advertise | Authors | Email Lists | Feedback | Link To Us | Privacy | Search