Click here to Skip to main content
15,860,859 members
Articles / Web Development / ASP.NET
Article

Keep ASP.NET ViewState out of ASPX Page for Performance Improvement

Rate me:
Please Sign up or sign in to vote.
4.37/5 (46 votes)
23 Jul 2005GPL34 min read 298.7K   1.1K   108   58
How you could improve performance of your ASP.NET projects, keeping ViewState on the server instead of on the ASPX page.

Sample Image - ServerViewState.gif

Introduction

ASP.NET ViewState is a great mechanism that simplifies the life of ASP.NET developers. But, as everybody knows, the .NET Framework saves the ViewState data as a hidden field on your ASPX page. If your page has only a few controls, this is not a problem. But, if your page has some Panels and/or some DataGrids, with the technique demonstrated on this article, you could reduce dramatically the load time of the page.

We will start our analysis thinking where the Framework needs to work with the data saved on the ViewState hidden field. The answer is: only on the server side. The system doesn't need to work with the ViewState data on the client side, so, if we start to save this data on the server instead of carrying all this from the server to the client and from the client to the server again, we will save a lot of time while loading our documents. You probably won't note the difference while loading the page on the same computer that the application is installed, but, test it using a dial-up connection and you will see what happens. You cold also see the the size of the source code generated with and without this technique.

This example consist of a class that inherits the System.Web.UI.Page, and overrides the methods SavePageStateToPersistenceMedium and LoadPageStateFromPersistenceMedium. These methods are responsible for saving and loading the ViewState used by the controls on a page. What we do is intercept the call to these methods and, using some simple custom config keys on the Web.Config, set how this class should work. It can save the ViewState on the server using two destinations: Session and Cache, and, has the ability to work as the original class, saving the ViewState data to the ASPX page.

If you already have a project and want to start using this technique, all that you need to do is add a reference to the class that accompanies this example and inherit your "code-behind files" from it instead of the System.Web.UI.Page, and add the Config information to your Web.Config.

To develop this technique, I read a lot of articles over the internet, but, one really "opened my mind" of how this implementation could be done and the benefits of it. See more information on the Points of Interest Section.

I included a demo project that you could download and use to test the implementation. Note that the demo project saves the ViewState to the session, which I think is the best place to store it.

Using the code

As I said, the implementation is very easy. So, let's start with my Class code, and after discussing it, let's see the configuration of the Web.Config file.

VB
'KEEPING THE VIEWSTATE OUT OF THE ASPX PAGE
'Autor.: Régis Daniel de Oliveira
'E-Mail: regisxp@hotmail.com
'Date..: 07/2005

'Reserach Source:
'http://www.eggheadcafe.com/articles/20040613.asp

Imports System.Configuration.ConfigurationSettings
Imports System.Diagnostics

Public Class VSPage
    Inherits System.Web.UI.Page

Now, let's see the method responsible for saving the ViewState data, called SavePageStateToPersistenceMedium. All that this method does is see if the ServerSideViewState on our Web.Config file is enabled (True). If no, the system will perform a normal ViewState save, storing it on the ASPX document. If yes, the system will check which is the ServerSideViewState method that you want to use: CACHE or SESSION. If you choose CACHE, the data will be stored on the cache and will expire after some time. If you choose SESSION, the data will be saved on the user session and will be discarded when the user session expires. When this option is used, the system automatically creates a DataTable that will be saved on the session and will hold all the ViewState data. The maximum number of ViewState data that could be held on the DataTable is defined by the Web.Config parameter ViewStateTableSize. The default value, 150, represents that the ViewState data of the last 150 postbacks will be available to the system. So, if the user clicks on the navigator's Back button 150 times (what is improbable to occur), the ViewState for that page will already be present to be used. This is a very good number...

VB
Protected Overrides Sub _
           SavePageStateToPersistenceMedium(ByVal viewState As Object)

    Dim VSKey As String
    'String that will hold the Unique Key
    'used to reference this ViewState data

    Debug.WriteLine(MyBase.Session.SessionID)

    'Create the key based on the SessionID, on the Request.RawUrl
    'and on the Ticks representated by the exact time
    'while the page is being saved
    VSKey = "VIEWSTATE_" & MyBase.Session.SessionID & "_" & _
            Request.RawUrl & "_" & Date.Now.Ticks.ToString

    'Check if the ServerSideViewState is Activated
    If UCase(AppSettings("ServerSideViewState")) = "TRUE" Then

        'Check were we will save the ViewState Data
        If UCase(AppSettings("ViewStateStore")) = "CACHE" Then

            'Store the ViewState on Cache
                Cache.Add(VSKey, viewState, Nothing, _
                    Date.Now.AddMinutes(Session.Timeout), _
                    Cache.NoSlidingExpiration, _
                    Web.Caching.CacheItemPriority.Default, Nothing)

        'The ViewStateData will be Saved on the SESSION
        Else

            Dim VsDataTable As DataTable
            Dim DbRow As DataRow

            'Check if the ViewState DataTable are on the Session
            If IsNothing(Session("__VSDataTable")) Then

                'No, it's not. Create it...
                Dim PkColumn(1), DbColumn As DataColumn
                VsDataTable = New DataTable("VState")
                'Create the DataTable

                'Column 1 - Name: VSKey - PrimaryKey
                DbColumn = New DataColumn("VSKey", GetType(String))
                VsDataTable.Columns.Add(DbColumn)
                PkColumn(0) = DbColumn
                VsDataTable.PrimaryKey = PkColumn

                'Column 2 - Name: ViewStateData
                DbColumn = New DataColumn("VSData", GetType(Object))
                VsDataTable.Columns.Add(DbColumn)

                'Column 3 - Name: DateTime
                DbColumn = New DataColumn("DateTime", GetType(Date))
                VsDataTable.Columns.Add(DbColumn)

            Else
                'The ViewState DataTable is already on the UserSession
                VsDataTable = Session("__VSDataTable")

            End If

            'Check if we already have a ViewState saved with the same key.
            'If yes, update it instead of creating a new row.
            '(This is very dificult to happen)
            DbRow = VsDataTable.Rows.Find(VSKey)

            If Not IsNothing(DbRow) Then
                'Row found!!! Update instead of creating a new one...
                DbRow("VsData") = viewState
            Else
                'Create a new row...
                DbRow = VsDataTable.NewRow
                DbRow("VSKey") = VSKey
                DbRow("VsData") = viewState
                DbRow("DateTime") = Date.Now
                VsDataTable.Rows.Add(DbRow)
            End If

            'Check if our DataTable is OverSized...
            If Convert.ToInt16(AppSettings("ViewStateTableSize"))_
                                  < VsDataTable.Rows.Count Then
                Debug.WriteLine("Deleting ViewState Created On " _
                       & DbRow(2) & ",ID " & DbRow(0))
                VsDataTable.Rows(0).Delete() 'Delete the 1st line.
            End If

            'Store the DataTable on the Session.
            Session("__VSDataTable") = VsDataTable

        End If

    'Register a HiddenField on the Page,
    'that contains ONLY the UniqueKey generated.
    'With this, we'll be able to find with ViewState
    'is from this page, by retrieving these value.
    RegisterHiddenField("__VIEWSTATE_KEY", VSKey)

    Else

    'Call the normal process.
    MyBase.SavePageStateToPersistenceMedium(viewState)

    End If

End Sub

And now, let's see the method responsible to load the ViewStateData, LoadPageStateFromPersistenceMedium:

VB
    Protected Overrides Function LoadPageStateFromPersistenceMedium() As Object

        'Verifica se o ServerSideViewState está ativado
        If UCase(AppSettings("ServerSideViewState")) = "TRUE" Then

            Dim VSKey As String 'ViewState UniqueKey
            VSKey = Request.Form("__VIEWSTATE_KEY")
            'Request the Key from the page and validade it.

                If Not VSKey.StartsWith("VIEWSTATE_") Then
                    Throw New Exception("Invalid VIEWSTATE Key: " & VSKey)
                End If

            'Verify which <SPAN id=BABID_Results7>modality was used to save ViewState
            If UCase(AppSettings("ViewStateStore")) = "CACHE" Then
                Return Cache(VSKey)

            Else

                Dim VsDataTable As DataTable
                Dim DbRow As DataRow
                VsDataTable = Session("__VSDataTable")
                DbRow = VsDataTable.Rows.Find(VSKey)

                    If IsNothing(DbRow) Then
                        Throw New Exception("VIEWStateKey not Found. " & _ 
                              "Consider increasing the ViewStateTableSize" & _ 
                              " parameter on Web.Config file.")
                    End If

                    Return DbRow("VsData")

            End If

        Else

            'Return the ViewState using the Norma Method
            Return MyBase.LoadPageStateFromPersistenceMedium()

        End If

    End Function

End Class

And now, this is what we need to insert on our config file Web.Config:

XML
<!-- application specific settings -->
<appSettings>

    <!--ServerSideViewState: Defines if ViewState
             will be saved on the Server: True|False-->
    <add key="ServerSideViewState" value="True"/>

    <!--ViewStateStore: Defines where we'll save the ViewState: Cache|Session-->
    <add key="ViewStateStore" value="Session" />

    <!--ViewStateCacheFSSize: Define the maximum Number
       of viewStates will be saved when ViewStateStore = Session -->
    <add key="ViewStateTableSize" value="150" />

</appSettings>

Points of Interest

A lot of research was done to implement the login presented on this article. One of the most interesting sources is this. If you would like to know more about these techniques and see the result of some stress tests, follow the link.

Conclusion

ViewState really simplifies the development of ASP.NET applications, but due to increase in the page load time, some developers don't like to use it. With this technique, you could have all the advantages of using ViewState on your projects without worry about the size of the generated page source code.

License

This article, along with any associated source code and files, is licensed under The GNU General Public License (GPLv3)


Written By
Web Developer
Brazil Brazil
Régis Daniel is currently living in Itaúna, MG, Brazil. He works with programming since 1999 and actualy works as IT Manager on a wholesaler company. He has experiency as Oracle DBA, and also worked as a PalmOS developer using CodeWarrior with C/C++.
Now a days he works on .NET Framework, developing solutions on Visual Basic.NET and ASP.NET. During his spare time, he likes reading books, watching movies and pratices some outdoor activities, like Trekking and Camping.

Comments and Discussions

 
GeneralRe: Nonsense!!! Pin
scotteg27-Jul-05 1:57
scotteg27-Jul-05 1:57 
GeneralRe: Nonsense!!! Pin
GustavoAyala27-Jul-05 2:09
GustavoAyala27-Jul-05 2:09 
GeneralRe: Nonsense!!! Pin
Régis Daniel de Oliveira27-Jul-05 15:05
Régis Daniel de Oliveira27-Jul-05 15:05 
GeneralRe: Nonsense!!! Pin
GustavoAyala28-Jul-05 1:16
GustavoAyala28-Jul-05 1:16 
GeneralIt works for me Pin
Member 118129426-Jul-05 5:09
Member 118129426-Jul-05 5:09 
GeneralRe: It works for me Pin
Régis Daniel de Oliveira26-Jul-05 14:36
Régis Daniel de Oliveira26-Jul-05 14:36 
GeneralRe: It works for me Pin
Member 118129426-Jul-05 23:00
Member 118129426-Jul-05 23:00 
GeneralRe: It works for me Pin
Régis Daniel de Oliveira27-Jul-05 14:49
Régis Daniel de Oliveira27-Jul-05 14:49 
Ok mccannj!!!
I agree with you that we could improve this solution as you said, and using this method to store all ViewState information.

I´ll work on something like you said!!!

Thanks so much for your feedback!!!

Régis Daniel de Oliveira

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.