Today’s installment of nagging you to pay attention where your view state goes is about another ASP.NET 2.0 novelty: the PageStatePersister class.
The Old Suspects
In 1.x, if you wanted to move view state out of your pages and store it, say, in a database, you had to deal with the undocumented LosFromatter class (see my earlier view state article). It was a fudge, but it worked. We’ve used this approach for a couple of years.
New Faces
In 2.0, we have a fully documented PageStatePersister class. “Out of the box,” you use HiddenFieldPageStatePersister to keep view state in a hidden input element, __VIEWSTATE, like in them old days.
Another handy stock persister is SessionPageStatePersister which—you guessed it—persists view state in the session. This persister maintains a Queue of view state entries, 9 being the default (see <sessionPageState>).
The best part is that you can write your own persister. You can either override the Page.PageStatePersister property, or create a very simple adapter and list it in a .browser file for all pages. I prefer the latter option.
No Silver Bullet
I have not yet seen a fully functional sample of a database view state persister.
Simply storing a view state string in a file/session/database doesn’t work. As you go from page A to B and then click the browser Back button, you end up on page A, but you’ll load page B view state because the browser didn’t postback. Needless to say, your code will blow up.
The stock session persister takes it a step further by storing individual view state strings in, well, the session and tracks some other information. This approach doesn’t work either, because it causes trouble when you run frames in pages or pop up dialog windows—they use the same session, therefore they attempt to read view state stored by other pages within the same session.
I think the only viable way is to tie persistence logic to the session id and file name. Ultimately, if you go down the path of using a database for persistence, you need to keep track of the following bits:
- session ID
- timestamp (adjust with every save)
- page file name
By trial and error we’ve figured out that these three guarantee enough uniqueness and will work with pop-ups, frames, and the like.
On the flip side, you have to deal with Session whims such as expiration, app restarts, etc. See my Session Q&A post where I outlined some issues that give me headaches.
You also need a mechanism to clean up view state entries of expired and abandoned sessions. This can be a SQL job or an HttpModule sitting on a timer.