ViewState is not always your enemy

I had to support a legacy Web Forms application and while in the process of cleaning up several existing UserControls I had to explain to another developer exactly why using the ViewState to store custom properties wasn't worse than the current solution - which was, on every page load, setting a large number of properties that weren't persisted beyond that page view.

For example, we had a property on the UserControl that wouldn't persist the value between postbacks:

public string EmptyMessage { get; set; }

This value was being set in the parent's Page_Load event on every page load. To change this so that it would persist the value, I could replace the property declaration with:

public string EmptyMessage
{
    get { return (string)ViewState["EmptyMessage"]; }
    set { ViewState["EmptyMessage"] = value; }
}

In explaining this change, I had to summarise why this wasn't a terrible idea. I'll admit that I had spent a long time thinking that the ViewState was a monstrous blob of encoded text that did nothing but bulk up my web pages unnecessarily, and for a long time wrote code so that every page essentially had EnableViewState="false". ViewState isn't the right answer for absolutely everything, but it is definitely useful in some circumstances.

My key points were:

  • If it makes sense to persist a value, then persist it. If saving a property lets you save time or effort, then just persist it. This can help make your code more declarative, so your parent control "tells" this control how to behave once and this control can "remember" to behave a certain way, display a certain message, etc.
  • Work out if the ViewState is the right place to persist this information. This is a much bigger question, but the ViewState generally isn't the right place to store large blobs of data. Small strings and other simple values, sure.
  • Setting a ViewState-backed property at design time won't make your ViewState huge, because these values aren't actually be stored in the ViewState. If you declare an initial value, for example <project:MyControl runat="server" EmptyMessage="There's nothing here!" /> - this default value won't be saved in to the ViewState because it's being set before TrackViewState() is called. The value will actually just be re-applied to your object on each subsequent page load, and then be overwritten later in the page lifecycle if you've actually changed it.
  • Don't try to save things to the ViewState in Init. Similar to the point above, changes you make at this point in the page lifecycle aren't tracked yet, so you'd have to re-apply them on each page request.

I remember that when I started to understand how the ViewState behaves over the page life cycle it was an "a-ha!" moment where the ViewState became something that made sense, rather than being a strange black box that just "somehow" sometimes remembered things.