Tuesday, April 14, 2009

New way to Store view state at Persistent Medium in .NET

Sometimes, it becomes necessity to store the view state at server side. It can be stored in session or at file IO. Most of us are aware of how to store the view state at server. If not aware of the traditional way of storing the view state at server then check it out.

I am going to explain another way, which I think is a great example of having object orientation.

.NET Provides us a class named PageStatePersister. Inheriting which we are going to create another class. I named it FilePageStatePersister.
The class will look like below.

public class FilePageStatePersister : PageStatePersister
{
#region Variables
/// <summary>
/// Holds the unique id for each of the view states.
/// </summary>
string _id = "";
/// <summary>
/// The folder path from where to read and write the view state files.
/// </summary>
string _viewStateFolderPath;
#endregion
#region Ctors
/// <summary>
/// Constructor for creating the object.
/// </summary>
/// <param name="page">reference of the page
/// <param name="id">unique id
public FilePageStatePersister(Page page, string id)
: base(page)
{
_id = id;
_viewStateFolderPath =page.Server.MapPath(Constants.VIEWSTATEPATH);

}
#endregion
#region Overrided Methods
/// <summary>
/// Load the view state from file system.
/// </summary>
public override void Load()
{
string viewStateData = GetViewState();
this.ViewState = this.StateFormatter.Deserialize(viewStateData);
}
/// <summary>
/// Save the view state to file system.
/// </summary>
public override void Save()
{
string viewStateData = this.StateFormatter.Serialize(this.ViewState);
StoreViewState(viewStateData);
}
#endregion
#region Class Methods
/// <summary>
/// Actually store the data to the file system.
/// </summary>
/// <param name="data">
private void StoreViewState(string data)
{
StreamWriter writer = null;
try
{
if (!Directory.Exists(_viewStateFolderPath))
{
Directory.CreateDirectory(_viewStateFolderPath);
}
writer = new StreamWriter(_viewStateFolderPath + _id);
writer.Write(data);
}
finally
{
writer.Close();
}
}
/// <summary>
/// Actually reads the data from the file system.
/// </summary>
/// <returns></returns>
private string GetViewState()
{
string data = "";

StreamReader reader = null;

try
{
reader = new StreamReader(_viewStateFolderPath + _id);
data = reader.ReadToEnd();
}
finally
{
reader.Close();
}

return data;
}
#endregion
}

We need to override Save and Load methods of the class.

Simple till now.

The class is ready to be used.
Now, the remaining portion is how to use it.
I have created a PageBase class, which inherits System.Web.UI.Page class. All the asp .net pages inherits from my PageBase class instead of inheriting from System.Web.UI.Page class.

We just need to override one of the properties available with System.Web.UI.Page.
The code will look like this.

/// <summary>
/// Get the Persiter object for storing view state.
/// If <see cref="DoSaveStateToPersistenceMedium"> is set to true then it will use
/// instance of <see cref="FilePageStatePersister"> class other wise it will use
/// default PageStatePersister.
/// </see>
protected override PageStatePersister PageStatePersister
{
get
{
if (DoSaveStateToPersistenceMedium)
{
if (_pageStatePersister == null)
{
string guid = "";

if (Request[Constants.VIEWSTATEKEY] == null)
{
guid = Guid.NewGuid().ToString();
}
else
{
guid = Request[Constants.VIEWSTATEKEY].ToString();
}

_pageStatePersister = new FilePageStatePersister(this, guid);

Literal literal = new Literal();
literal.Text = "<div><input type=\"hidden\" name=\"" + Constants.VIEWSTATEKEY + "\" value=\"" + guid + "\" /></div>";
this.Form.Controls.Add(literal);
}
}
else
{
_pageStatePersister = base.PageStatePersister;
}
return _pageStatePersister;
}
}


As I have developed a PageBase and some of the pages of the project may require the viewstate to be stored at server, I have added a property which will notify whether the viewstate will be stored at server side or it will be stored at client(which is default). This provides us the flexibility to change the behavior of the view state storing whenever required.