ASP.NET Simplifies State Management in Web Applications

ne of ASP.NET’s main improvements over classic ASP is its improved options for state management. Die-hard ASP classic developers moving to ASP.NET are often surprised by the dramatic change in programming paradigm. The powerful state management techniques in ASP.NET make Web development much more like traditional Windows desktop programming. This article shows you how to use the various techniques for managing state in ASP.NET and the pitfalls of each method.

Managing State the ASP.NET Way
The simple application shown in Figure 1 illustrates how ASP.NET manages state:

Figure 1: The application retains the text in the label between postbacks to the server.

The dropdown list and the button shown in Figure 1 are part of an HTML form. When the user clicks the Submit button, the browser posts the form back to the server. Forms in ASP.NET (aspx) pages post back to the originating page by default. The server-side code takes the item the user selected and uses it to create the text of a Label control on the Web page that shows the item selected. ASP.NET’s automatic state management preserves the text in the Label control between postbacks as well as the user’s selection in the Listbox. You don’t have to write any extra code to make the items retain state between postbacks.

In contrast, using classic ASP, even a simple application such as this requires several lines of additional codes to ensure that the Listbox item remains selected and to preserve the text in the Label control. You have to write the additional code because HTTP is a stateless protocol. The Web server treats each request as a new connection; the server “forgets” about all requests immediately after processing them. In other words, in classic ASP, unless you write the state management code yourself, after each postback the user’s Listbox selection will be lost (reset to the first item).

In ASP.NET, the list box is a Web server control. Web server controls can automatically maintain their state and you can manipulate them on the server programmatically. That change has far-reaching ramifications for how you should think about state management in ASP.NET. To have a better understanding of how ASP.NET manages the state for you, take a look at the source for the page shown in Figure 1.

      

The preceding code shows a part of the HTML generated by ASP.NET. The HTML contains a hidden field called Viewstate that holds a string of characters. That string stores the state of the various controls on a Web Form. When the server processes a Web Form, it hashes and stores the state of the controls in that form in the Viewstate hidden field before it sends the page to the browser for display. When the browser posts the form back to the server, ASP.NET reads the values stored in Viewstate to restore the state of the controls. It is important to understand that Viewstate maintains information that would not normally be posted back to the server. For example, in the sample application, the HTML form would automatically post the item selected by the user back to the server, but would not post back the text in the Label control. So there’s no point in Viewstate storing the item selected, because it can restore the selected item from the information posted by the form. Hence Viewstate stores the text in the Label control but not the item selected.

You can examine what the form sends to the server by using the GET method instead of the POST method. Simply change the method property of the form from post to get. Now when the form is submitted, you can examine the URL to see the form data sent back to the server:

      http://localhost/StateManagement/WebForm1.aspx?   __VIEWSTATE=dDwxNTgwOTQ2NjA3Ozs%2B&lstLanguages=   VB.NET&cmdSubmit=Submit

Click on the Submit button a few times and note how the length of the Viewstate parameter value increases!

Examining Viewstate
If you look at the Viewstate hidden field, it looks like the information has been encrypted; but it isn’t. Viewstate is simply a string in Base64 encoding. To see what the Viewstate string contains, you need to decode it:

   dDwxNTgwOTQ2NjA3O3Q8O2w8aTwxPjs+O2w8dDw7bDxpPDM+Oz47bD   x0PHA8cDxsPFRleHQ7PjtsPFlvdSBoYXZlIGNob3NlbiBDIywgVkIu   TkVUOz4+Oz47Oz47Pj47Pj47Pg==

I have modified a simple routine (from MSDN help) to convert the Base64 encoding into a string value and write it into a text file as shown in the following code snippet.

   Dim str As String =       "dDwxNTgwOTQ2NjA3O3Q8O2w8aTwxPjs+O2" &       _"w8dDw7bDxpPDM+Oz47bDx0PHA8cDxsPFRleHQ7" & _      "PjtsPFlvdSBoYXZlIGNob3NlbiBDIywgVkIuTk" & _      "VUOz4+Oz47Oz47Pj47Pj47Pg=="   Dim binaryData() As Byte   binaryData = System.Convert.FromBase64String(str)   Dim outFile As System.IO.FileStream   Try      outFile = New System.IO.FileStream("c:output", _         System.IO.FileMode.Create,          System.IO.FileAccess.Write)      outFile.Write(binaryData, 0, binaryData.Length - 1)      outFile.Close()   Catch exp As System.Exception      System.Console.WriteLine("{0}", exp.Message)   End Try

After the conversion, the string represented by Viewstate appears as:

   t<1580946607;t<;l;>;l;>;l;l>;>;;>;>>;>>;

Although the decoded string isn’t in plain English, it’s not too difficult to see the text contained in the Label control. This might pose a security risk as these values can be spoofed and modified. To prevent that, you can detect whether the user has modified the Viewstate value by forcing the ASP.NET framework to run a Machine Authentication Check (MAC) when the client posts the Viewstate back to the server. To do so, add an EnableViewStateMac attribute to the @Page directive in your aspx file.

   <%@ Page EnableViewStateMac="true" Language="vb" %>

Programming Viewstate
Most ASP.NET developers are aware of the existence of the Viewstate hidden field. But most are not aware that it is possible to programmatically manipulate the field, adding any values that you wish. For example, suppose you want to know the last time the Listbox item was selected. You can use the code similar to the following to save the current date and time to the Viewstate:

   Private Sub lstLanguages_SelectedIndexChanged( _      ByVal sender As System.Object, ByVal e As _      System.EventArgs) Handles       lstLanguages.SelectedIndexChanged      ViewState("lastChanged") = DateTime.Now   End Sub

You can retrieve values you add to Viewstate, with code similar to the following:

   Response.Write("The Listbox was last changed at " & _      ViewState("lastChanged"))

Use Viewstate Sparingly
While the Viewstate hidden field is a great way to maintain the state of the controls in a Web Form, it comes with a performance penalty. The string stored in Viewstate grows with the number of controls on a Web Form. To see the effect of this, add a Listbox server control to a Web Form and turn tracing on. To turn tracing on in ASP.NET, switch the Web Form to HTML view and add the attribute Trace=true” to the @Page directive (see Figure 2).

Figure 2. Add the Trace=”true” attribute to turn on tracing for a Web Form.

The sample form shown in Figure 3 binds the Listbox to a DataSet containing Author names.

Figure 3: This Web Form contains a Listbox control and a Button control.

To display the full name of an author, a user can select the author from the ListBox and click the “Display Full Name” button. After the resulting page is loaded, you can examine the size of the Viewstate hidden field (see Figure 4).

Figure 4: The length of Viewstate grows with the number of controls in a Web Form.

As you can see in Figure 4, the Listbox control requires a whopping 692 bytes of Viewstate! The reason for the large Viewstate is because the control automatically attempts to retain all the values in the Listbox. Listing 1 shows the source for this application. The page binds the Listbox to the data source the first time the user requests the page, but after each postback the page relies on the saved Viewstate to restore control settings.

Disabling Viewstate
The problem with a large Viewstate is that the increased length causes the Web page to be larger, which not only increases network traffic, but also results in longer processing time by the Web browser. The Viewstate is enabled by default, but there are instances where turning off Viewstate can improve the performance of your application. For instance, if there is no need to post back values (such as using the ListBox purely for displaying information), then Viewstate can be disabled. To disable Viewstate for the entire page, set the EnableViewState attribute of the @Page directive of the ASP.NET page to “false”:

   <%@ Page EnableViewState="false" Language="vb" %>

When you disable Viewstate, you may have to do extra work. In this example, every time the page is loaded, the code must bind the Listbox to the database because the values within the Listbox are no longer preserved. Also, even though the Viewstate has been disabled, ASP.NET still uses about twenty bytes for Viewstate.

Not only can you disable Viewstate at the page level, but you can also disable Viewstate at the control level. For example, the following code disables Viewstate for a ListBox control:

   

You can also disable Viewstate for the entire application in the web.config file:

                           

Evaluating Other ASP.NET State Maintenance Options
You aren’t limited to using ASP.NET Viewstate to maintain state data. In fact, Viewstate automatically stores only control state, and is less useful for persisting other values between pages or sessions even though?as you’ve seen?you can modify it programatically. In the rest of this article, you’ll see how to use these other state maintenance options.

Maintaining State with Cookies.
A cookie is basically a small piece of information sent by the Web server to be written to the Web browser. Subsequent requests by the Web browser will send the cookie back to the server.

The syntax for creating a cookie is:

   Response.Cookies(NameOfCookie)(key) = value

The cookie behaves much like Viewstate, with the notable exception that a cookie transcends pages while Viewstate is only valid within a single page.

Consider the following example:.

   If IsPostBack Then       '---retrieves the cookies value---      Response.Write(Request.Cookies _         ("Page4Cookies")("timeRequested"))      Response.Write(Request.Cookies _         ("Page4Cookies")("country"))   Else      '---sets the cookies---      Response.Cookies("Page4Cookies")("timeRequested") = _         DateTime.Now      Response.Cookies("Page4Cookies")("country") =         "SINGAPORE"   End If

In the preceding code, when a page is loaded for the first time (IsPostBack = False), the server sets two cookies?timeRequested and country. When a postback occurs, the server retrieves the cookie values. Note that the cookies created in this example are called session cookies, which are name/value pairs stored in the client’s memory. Session cookies apply to a single browser instance. When the user closes that browser instance, the session cookies are destroyed. To create cookies that retain their values between browser instances, you must create persistent cookies, which reside on the user’s hard drive. To create a persistent cookie, add an expiration time to the cookie. For example:

   Response.Cookies("Page4Cookies").Expires = _      DateTime.Now.AddMinutes(5)   Response.Cookies("Page4Cookies")("timeRequested") = _      Date.Now

The cookies will now expire in five minutes after they have been saved on the Web browser. You can verify this by examining your browser cache as shown in Figure 5.

Figure 5: The cookies are stored in the folder designated as your browser cache.

Maintaining State on the Server with the Session Object
Storing state information on the client side using Viewstate reduces server load at the cost of increasing the network traffic and the client workload, so it’s not suitable when you need to maintain a large amount of information between pages. Also, there is a practical limit as to how much information you can store on the client side. Viewstate also poses a security problem. Even though the Viewstate value is hashed, it is nonetheless possible for a malicious user to tamper with it.

In classic ASP, you use the Session object to maintain state between pages. ASP.NET extends the Session object to solve some problems with the classic ASP version. Before discussing the extensions, here’s a brief review on how classic ASP establishes a Session.

  1. A browser requests a page from the server for the first time.
  2. The server responds with the requested page and sets a cookie containing the Session ID.
  3. The browser requests additional pages from Web server, passing the cookie containing the Session ID back to the server with each request.
  4. When the requested pages contain code to create Session variables, the ASP engine creates the variables in the Web server’s memory using the Session ID as a key.
  5. Subsequent ASP pages can access the Session variables created earlier (based on the Session ID).

A few things to note:

  1. The Session variables are stored in the Web server’s memory. If an application uses five session variables on average, 100 concurrent users will require 500 session variables. This increases the memory requirements of the Web server. Hence you should use Session variables sparingly.
  2. Session variables are stored in volatile memory, so if the Web server shuts down or crashes, all the values will be lost.
  3. Sessions are problematic in a Web server farm. The Session variables are stored only on the Web server that created them. Subsequent requests from the same user might be rerouted to another Web server, from which the stored Session variables will be inaccessible.

The ASP.NET Session object solves many of these problems. Figure 6 shows a page with tracing enabled. You can see the Session ID generated when a request is made to the Web server. When you refresh this page, you should see the same Session ID.

Figure 6. Turning Tracing on shows the Session ID generated (or retrieved) for a request.

However, if you remove the Session_Start event in Global.asax file, an interesting thing occurs; the Session ID now changes every time you refresh or postback the page. The ASP.NET framework automatically turns off session support when the event handler is not present. You can also explicitly turn off Session support explicitly by modifying the application’s web.config file:

   

Conversely, to enable session support, you need to:

  • Add the Session_Start event to the global.asx file, and
  • Use the Session object in your code

After enabling Sessions, you can add some code to a Web Form:

   Private Sub Page_Load(ByVal sender As System.Object, _    ByVal e As System.EventArgs) Handles MyBase.Load      Session("requestedTime") = DateTime.Now   End Sub

When the browser requests this Web Form, the code saves the time of the request into a Session variable called requestedTime.

To prove that the value was saved correctly, you can add a second Web Form (Webform2.aspx) to the project:

   Private Sub Page_Load(ByVal sender As System.Object, _    ByVal e As System.EventArgs) Handles MyBase.Load      Response.Write("Webform1.aspx was requested at " _      & Session("requestedTime"))   End Sub

To run this project, first load Webform1.aspx, and then browse to Webform2.aspx. Webform2.aspx will display the date and time you requested Webform1.aspx. Figure 7 shows the Session variable and its value.

Figure 7: Trace-enabled display shows the value of the Session variable and the SessionID cookie.

Using Cookieless Sessions
Sessions rely on cookies by default. Although all modern Web browsers support cookies, users may choose to turn off cookie support, or the client device (such as a WAP phone) may not support cookies. In these cases, the Session object will not work. You can work around this problem by embedding the Session ID in each URL. This technique is used widely by many Web sites, such as Amazon.com. ASP.NET now supports this “cookieless” method for supporting Sessions. To enable cookieless sessions, edit your application’s web.config file and set the cookieless attribute to “true”:

   

After altering the web.config file, when you load Webform1.aspx, the URL will look similar to the following (the URL is a single line):

   http://localhost/StateManagement/(ymqpoo45lyfih455lcf2      kvfp)/WebForm1.aspx

Note that the Session ID is now embedded within the URL, enclosed in parentheses. To request Webform2.aspx, change the URL to (all on one line):

   http://localhost/StateManagement/      (ymqpoo45lyfih455lcf2kvfp)/WebForm2.aspx

You should see the time in which Webform1.aspx is requested. However, if you request Webform2.aspx without the embedded Session ID (http://localhost/StateManagement/WebForm2.aspx), the state is lost and the ASP.NET framework issues a new Session Id.

Note that you can’t have it both ways?either you use cookie-based Sessions or cookie-less Sessions but not both. To determine if the browser supports cookies, try creating a cookie and examine the value of the cookie when a postback occurs. If the cookie value is found, that means cookies are supported on the browser.

Maintaining State in Hidden Fields
Yet another way to maintain state without using cookies is to use hidden form fields in your Web pages. You can use the HTMLInputHidden control (under the HTML tab in Toolbox) to add hidden fields (see Figure 8).

Figure 8: The HTML tab contains a Hidden control that inserts a hidden field in a Web Form.

To set a value using the HTMLInputHidden control, simply set its Value property:

   HiddenField.Value = "some values here"

On postbacks, you can retrieve and examine the value of the hidden field.

   hiddenValue = HiddenField.Value

Using the Session Object in a Web Farm
Microsoft has also added ASP.NET features that help solve the problems involved in using the Session object in a Web server farm. ASP.NET provides two potential solutions to this problem: StateServer and SQLServer session support.

The StateServer solution stores all the Session variables for the entire Web farm on a single server. All Web servers in a Web farm need to configure their applications to point to this StateServer machine. The StateServer runs as a Windows service?installed when Visual Studio.NET is installed. Previously, you had to obtain the ASP.NET Premium Edition to get the StateServer service). Run the StateServer service on the machine that you want to be the central repository for Session variables. To run the service, invoke the Services application (Start-> Programs -> Administrative Tools -> Services) and start the ASP.NET State Server service.

Next, edit the mode and stateConnectionString attributes of the element of the web.config file:

   

Table 1 summarizes the various values of the mode attribute.

Table 1: Effect of using different values for the mode attribute.

Mode

Description

Off

DisablesSession state

InProc

Thedefault. The Session state is “in process” with an ASP.NET worker process

SQLServer

Sessionstate information is stored in SQL Server.

StateServer

Sessionstate information is stored in a State Server

The stateConnectionString attribute specifies the server identified as the State Server. The sample code above uses my local machine; so the IP address is the local loopback address 127.0.0.1. The number 42424 is the port address of the service. Using the web.config settings shown, all session variables for the Web farm would now be routed and stored on this machine.

Persisting Session Variables to SQLServer
Using a state server lets all the servers in a Web farm share state information; however, that does not prevent state data from being lost if the state server crashes. You can persist state information and keep it accessible (even after a reboot) by storing the state data in a SQL Server database. To do that, modify the web.config file as follows:

   

The sqlConnectionString attribute contains the IP address of the machine running SQL Server (127.0.0.1 in this case) as well as the user ID and password required to access the SQL Server.

Next, you need to set up the necessary database and tables to store the state information. Fortunately, ASP.NET provides an installation script to help you setup the database, ASPState, and its tables. To use the script, enter the following at a command prompt (you need to enter the following on a single line):

   D:WINNTMicrosoft.NETFrameworkv1.0.3328>     osql -S localhost -U sa -P 

The state information is actually stored in the tempdb database (not ASPState), in the ASPStateTempApplications and ASPStateTempSessions tables. The ASPState database contains several stored procedures that allow ASP.NET to perform housekeeping tasks, such as retrieving session variables and removing expired Session variables. All Session variables would now be stored in SQL Server as shown in Figure 9.

Figure 9: The session variables are stored in two tables?ASPStateTempApplications and ASPStateTempSessions.

To sum up, you've seen an overview of the various methods for maintaining state in ASP.NET. But which of these methods should you choose? Here are some criteria that may help you determine the appropriate state maintenance method for your applications:

  • If security is not a main concern, using Viewstate is a cost-effective way to maintain state. However, the downside of this method is that of increased loading and processing time on the Web browser. Viewstate also exposes the state information on the client side, which may not be desirable if secrecy is a top priority.
  • The Session object offers an effective way to maintain state information on the server-side. However, the Session object should be used sparingly as it increases the workload on the Web server.
  • The Session object supports three modes?InProc, StateServer and SQLServer. With InProc being the least resource intensive, but being the least robust, to SQLServer being the most resource intensive, and the most robust. There is no free lunch; choose the mode carefully to suit your needs.

Remember, maintaining state is a costly affair; enable it only when necessary!

Share the Post:
Share on facebook
Share on twitter
Share on linkedin

Overview

The Latest

Top 5 B2B SaaS Marketing Agencies for 2023

In recent years, the software-as-a-service (SaaS) sector has experienced exponential growth as more and more companies choose cloud-based solutions. Any SaaS company hoping to stay ahead of the curve in this quickly changing industry needs to invest in effective marketing. So selecting the best marketing agency can mean the difference

technology leadership

Why the World Needs More Technology Leadership

As a fact, technology has touched every single aspect of our lives. And there are some technology giants in today’s world which have been frequently opined to have a strong influence on recent overall technological influence. Moreover, those tech giants have popular technology leaders leading the companies toward achieving greatness.

iOS app development

The Future of iOS App Development: Trends to Watch

When it launched in 2008, the Apple App Store only had 500 apps available. By the first quarter of 2022, the store had about 2.18 million iOS-exclusive apps. Average monthly app releases for the platform reached 34,000 in the first half of 2022, indicating rapid growth in iOS app development.