I had a request from Scott Hanselman (who has been vocal on the subject of ViewState on many occasions) to share my approach to file-based ViewState persistence that I mentioned in my previous post. Feel free to comment on my approach. I need to get code formatting set up. Pasting from Visual Studio is a pain.
Here's my overrides of my base class page's LoadPageStateFromPersistenceMedium and SavePageStateToPersistenceMedium:
protected override object LoadPageStateFromPersistenceMedium() {
return _viewStatePersister.LoadViewState();
}
protected override void SavePageStateToPersistenceMedium(object viewState) {
_viewStatePersister.SaveViewState(viewState);
}
Doesn't tell you much, except I'm delegating persistence to a ViewStatePersister, which looks like (with some things renamed to protect the innocent):
public abstract class ViewStatePersister {
public ViewStatePersister(BasePage page) {
_page = page;
}
protected BasePage Page {
get {return _page;}
}
BasePage _page;
public abstract object LoadViewState();
public abstract void SaveViewState(object viewState);
}
Delegating this responsibility to a separate class gives me finer control over how the persistence happens, as well as modularizing that functionality. Naturally, I have a class that wraps the default ViewState persistence functionality (which is fairly uninteresting), as well as a FileBasedViewStatePersister. It extends the DefaultViewStatePersister and harnesses that existing behavior to store a single Guid in the __VIEWSTATE field used to uniquely identify the request. It's methods of interest look like: (You might look at SaveViewState first so Load makes more sense. I'm not about to screw with the formatting again to re-order them.)
public override object LoadViewState() {
object viewState = base.LoadViewState();
if (viewState != null) {
Guid guid = (Guid)viewState;
LosFormatter formatter = new LosFormatter();
using (FileStream fileStream = new FileStream(CreateOfflineViewStateFilePath(guid), FileMode.Open, FileAccess.Read, FileShare.None)) {
viewState = formatter.Deserialize(fileStream);
}
}
return viewState;
}
public override void SaveViewState(object viewState) {
//create a guid for this viewstate
Guid guid = Guid.NewGuid();
LosFormatter formatter = new LosFormatter();
using (FileStream fileStream = new FileStream(CreateOfflineViewStateFilePath(guid), FileMode.CreateNew, FileAccess.Write, FileShare.None)) {
formatter.Serialize(fileStream, viewState);
}
//trick the regular system into thinking all it needs to save is the guid
base.SaveViewState(guid);
}
The appropriate persister is created with a call to a virtual CreateViewStatePersister() method, which a page can use to create the persister of its choice. As I said in my previous post, I was dissapointed that I had to use the LosFormatter rather than the BinaryFormatter. The downside of this approach is the possibility for creating LOTS of files, as opposed to creating a single file per session. But I already have a file cleaning mechanism in place that cleans up files created by my graphing library, which creates more files.