In a previous post, I eluded to the fact that I remove the ViewState from our ASP.NET pages to improve performance. I can’t take credit for coming up with the idea though. Originally, I got the idea and solution I wanted to implement by reading this article at EggHead Cafe. The solution I chose was to store the ViewState on the web server’s file system and reference the file in the page sent back to the client. I’ll outline how I did that below.
The first thing you’ll want to do is create a new Page base class that inherits from System.Web.UI.Page so you can override some of its methods, namely SavePageStateToPersistenceMedium and LoadPageStateFromPersistenceMedium. This will allow you to save the page’s ViewState to the file system and then re-load it on a post back. Let’s start with saving the ViewState to the file system.
protected override void protectedSavePageStateToPersistenceMedium(object viewState) { // Serialize the view state into a base-64 encoded string LosFormatter los = new LosFormatter(); StringWriter writer = new StringWriter(); los.Serialize(writer, viewState); string guid = NewGuid(); string vsp = ViewStateFilePath(guid); // Save the string to disk StreamWriter sw = File.CreateText(vsp); sw.Write(writer.ToString()); sw.Close(); // Save the guid in a form field ClientScript.RegisterHiddenField("__VIEWSTATE_GUID", guid); }
So, let’s step through what we’re doing here. The first few lines of code, we’re serializing the view state. Next, where we call
string uid = NewGuid();
We’re creating a new guid that we will use in creating the file name on the server for the actual value of the current view state. NewGuid() just returns a new guid value from the System.Guid class.
Next, we need to create a path to where we’re going to store the file as well as its file name. Now, you can do this any way you want as long as all of your files end up being unique. You can’t go overwriting one guy’s view state with someone else’s. Now I based mine on basically the guid appended with the current request path minus the extension and replacing the slashes with dashes. So, my filename looks like:
string fileName = guid + "-" + Path.GetFileNameWithoutExtension(Request.Path).Replace( "/", "-") + ".vs";
Where the guid was passed in to the function that I called to create the view state file path.
So now that we have a path to where we can write the file, we can go ahead and do so using the StreamWriter that we created. Now, the last thing to do is spit out where we can find the view state to the client. This is done by registering a hidden field with the client:
ClientScript.RegisterHiddenField("__VIEWSTATE_GUID", guid);
That GUID allows you to recall the proper file for the client when you need to access the ViewState.
So now you’ve persisted the view state to the file system. Now all that’s left is to load it up when needed, which is done with LoadPageStateFromPersistenceMedium(), which is below.
protected override object LoadPageStateFromPersistenceMedium() { string guid = Request.Form["__VIEWSTATE_GUID"]; if (guid == "") return null; // determine the file to access if (!File.Exists(ViewStateFilePath(guid))) { return null; } else { // open the file StreamReader sr = File.OpenText(ViewStateFilePath(guid)); string viewStateString = sr.ReadToEnd(); sr.Close(); // deserialize the string LosFormatter los = new LosFormatter(); return los.Deserialize(viewStateString); } }
This approach gives you the ability to minimize the amount of data that you have to send over the wire to a client browser. There are other solutions to this like storing the ViewState in memory, but I felt that it was a waste of resources if a ViewState might only be used once and then abandoned. The one thing you’ll want to do is manage your saved ViewState files on your disk. These files can get out of control, especially when you get a lot of visitor’s. So what I did was just set up a Scheduled Task in Windows to clean up stored ViewState’s every three hours. This works out pretty good since a ViewState really won’t be needed beyond that timeframe.
Anyway, I hope this solution helps some other C# ASP.NET developers out there. It sure worked out great for me!