Utpal Chakraborty

Subscribe to Utpal Chakraborty: eMailAlertsEmail Alerts
Get Utpal Chakraborty: homepageHomepage mobileMobile rssRSS facebookFacebook twitterTwitter linkedinLinkedIn


Article

Streamline Performance

Streamline Performance

Like many features available in Microsoft's products, page ViewState in ASP.NET works behind the scenes by default. However, unlike most other features, ViewState can impact the pages we develop dramatically. The impact may not only be in page size but also in server-side performance. Pages with large ViewState can throw unexpected errors. Developers must understand what factors affect page ViewState and the strategies to follow to gain maximum benefit from this feature. Since there is no one strategy for all scenarios, we will review two different scenarios.

First, you must understand the benefits of ViewState.The Web is a stateless scenario. In the ASP world, developers often use hidden form fields to store values to persist information across postbacks. Automatic state management is a feature that enables server controls to repopulate their values on a round-trip without requiring you to write any code. However, this feature is not without cost, because the state of a control is passed to and from the server in a hidden form field. Each control defines what it needs to store in its ViewState. They are stored as key-value pairs, using the System.Web.UI.StateBag object. On page postback this data is sent back to the server and ASP.NET uses it to construct the state of the controls on the page during page initialization. To better appreciate the amount of data stored in the ViewState we'll look at two examples.

Examples of Pages with ViewState
First we take an empty page with the following source:



Viewstatetest - Empty<br> page


runat=server>

If you save it as an .aspx file, open it in a browser, and look at the page source you will see the code shown in Listing 1. (All of the code for this article can be downloaded from www.sys-con.com/dotnet/sourcec.cfm.) There is already some ViewState data because some of the ViewState data is actually ViewState metadata that always exists. This metadata tells ASP.NET how the ViewState data will be applied to create the state of the different page controls.

Now, let's consider a page that has a control. The simple page shown in Listing 2 uses a DataGrid with all default settings to display just five rows from a table. On saving this .aspx page and opening it up in a browser we can take a look at the page source, which is shown in Listing 3.

That is about 4K of ViewState for just five rows. In a typical scenario in which there will be more controls on a page (and probably a higher number of result rows), the ViewState can be really large. It is thus imperative that we gain some understanding of how to control the size of the ViewState.

Controlling ViewState
ViewState can be controlled at four levels ­ the machine level, the application level, the page level, and the control level. Each level inherits the setting of the level above by default. For ViewState to be enabled, all four levels must enable ViewState. By default it is enabled at each level. If ViewState is disabled at the application level (this is done in the web.config file) it overrides any page-level setting. Similarly, if ViewState is disabled at the page level, then it overrides the setting of any control within the page. A child cannot override the ViewState setting of the parent. For example, if a page-level ViewState setting is set to false, controls within the page cannot store ViewState information.

Only controls contained within a

tag in the .aspx page can store ViewState. A form field is required so that the hidden field that contains the ViewState information can post back to the server. It must be a server-side form so the ASP.NET page framework can add the hidden field when the page is executed on the server.

The page saves about 20 bytes of information into ViewState. This is used to distribute postback data and ViewState values to the correct controls on postback. So even if ViewState is disabled for the page or application, you may see a few remaining bytes in ViewState. In cases where the page does not need to post back at all, ViewState can be eliminated from the page by omitting the server-side tag.

Remember that ViewState for each control on each page is enabled by default. Since many server controls defined on a page contribute to ViewState size, ViewState, if unchecked, will grow really large and impact performance.

We need to understand how the various server controls affect ViewState. While it's not possible to delve into the details of each of the server controls, for our purposes they can be classified into two groups.

The first group, the light control group (see Figure 1), consists of the controls that have little or no effect on the ViewState of a page. So for all practical purposes the enableviewstate setting of these controls can be ignored. The validation controls also fall in this group. Most of these (notably TextBox and CheckBox) retain their states regardless of their ViewState settings. Thus, their ViewState can be turned off globally. One easy way of doing this is to create a custom control that inherits from TextBox, for example, and sets the ViewState property to false in its constructor, as shown below. This control can be used in place of the TextBox control throughout. It is necessary to disable the ViewState in the constructor (and nowhere else), since that way it can always be overridden for the page by using the enableviewstate attribute. This is a good strategy to follow in nearly every scenario.

using System;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.ComponentModel;

namespace ViewState.Controls
{
public class MyTextBox : System.Web.UI.WebControls.TextBox
{
public MyTextBox()
{
base.EnableViewState = false;
}
}
}

The second group, the heavy control group (see Figure 2), consists of all the list and grid controls. Typically, these store their entire contents in the ViewState. Thus, all our efforts henceforth should concentrate on how best to manage the ViewState of these controls.

Scenario 1: Network Bandwidth Is the Constraint
This is the typical scenario of a Web site on the Internet, e.g., an e-commerce site. While it is easy to add more hardware to alleviate performance issues, little can be done about network bandwidth on the client side. Generally, pages should be made as light as possible. A highly interactive page with server-side controls belonging to the heavy control group will add a lot of ViewState data, increasing the size of the page. This ViewState not only must be downloaded by the client but also uploaded during postback. Thus, a 1KB increase in ViewState increases the traffic by 2KB. Therefore, our strategy's main aim should be to minimize ViewState data.

The DataGrid control is a particularly heavy ViewState user. By default, all of the data displayed in the grid is also stored in ViewState, which is particularly useful when an expensive operation (like a complex SQL query) is required to fetch the data. However, this behavior also makes DataGrid the prime suspect for unnecessary ViewState. If sorting and paging is being used, then a rebind of the DataGrid to its dataview class is necessary on every postback, and the entire ViewState of the DataGrid is unnecessary. Even when sorting and paging is not being used, the grid should be rebound on every postback. If this rebinding requires a complex query, then it is worthwhile to investigate whether the query can be broken into expensive and less expensive operations. If so, only the results of the expensive operations need be stored in the ViewState and reused on every postback to rebind the grid.

Sometimes data can be added to the ViewState judiciously for overall benefit. The most striking example is provided by Web farms. Typically in these scenarios the session state is persisted in an external database, since a session may jump between servers during its lifetime. In this case, the session data is fetched from the database, deserialized, and made available to the page. Any changes to the session data that follow are serialized and persisted to the database. Although ASP.NET's session persistence makes it easy to implement this, it is an expensive process. If this data is stored in ViewState instead, then the round-trip access to the database can be completely eliminated. While adding data to the ViewState, keep in mind that ViewState is optimized to work with the following:

  • Int, boolean, string, and other primitive types both boxed and unboxed versions
  • Arrays of primitive types
  • ArrayList and Hashtable
  • Any type that is marked with the serializable attribute, or that supports the serializable interface

    These should allow the ability to store most data structures into ViewState. Again, there is a critical point at which the amount of data involved makes it more efficient to store it in the database. This depends on the individual characteristics of the application setup and can only be found empirically.

    Two caveats should be kept in mind when persisting data in ViewState. First, ViewState data is easy to decode (since it is basically base64 coding). Thus, any sensitive information should not be stored in ViewState and sent over an insecure link. Sensitive information can be stored in the ViewState if it is encrypted and hashed, as described later. Second, sessions, unlike ViewState, time out after a predetermined time. If timeout functionality is required, then sessions must be used instead of ViewState to store data.

    Scenario 2: Processing Power Is the Constraint
    This is the usual scenario of a local intranet site running over a corporate LAN. The available bandwidth is usually many times greater than that available over the Internet, so the constraint usually lies in server-side processing power. Typically there is less hardware available for running an intranet, as compared to an external-facing Internet site. Intranet applications also tend to be more interactive, having quick, frequent postbacks between pages, owing to the speed of the network the nature of the application.

    In such a scenario, application design should favor putting as much reusable data into the ViewState as possible, minimizing database access. This is done by checking the Page.IsPostback property in the Page_Load event of the page. Data is loaded from the database only for the initial load. All subsequent requests are served using the stored ViewState.

    This strategy results in making the application servers, rather than the database server, the critical resource. This is favorable since we can get an almost linear increase in performance by adding more application servers until the database becomes the critical resource. Thus, ViewStates of all the controls in the heavy control group ­ which require database access to build themselves ­ should be enabled. In this way, they need to be built only once for every page and built from the ViewState on postbacks. An exception, as always, is DataGrid, with sorting and paging allowed on it. It needs to be rebound on every postback and enableviewstate should be set to false.

    There is a directive, EnableViewStateMac, that can be set to either true or false at the page level or in web.config. When true, a hash code is appended to the ViewState during page rendering. On postback the hash code is calculated again and checked against the stored value. The page is rejected if they are not the same. This ensures that the ViewState has not been tampered with during the round-trip from the client to the server. While this feature has its uses over an insecure Internet connection, it requires extra CPU resources on the server. On an intranet, where there is less chance of the ViewState being tampered with, EnableViewStateMac can be set to false in web.config to increase performance.

    Checking ViewState Size
    After we implement our strategy we need to check the results. Each .aspx page developed should be tested for ViewState size before being released to production. Server-side tracing of ASP.NET pages does not allow us to see the size of the total ViewState of each page. It displays only individual ViewState sizes of the controls. Does this mean we have to laboriously open every page in the browser and see the source of the ViewState to compare sizes? Fortunately, there is a better way of doing things.

    We can create a base page class that every other .aspx page in our application inherits (see Listing 4). This class can override the OnPreRender event of the page class to trace the ViewState. This trace can then be used to see the size of the ViewState. To test this class we can modify the DataGrid page we used earlier. The only changes are in the page attribute at the top and adding a button to do the postback (see Listing 5).

    We have to set the web.config to enable trace and to show the trace in the page output. After this is done, on postback we see a lot of trace output. Just after the ³request details² section we see the ViewState size information. The relevant portion of the trace is shown in Table 1.

    Conclusion
    The ViewState of a page is affected most by the controls belonging to the heavy control group. The amounts of ViewState data being stored by these controls should be carefully monitored to see whether they are within acceptable limits for the particular application. Special care should be given to the DataGrid control. In some situations, data can be added to the ViewState instead of the session to reduce database access and increase performance.

  • More Stories By Utpal Chakraborty

    Utpal Chakraborty is a Microsoft Certified Professional. He has extensive experience in design and implementation of n-tier applications and is currently leading many .NET implementations. Before his current experience with .NET he has has man years developing in Java and C++.

    Comments (3) View Comments

    Share your thoughts on this story.

    Add your comment
    You must be signed in to add a comment. Sign-in | Register

    In accordance with our Comment Policy, we encourage comments that are on topic, relevant and to-the-point. We will remove comments that include profanity, personal attacks, racial slurs, threats of violence, or other inappropriate material that violates our Terms and Conditions, and will block users who make repeated violations. We ask all readers to expect diversity of opinion and to treat one another with dignity and respect.


    Most Recent Comments
    Dick Haynes 08/10/04 05:41:24 PM EDT

    Great Article Thanks

    Haresh 06/21/04 03:40:58 AM EDT

    Right,

    But we face problem when we want to do some postback like sorting and paging ( which is essential part of grid).
    Server side events do not fire if we disable view state,

    any solution for that...!!!

    Vinay Sharma 03/25/04 05:55:44 AM EST

    Informative Article