Monday, 15 December 2014

ASP.NET Tips #3 - Avoid using ViewState

Every time I have to deal with a classic ASP.NET Web Forms application, one of the first things I look at is the resulting source, to check whether the DOM is a complete mess and whether the ViewState is an enormous, unnecessary blob of ugliness. Usually, they indicate what kind of mess will be found further down the stack.

<input id="__VIEWSTATE" name="__VIEWSTATE" type="hidden" value="/wFzY3JpcHQ6IE9uY2xpY2s9J3dpbmRvdy5vcGVuKCJFcXVpcG1lbnQtRGV0YWlscy5hc3B4P1VzZWQtMjAxMC1UZXJl…(
continues for 18,000 characters)…UlVTIiB3aWR0aD=" />

Inadvertently using ViewState when it's not necessary substantially increases the amount of data going back and forth, and can lead to a greater prevalence of invalid ViewState exceptions; the bigger the blob, the more likely it could be interrupted in transmission and not be posted back in entirety in a post.

Unless you're tracking a Text_Changed event, you don't need ViewState enabled on TextBoxes and similar controls. Classic ASP.NET automatically repopulates TextBox.Text values upon postback, even without ViewState enabled. Turn it off on each TextBox with EnableViewState="false" on each one. You can do this for other controls like labels, but unless you're setting their values after the page's load event, you won't reduce the size of the ViewState.

The same goes for most implementations of Repeaters, ListViews, and so on. These are usually the biggest culprits and they can be ugly. The advantage of ViewState with these is avoiding having to populate values again in a postback. If you're convinced that it's worth passing ViewState back and forth again and again to save your app the extra database hit...well...you're probably wrong. Save the database hit (if you need to) with some caching and disable that dang ViewState on that Repeater!

If you're re-binding data anyway, or just toggling one property on postback (asp:Panel anyone?), please turn off that ViewState!

If you do need ViewState, understand the page lifecycle and bind your data appropriately. A control loads its ViewState after Page_Init and before Page_Load, i.e. server controls don't start tracking changes to their ViewState until the end of the initialization stage. Any changes to ViewState mean a bigger ViewState, because you have the before value and the after value. So, if you're changing or setting a control's value, set it before ViewState is being tracked, if possible.

You may think it's impossible to turn off ViewState on a DropDownList, even if you re-bind it on every postback. But with a tiny bit of elbow grease you can keep ViewState enabled and avoid passing all your option values back and forth. This is particularly worthwhile for DropDownLists with a big ListItem collection. One way is to turn off ViewState and bind the select value manually to the actual posted value, like so:

string selectedId = Request[Countries.UniqueID];
if (selectedId != null)
{
   Countries.SelectedValue = selectedId;
}

However, you may prefer something I came across more recently. Instead of bianding your DropDown-List in the typical Page_Load or Page_Init, bind it in the control's Init event:

<asp:dropdownlist id="Countries" oninit="CountryListInit"></asp:dropdownlist>
protected void CountryListInit(object sender, EventArgs e)
{
   Countries.DataSource = // get data from database
   Countries.DataBind();
}

Make it your habit to turn off ViewState on every control by default, and only turn it on when you need it. If a page doesn't need ViewState anywhere, turn it off at the page level. You do all that work to reduce requests, combine and compress static references, and make sure your code is as clean as possible - don't ruin it with a ViewState monster!

Application Level

We can disable ViewState for the pages that do not require access to ViewState data using the EnableViewState statement in the Page directive of a page as shown below:

  
<%@ Page EnableViewState="False" %>

Application Level

View State can also be disabled for all the pages of the application by specifying the same at the application level in the configurations section of the web.config file.

<configuration>
  <system.web>
    <pages enableViewState="False" />
  </system.web>
</configuration>

No comments :

Post a Comment