RSS Feed
Download our iPhone app
Browse DevX
Sign up for e-mail newsletters from DevX


Building a PreserveProperty Control in ASP.NET 2.0 : Page 4

Find out how to create a deterministic and declarative property persistence control that works without ViewState and provides transparent access to persisted properties and fields on your ASP.NET controls and pages.

Other Persistence Mechanisms
ControlState works fine and is probably the most reliable way to store the persisted data, but if you're using ASP.NET 1.1 or if you don't like ViewState persistence (even if permanent) you might want to use a different storage mechanism. The PreservePropertyControl supports four persistence modes:

  • ControlState
  • HiddenVariable
  • SessionVariable
  • CachePerPage
All but ControlState require custom hooks into the page pipeline and a little extra work to serialize the data. When I created the original control for this I used my own serialization mechanism which was less efficient and required quite a bit more code. After a few suggestions from my blog someone suggested that I use the LosFormatter. The LosFormatter is a little known string serializer in the System.Web.UI namespace that you can use to serialize objects. The format used by this serializer is lighter-weight than the full binary formatter because it encodes common types more efficiently, often bypassing the expensive full .NET serialization mechanism. Listing 3 shows the relevant code from the control that demonstrates the non-ControlState storage mechanisms.

For all but the ControlState persistence, both OnInit() and OnPreRender() methods are hooked. OnInit() calls LoadStateFromLosStorage() and OnPreRender() calls SaveStateToLosStorage(). These methods delegate the actual Hashtable generation and parsing to SaveControlState() and LoadControlState() shown above. SaveStateToLosStorage() then calls the LosFormatter to create a string representation of this Hashtable. Each of the different storage mechanisms then stores this string in the appropriate storage mechanism.

With HiddenFormVariable the data is stored as follows:

      "__" + this.UniqueID, Serialized);
Then, you read it back using code such as:

   RawBuffer = HttpContext.Current.Request.Form[
      "__" + this.UniqueID];
When the raw buffer is retrieved it's deserialized back into a Hashtable and then passed to LoadControlState(), which reassigns the values to the controls.

Session variable storage is a little different and requires a little explanation. Session storage stores the preserved property state in a Session variable that is reused for all pages. This means every page gets the same Session variable instance and there's one variable per user.

Using Session can be a great boon because if you store the persisted data in the Session object, you're not shipping it over the wire, which means smaller pages. Session storage also tends to be much faster than ViewState encoding of any kind if using InProc storage because no serialization occurs.

You'll want to use caution with this approach! If you open two windows in the same browser session or use Frames pages that have the same Session active simultaneously, you'll run into problems with getting the wrong state restored. In the included demo page you can test this by running the page, setting a color, and submitting then pressing Ctrl-N (or Ctrl-T if you have tabs) to create a new browser window in the same browser session. Open the same page, select a different color, and click Show. Now go back to the first page and click the postback button—you should see the color from the second instance in the first instance, which is clearly incorrect. The first instance picked up the persisted data of the second.

This might not be a problem in some internal applications where there's no reason to run multiple browser windows or frames, but even so, be very careful with this option. You could solve this problem by generating a unique per-page ID for a Session variable, but this would then potentially clutter up Session state with a lot of persisted memory. Session variable storage should be considered only if you work on pages that have a large amount of persisted data and want to avoid sending that data over the wire for each postback.

Similarly, you can use the Cache object. Unlike the Session approach, the Cache approach writes to the session, assigning a new GUID for each page. So every new page for every user creates a new cache entry.

As with Session, be aware of the trade-offs: Using the Cache object you will generate a large number of cache entries, so on a really busy site with many pages, this approach is probably not realistic. Also note that the Cache approach will not work in Web farm environments as Cache doesn't persist across machines.

Both Cache and Session offer lighter-weight pages and better performance for state storage though, so you might want to experiment with the options.

Both ControlState and HiddenFormVariable approaches are stored in the page itself as POST data so they don't suffer from these issues. Out of the two, ControlState is the more reliable solution simply because ControlState has its own events that fire as part of the page pipeline and don't require hooking existing events where timing issues with other controls can potentially occur. I provided a HiddenFormVariable implementation primarily to support ASP.NET 1.x.

Preserve the World
In recent applications I've found a lot of uses for this control where I had previously not even considered state storage. When you can control exactly what gets persisted it's easy to keep persisted state size down and still get a flexible page that provides true property access to the persisted values. I tend to run my pages with ViewState off altogether, so having a control that can persist a few items declaratively can be very helpful. All in all, this control makes life easier in many ways.

The most common scenarios for me are managing List state settings such as SelectedValue properties from list controls, paging, and sorting settings in grids and lists. Storing page-level state like a current record ID also works very well. The beauty is that it becomes much more natural to interact with any preserved properties because you simply reference the properties without any concern for the persistence mechanism—the process is totally transparent once you've added it to the PreservePropertyControl. The control basically lets you turn ASP.NET's promiscuous ViewState policy upside down: Instead of storing everything in ViewState automatically you store only what you explicitly need to store. This can drastically reduce the size required by ViewState in your pages. Check it out and see if you can't trim your page size considerably using this control.

I hope you'll find this control useful and that this article has given you a few insights into the various page-level state persistence mechanisms. Go ahead-do your thing for the environment and preserve… in real life and now in your Web code!

If you have any comments, questions or suggestions regarding this article, you can post them at www.west-wind.com/wwthreads/?default.asp?forum=White+Papers.

Rick Strahl is the big Kahuna and janitor at West Wind Technologies in Maui, Hawaii. When he�s not out playing on waves and water, he likes to write code until the cows come home. Rick specializes in web and distributed applications with .NET and provides training and mentoring to clients and customers. He's also a C# MVP and ASP Insider, a frequent contributor to magazines and books, a frequent speaker at international developer conferences, and the co-publisher of CoDe Magazine. For more information please visit his Web site at www.west-wind.com.
Email AuthorEmail Author
Close Icon
Thanks for your registration, follow us on our social networks to keep up-to-date