Recipe 19.2. Reducing Page Size by Selectively Disabling the ViewState


Problem

You want to reduce the size of your application pages to improve performance.

Solution

Review each page of your application and each of its controls to determine if the ViewState is required. Disable the ViewState where it is not explicitly needed.

In the code for the page, use the .NET language of your choice to do either of the following:

  • Disable the ViewState for the page by setting the EnableViewState attribute in the @ Page directive to False. (Alternatively, set Page.EnableViewState to False in the code-behind.)

  • Disable the ViewState for individual controls on the page by setting the control's EnableViewState attribute to False. (Alternatively, set the control's EnableViewState property to False in the code-behind.)

To illustrate these performance improvements, we took two examples from Chapter 2 and optimized them by disabling the ViewState. In the first example, we took the ASP. NET page created for Recipe 2.22, which displays a grid containing books and price data, and disabled the ViewState at the page level. Table 19-1 shows the page and ViewState size before and after the optimization.

Table 19-1. ViewState performance improvement for Recipe 2.22 example
 

Before optimization

After optimization

Page size

9,947 bytes

6,766 bytes

ViewState size

3,362 bytes

162 bytes


In the second example, we have used the ASP.NET page created in Recipe 2.10 and disabled the ViewState for the row controls within the DataGrid that appears within the page body. Example 19-1 shows the .aspx file for this application. The code-behind class for the application is shown in Example 19-2 (VB) and Example 19-3 (C#). Table 19-2 shows the page and ViewState sizes before and after optimization.

Table 19-2. ViewState performance improvement for Recipe 2.10 example
 

Before optimization

After optimization

Page size

9,448 bytes

6,378 bytes

ViewState size

3,734 bytes

670 bytes


Discussion

The ViewState is used to keep track of the state of each control on a page and to rehydrate the control upon postback to the server. Because of its ability to maintain state when a page is posted back to the server, the use of the ViewState reduces the amount of code you would have to write. Thanks to the ViewState, you no longer need to extract values from the posted form for processing or reset the control values when you display the page again, as is the case with classic ASP. The controls are accessed as they were when the page was initially generated.

Though use of the ViewState significantly reduces your coding and maintenance efforts, it comes at a cost. All of the data required to keep track of the control's state is stored in a hidden input control in the HTML page as shown next. Depending on the number and types of controls you use on your pages, the ViewState can get large, resulting in a decrease in performance. Because the ViewState data is sent to the browser when the page is rendered and returned to the server as part of the postback, a performance hit occurs when the page is first displayed and when the page is posted back to the server. Performance is degraded not so much by the generation of the ViewState data when the page is first rendered, but rather by the transfer of the extra ViewState data to and from the browser on postbacks, as well as by the processing of the data by the browser. Here is a typical ViewState input control:

 <input type="hidden" name="_ _VIEWSTATE"    value="dDwtOTQzNjg3NDE1O3Q8O2w8aTwxPjs"/> 

While "byte counters" will be quick to disable the ViewState completely because of its inevitable negative impact on performance, a compromise is available that provides the best of both worlds: selectively disable ViewState because it is not needed for all pages or controls. By reviewing each of the pages in your application, you can improve the application's performance without losing the benefits of the ViewState.

The first step when reviewing a page is to determine if the page does a postback to itself. If not, then the ViewState can be disabled for the entire page. This is done by setting the EnableViewState attribute in the @ Page directive to false:

 <%@ Page Language="VB" MasterPageFile="~/ASPNetCookbookVB.master"  AutoEventWireup="false"  CodeFile="CH19ViewStatePerformanceVB1.aspx.vb"  Inherits="ASPNetCookbook.VBExamples.CH19ViewStatePerformanceVB1"  Title="ViewState Performance"  EnableViewState="false" %> 

Alternately, you can place this line of code in the Page_Load method to disable the ViewState for the entire page:

 

Page.EnableViewState = False

Page.EnableViewState = False;

Even with the ViewState disabled for a page, a few bytes will remain in the value setting of the hidden input control. If you are determined to remove all traces of the ViewState, you must remove the form element or remove the runat="server" attribute from the form element. Either action can cause maintenance issues later, and the resulting savings of fewer than 50 bytes in a 20KB page has no measurable performance impact, so we do not recommend this remedy.

If the page does a postback to itself, you will need to review each of the controls on the page. For each control, you need to determine if any state information is required by the control upon postback. If no state information is required, the ViewState for the control can be disabled.

The example page created in Recipe 2.22 displays a grid containing books and price data. The page has no "action" controls; therefore, this page has no mechanism to postback to itself and is a good candidate for disabling the ViewState at the page level, a conclusion presented in the results shown in Table 19-1. After this optimization, the page size is 68% of the original size and the ViewState represents less than 2.4% of the optimized page.

The example page created in Recipe 2.10 is a good candidate for performance improvement. This page is similar to the page created in Recipe 2.22 but has three "action" controls used to sort the data in the grid. Clicking on the column headers in the grid causes the page to be posted back to itself with the data sorted by the column clicked; therefore, this page cannot have the ViewState disabled at the page level.

Because the ViewState cannot be disabled at the page level, we need to review each control to determine if the ViewState is needed. The page contains two controls, a content control and a DataGrid control. The content control contains no "action" controls and no programmatically set content; therefore, the ViewState for the content control can be disabled using the code shown here:

 <asp:Content  Runat="server" ContentPlaceHolder enableviewstate="false"> 

While you might be tempted to disable the ViewState for the DataGrid, because all of the data is regenerated on each postback, you cannot. ASP.NET needs the ViewState information for the controls within the header of the DataGrid to process its click events and to execute the dgBooks_SortCommand method. If you disable the ViewState for the DataGrid, the postback will occur but none of the event handlers will be called.

A DataGrid is a container of controls. At its highest level, a DataGrid consists of a header control and one or more row controls. In this example, only the header contains "action" controls and because the data in each row are regenerated with each postback, the ViewState for the row controls can be disabled using the code shown here:

 

For Each item In dgBooks.Items item.EnableViewState = False Next

foreach (DataGridItem item in dgBooks.Items) { item.EnableViewState = false; }

Code that programmatically disables the ViewState of individual controls, must be executed every time the page is rendered. In addition, the disabling of controls within a DataGrid must be performed after data binding.


The results in Table 19-2 confirm the advantage of this optimization. By disabling the ViewState for the content control and for each row in the DataGrid, we have reduced the size of the ViewState and the overall page size as well. After optimization, the page size is 68% of the original size and the ViewState represents less than 11% of the optimized page.

ASP.NET 2.0 has removed the information needed for control postback from the ViewState; the postback information is now contained within the ControlState. This separation of control functionality from data provides more flexibility in disabling the ViewState to reduce the size of pages. The ControlState is implemented in most ASP.NET server controls. The DataGrid is one of the server controls that does not use the ControlState.

If a GridView had been used in this example instead, such as the one shown in Recipe 2.14, the ViewState for the entire GridView could have been disabled without affecting the functionality of the page.


See Also

Recipes 2.10, 2.14, and 2.22

Example 19-1. Modified .aspx file from Recipe 2.10

 <%@ Page Language="VB" MasterPageFile="~/ASPNetCookbookVB.master" AutoEventWireup="false" CodeFile="CH19ViewStatePerformanceVB2.aspx.vb" Inherits="ASPNetCookbook.VBExamples.CH19ViewStatePerformanceVB2" Title="View State Performance" %> <asp:Content  Runat="server" ContentPlaceHolder enableviewstate="false"> <div align="center" > Improving ViewState Performance of Recipe 2-10 (VB) </div> <asp:DataGrid  runat="server" BorderColor="#000080" BorderWidth="2px" HorizontalAlign="Center" AutoGenerateColumns="False" Width="90%" AllowSorting="True" OnSortCommand="dgBooks_SortCommand" > <HeaderStyle HorizontalAlign="Center" Css /> <ItemStyle css /> <AlternatingItemStyle css /> <Columns> <asp:BoundColumn DataField="Title" SortExpression="Title" /> <asp:BoundColumn DataField="ISBN" ItemStyle-HorizontalAlign="Center" SortExpression="ISBN" /> <asp:BoundColumn DataField="Publisher" ItemStyle-HorizontalAlign="Center" SortExpression="Publisher" /> </Columns> </asp:DataGrid> </asp:Content> 

Example 19-2. Optimized code-behind for Recipe 2.10 (.vb)

 Option Explicit On Option Strict On Imports System.Configuration Imports System.Data Imports System.Data.OleDb Namespace ASPNetCookbook.VBExamples   ''' <summary>   ''' This class provides the code-behind for   ''' CH19ViewStatePerformanceVB2.aspx   ''' </summary>   Partial Class CH19ViewStatePerformanceVB2 Inherits System.Web.UI.Page 'the following enumeration is used to define the sort orders Private Enum enuSortOrder   soAscending = 0   soDescending = 1 End Enum 'strings to use for the sort expressions and column title 'separate arrays are used to support the sort expression and titles 'being different Private ReadOnly sortExpression() As String = {"Title", "ISBN", "Publisher"} Private ReadOnly columnTitle() As String = {"Title", "ISBN", "Publisher"} 'the names of the variables placed in the viewstate Private Const VS_CURRENT_SORT_EXPRESSION As String = "currentSortExpression" Private Const VS_CURRENT_SORT_ORDER As String = "currentSortOrder" '''*********************************************************************** ''' <summary> ''' This routine provides the event handler for the page load event. It ''' is responsible for initializing the controls on the page. ''' </summary> ''' ''' <param name="sender">Set to the sender of the event</param> ''' <param name="e">Set to the event arguments</param> Private Sub Page_Load(ByVal sender As Object, _   ByVal e As System.EventArgs) Handles Me.Load       Dim defaultSortExpression As String   Dim defaultSortOrder As enuSortOrder   If (Not Page.IsPostBack) Then 'sort by title, ascending as the default defaultSortExpression = sortExpression(0) defaultSortOrder = enuSortOrder.soAscending 'store current sort expression and order in the viewstate then 'bind data to the DataGrid ViewState(VS_CURRENT_SORT_EXPRESSION) = defaultSortExpression ViewState(VS_CURRENT_SORT_ORDER) = defaultSortOrder bindData(defaultSortExpression, _      defaultSortOrder) End If 'disable the ViewState for controls that do not need it disableViewState() End Sub 'Page_Load '''*********************************************************************** ''' <summary> ''' This routine provides the event handler for the datagrid sort event. ''' It is responsible rebinding the data to the datagrid by the selected ''' column. ''' </summary> ''' ''' <param name="source">Set to the source of the event</param> ''' <param name="e">Set to the event arguments</param> Protected Sub dgBooks_SortCommand(ByVal source As Object, _      ByVal e As DataGridSortCommandEventArgs)       Dim newSortExpression As String   Dim currentSortExpression As String   Dim currentSortOrder As enuSortOrder       'get the current sort expression and order from the viewstate   currentSortExpression = CStr(ViewState(VS_CURRENT_SORT_EXPRESSION))   currentSortOrder = CType(ViewState(VS_CURRENT_SORT_ORDER), enuSortOrder)   'check to see if this is a new column or the sort order   'of the current column needs to be changed.   newSortExpression = e.SortExpression   If (newSortExpression = currentSortExpression) Then 'sort column is the same so change the sort order If (currentSortOrder = enuSortOrder.soAscending) Then   currentSortOrder = enuSortOrder.soDescending    Else   currentSortOrder = enuSortOrder.soAscending End If       Else 'sort column is different so set the new column with ascending 'sort order currentSortExpression = newSortExpression currentSortOrder = enuSortOrder.soAscending   End If   'update the view state with the new sort information   ViewState(VS_CURRENT_SORT_EXPRESSION) = currentSortExpression   ViewState(VS_CURRENT_SORT_ORDER) = currentSortOrder   'rebind the data in the datagrid   bindData(currentSortExpression, _        currentSortOrder) End Sub 'dgBooks_SortCommand '''*********************************************************************** ''' <summary> ''' This routine queries the database for the data to displayed and binds ''' it to the datagrid ''' </summary> ''' ''' <param name="sortExpression">Set to the sort expression to use for ''' sorting the data</param> ''' <param name="sortOrder">Set to the requried sort order</param> Private Sub bindData(ByVal sortExpression As String, _    ByVal sortOrder As enuSortOrder)     Dim dbConn As OleDbConnection = Nothing   Dim da As OleDbDataAdapter = Nothing   Dim dTable As DataTable = Nothing   Dim strConnection As String   Dim strSQL As String   Dim index As Integer   Dim col As DataGridColumn = Nothing   Dim colImage As String   Dim strSortOrder As String   Try 'get the connection string from web.config and open a connection 'to the database strConnection = ConfigurationManager. _ ConnectionStrings("dbConnectionString").ConnectionString dbConn = New OleDbConnection(strConnection) dbConn.Open( ) 'build the query string and get the data from the database If (sortOrder = enuSortOrder.soAscending) Then   strSortOrder = " ASC" Else   strSortOrder = " DESC" End If strSQL = "SELECT Title, ISBN, Publisher " & _    "FROM Book " & _  "ORDER BY " & sortExpression & _  strSortOrder         da = New OleDbDataAdapter(strSQL, dbConn) dTable = New DataTable da.Fill(dTable) 'loop through the columns in the datagrid updating the heading to 'mark which column is the sort column and the sort order For index = 0 To dgBooks.Columns.Count - 1   col = dgBooks.Columns(index)   'check to see if this is the sort column   If (col.SortExpression = sortExpression) Then 'this is the sort column so determine whether the ascending or 'descending image needs to be included If (sortOrder = enuSortOrder.soAscending) Then   colImage = " <img src='/books/1/505/1/html/2/images/sort_ascending.gif' border='0'>" Else   colImage = " <img src='/books/1/505/1/html/2/images/sort_descending.gif' border='0'>"             End If       Else 'This is not the sort column so include no image html colImage = ""   End If 'If (col.SortExpression = sortExpression)   'set the title for the column   col.HeaderText = columnTitle(index) & colImage     Next index 'set the source of the data for the datagrid control and bind it dgBooks.DataSource = dTable dgBooks.DataBind()   Finally 'cleanup If (Not IsNothing(dbConn)) Then   dbConn.Close() End If   End Try End Sub 'bindData '''*********************************************************************** ''' <summary> ''' This routine disables the ViewState for all controls on the page ''' that do not need to use it. ''' </summary>   Private Sub disableViewState()   Dim item As DataGridItem   'disable the ViewState for each row in the DataGrid   For Each item In dgBooks.Items item.EnableViewState = False   Next item End Sub 'disableViewState   End Class 'CH19ViewStatePerformanceVB2 End Namespace 

Example 19-3. Optimized code-behind for Recipe 2.10 (.cs)

 using System; using System.Configuration; using System.Data; using System.Data.Common; using System.Data.OleDb; using System.Web.UI.HtmlControls; using System.Web.UI.WebControls; namespace ASPNetCookbook.CSExamples {   /// <summary>   /// This class provides the code-behind for   /// CH19ViewStatePerformanceCS2.aspx   /// </summary>   public partial class CH19ViewStatePerformanceCS2 : System.Web.UI.Page   { // the following enumeration is used to define the sort orders private enum enuSortOrder { soAscending = 0, soDescending = 1     } // strings to use for the sort expressions and column title // separate arrays are used to support the sort expression and titles // being different static readonly String[] sortExpression = new String[] { "Title", "ISBN", "Publisher" }; static readonly String[] columnTitle = new String[] { "Title", "ISBN", "Publisher" };     // the names of the variables placed in the viewstate static readonly String VS_CURRENT_SORT_EXPRESSION = "currentSortExpression";; static readonly String VS_CURRENT_SORT_ORDER = "currentSortOrder"; ///*********************************************************************** /// <summary> /// This routine provides the event handler for the page load event. It /// is responsible for initializing the controls on the page. /// </summary> /// /// <param name="sender">Set to the sender of the event</param> /// <param name="e">Set to the event arguments</param> private void Page_Load(object sender, System.EventArgs e) {   String defaultSortExpression;   enuSortOrder defaultSortOrder;      if (!Page.IsPostBack)   {     // sort by title, ascending as the default defaultSortExpression = sortExpression[0]; defaultSortOrder = enuSortOrder.soAscending; // bind data to the DataGrid this.ViewState.Add(VS_CURRENT_SORT_EXPRESSION, defaultSortExpression); this.ViewState.Add(VS_CURRENT_SORT_ORDER, defaultSortOrder); bindData(defaultSortExpression,      defaultSortOrder);   }   // disable the ViewState for controls that do not need it   disableViewState(); }  // Page_Load ///*********************************************************************** /// <summary> /// This routine provides the event handler for the datagrid sort event. /// It is responsible rebinding the data to the datagrid by the selected /// column. /// </summary> /// /// <param name="source">Set to the source of the event</param> /// <param name="e">Set to the event arguments</param> protected void dgBooks_SortCommand(Object source, System.Web.UI.WebControls.DataGridSortCommandEventArgs e) {   String newSortExpression = null;   String currentSortExpression = null;   enuSortOrder currentSortOrder;   // get the current sort expression and order from the viewstate   currentSortExpression = (String)(this.ViewState[VS_CURRENT_SORT_EXPRESSION]);   currentSortOrder = (enuSortOrder)(this.ViewState[VS_CURRENT_SORT_ORDER]);   // check to see if this is a new column or the sort order   // of the current column needs to be changed.   newSortExpression = e.SortExpression;   if (newSortExpression == currentSortExpression)   {     // sort column is the same so change the sort order if (currentSortOrder == enuSortOrder.soAscending) {   currentSortOrder = enuSortOrder.soDescending; } else {   currentSortOrder = enuSortOrder.soAscending; }   }   else   {     // sort column is different so set the new column with ascending     // sort order     currentSortExpression = newSortExpression;     currentSortOrder = enuSortOrder.soAscending;   }   // update the view state with the new sort information   this.ViewState.Add(VS_CURRENT_SORT_EXPRESSION, currentSortExpression);   this.ViewState.Add(VS_CURRENT_SORT_ORDER, currentSortOrder);   // rebind the data in the datagrid   bindData(currentSortExpression,    currentSortOrder);  } // dgBooks_SortCommand ///*********************************************************************** /// <summary> /// This routine provides the event handler for the page index changed /// event of the datagrid. It is responsible for setting the page index /// from the passed arguments and rebinding the data. /// </summary> /// /// <param name="source">Set to the sender of the event</param> /// <param name="e">Set to the event arguments</param> protected void dgBooks_PageIndexChanged(Object source,  System.Web.UI.WebControls.DataGridPageChangedEventArgs e) {   String currentSortExpression;   enuSortOrder currentSortOrder;   // set new page index and rebind the data   dgBooks.CurrentPageIndex = e.NewPageIndex;   // get the current sort expression and order from the viewstate   currentSortExpression = (String)(this.ViewState[VS_CURRENT_SORT_EXPRESSION]);   currentSortOrder = (enuSortOrder)(this.ViewState[VS_CURRENT_SORT_ORDER]);   // rebind the data in the datagrid   bindData(currentSortExpression,    currentSortOrder); } // dgCustomers_PageIndexChanged ///*********************************************************************** /// <summary> /// This routine queries the database for the data to displayed and binds /// it to the datagrid /// </summary> /// /// <param name="sortExpression">Set to the sort expression to use for /// sorting the data</param> /// <param name="sortOrder">Set to the requried sort order</param> private void bindData(String sortExpression,   enuSortOrder sortOrder)   {   OleDbConnection dbConn = null;   OleDbDataAdapter da = null;   DataTable dTable = null;   String strConnection = null;   String strSQL = null;   int index = 0;   DataGridColumn col = null;   String colImage = null;   String strSortOrder = null; try {   // get the connection string from web.config and open a connection   // to the database   strConnection = ConfigurationManager.       ConnectionStrings["dbConnectionString"].ConnectionString;   dbConn = new OleDbConnection(strConnection);       dbConn.Open();      // build the query string and get the data from the database  if (sortOrder == enuSortOrder.soAscending)      {    strSortOrder = " ASC";    }  else      {    strSortOrder = " DESC";     }  strSQL = "SELECT Title, ISBN, Publisher " +   "FROM Book " +   "ORDER BY " + sortExpression +   strSortOrder;  da = new OleDbDataAdapter(strSQL, dbConn);  dTable = new DataTable();  da.Fill(dTable);  // loop through the columns in the datagrid updating the heading to  // mark which column is the sort column and the sort order  for (index = 0; index < dgBooks.Columns.Count; index++)  {    col = dgBooks.Columns[index];    // check to see if this is the sort column    if (col.SortExpression == sortExpression)    {  // this is the sort column so determine whether the ascending or  // descending image needs to be included  if (sortOrder == enuSortOrder.soAscending)  {    colImage = " <img src='/books/1/505/1/html/2/images/sort_ascending.gif' border='0'>";  }  else  {    colImage = " <img src='/books/1/505/1/html/2/images/sort_descending.gif' border='0'>";  }    }    else    {         // This is not the sort column so include no image html  colImage = "";     } // if (col.SortExpression == sortExpression) // set the title for the column col.HeaderText = columnTitle[index] + colImage;    }  // for index    // set the source of the data for the datagrid control and bind it    dgBooks.DataSource = dTable;    dgBooks.DataBind();   } // try       finally    { //clean up if (dbConn != null) {   dbConn.Close(); }    } // finally   } // bindData   ///***********************************************************************   /// <summary>   /// This routine disables the ViewState for all controls on the page   /// that do not need to use it.   /// </summary>   private void disableViewState()   { // disable the ViewState for each row in the DataGrid foreach (DataGridItem item in dgBooks.Items) {   item.EnableViewState = false; }   } // disableViewState } // CH19ViewStatePerformanceCS2 }



ASP. NET Cookbook
ASP.Net 2.0 Cookbook (Cookbooks (OReilly))
ISBN: 0596100647
EAN: 2147483647
Year: 2003
Pages: 202

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net