Session State

Session State

One of the more difficult problems in Web programming is storing per-user state. Suppose you intend to write a site that lets visitors drop items into virtual shopping carts by clicking Add to Cart buttons. It sounds simple enough, but remember: the Web server sees the button clicks as a series of unrelated HTTP requests, and the requests generated by one user are mixed in with similar requests from other users. Finding a place to store the contents of your shopping carts in memory on the server, for example, or in hidden <input> fields round-tripped to the client and back is only half the battle; the other half involves examining each incoming request, determining whether that request came from a user for whom a shopping cart has been created, and either correlating the request to an existing shopping cart or creating a brand new shopping cart. The challenge is far less trivial than most people realize.

ASP offers a convenient and easy-to-use solution to the per-user-state problem in the form of sessions. When a user who hasn t visited an ASP-driven site recently (typically in the last 20 minutes) submits a request to that site, ASP creates a session for that user and returns a cookie that uniquely identifies the session. In subsequent requests from the same user, ASP uses the cookie to correlate the request to the session it created earlier. If hundreds of users browse a site simultaneously, each is assigned his or her own session, and each session implements a data store that s exposed to ASP scripts through a session object. Information written to that data store is called session state. One simple statement in an ASP script writes a value to session state or reads it back. And because each session corresponds to exactly one user, data written to session state is stored strictly on a per-user basis.

Despite its elegance, ASP s session state implementation suffers from two fatal flaws:

  • ASP session state is stored in memory, which means it s incompatible with Web farms clusters of Web servers that act as one and also that it s destroyed if IIS is restarted or the server is rebooted.

  • ASP session state relies on cookies to correlate users to sessions. If a user disables cookies in his or her browser, an ASP Web server is powerless to map incoming requests to sessions.

For these reasons, many large sites that rely on ASP either don t use session state or use a custom implementation that replaces ASP s default session state provider with one of their own.

ASP.NET also uses sessions to enable Web applications to store per-user state. ASP.NET s session state implementation is better thought out and more robust, however, and it suffers from none of the shortcomings of ASP session state. It supports a variety of storage models, enabling session state to be physically stored in-process to ASP.NET, in another process, on another machine, or even in a database, and it supports cookieless operation for the benefit of browsers that don t support cookies (or that have cookies turned off). All in all, it s a huge improvement over ASP and one of ASP.NET s greatest strengths. And it s the perfect place to store shopping carts or anything else that requires unique storage for each visitor to your site.

Using Session State

Using ASP.NET session state is simplicity itself. Pages access it through the Session property that they inherit from System.Web.UI.Page. Global.asax files access it through the Session property inherited from System.Web.HttpApplication. In both cases, the Session property maps to an instance of System.Web.SessionState.HttpSessionState specially created by ASP.NET to store data for the user who originated the request.

HttpSessionState.Add adds an item to session state. As are items stored in application state or the application cache, an item is an instance of any managed type keyed by a string. The following statement adds an item named 10012552 to session state and assigns it the value Quantity=1 :

Session.Add ("10012552", "Quantity=1");

Or, if you d prefer, you can add it this way:

Session["10012552"] = "Quantity=1";

The Add method and [] operator are semantically equivalent. In other words, both add items to session state, and both replace an existing item if an existing key is specified.

Retrieving an item from session state is equally painless:

string value = Session["10012552"];

The same can be said about enumerating items and the strings that they re keyed with:

NameObjectCollectionBase.KeysCollection keys = Session.Keys; foreach (string key in keys) { // key is the item's key // Session[key] returns the item's value . . . }

To remove items from session state, use HttpSessionState s Remove, RemoveAt, and RemoveAll methods. You can also use Clear, which is equivalent to RemoveAll.

ASP.NET uses randomly generated session IDs, which aren t unlike COM GUIDs (globally unique identifiers), to identify sessions. If you d like to know what the ID of a given session is, you can retrieve it from the SessionID property of the corresponding HttpSessionState object. Another interesting HttpSessionState property is IsNewSession, which reveals whether the session ID was generated for the current request (true) or a previous request (false).

Incidentally, if you perform a multistep update on session state and are concerned that a read from another thread at just the wrong time might catch the data in an indeterminate state, don t fret. ASP.NET locks session state when an HttpApplication instance fires an AcquireRequestState event and unlocks it following the next ReleaseRequestState event. The practical effect is that it s impossible for two requests to read and write session state at the same time, even in the unlikely event that two requests that correspond to the same session overlap each other.

The SessionSpy Page

For a firsthand look at session state in action, check out the Web page in Figure 9-7. Called SessionSpy.aspx, it uses session state to store a count of the number of times a user visits the site. The first time you request the page, you ll be greeted as a first-time visitor and shown the ID of the session that was created for you. Each time thereafter, you ll be told how many times you ve visited the site (that is, requested the page).

The count is a simple integer stored in session state and keyed with the string Count . SessionSpy.aspx reads the HttpSessionState object s IsNewSession property to determine whether this access is the first one to the page and its SessionID property to get the session ID.

SessionSpy.aspx

<%@ Page Language="C#" %> <html> <body> <% if (Session.IsNewSession Session["Count"] == null) { Session["Count"] = 1; Response.Write ("Welcome! Because this is your first " +  "visit to this site, a new session has been created " +  "for you. Your session ID is " + Session.SessionID +  "."); } else { Session["Count"] = (int) Session["Count"] + 1; Response.Write ("You have visited this site " + Session["Count"] + " times. Your session ID is still " + Session.SessionID + "."); } %> </body> </html>
Figure 9-7

The SessionSpy page.

After you ve played with the page for a few moments, start a second instance of your browser and open SessionSpy.aspx. Because the new browser instance represents a new session and doesn t share cookies with the first, you re greeted as a first-time user. But use your browser s New Window command (Ctrl+N in most browsers) to start a third instance, and you ll be greeted as a returning user. Why? A browser started with the New Window command doesn t represent a new session. It shares cookies and other resources with the first instance and thus shares its session state on the server, too.

Cookieless Session State

By default, ASP.NET, like ASP, uses cookies to correlate returning users to sessions on the server. Unlike ASP, ASP.NET supports cookieless session state as well. Cookieless sessions are enabled by adding cookieless= true to the sessionState element in Web.config or Machine.config:

<sessionState cookieless="true" />

How does ASP.NET correlate users and sessions when cookies are disabled? By using URL munging. Check out the screen in Figure 9-8, which was taken after a client retrieved a page from an ASP.NET application running in cookieless mode. The strange-looking value in parentheses in the browser s address bar is the session ID. Before returning the page to the client, ASP.NET inserts the session ID into the URL. When the page posts back to the server, ASP.NET strips the session ID from the URL and uses it to associate the request with a session. URL munging isn t perfect because there s nothing preventing the user from editing the URL and invalidating the session ID. But it s better than nothing, and it prevents ASP.NET session state from being unusable with browsers that don t honor cookies.

You re probably wondering, Is there a way I can ask ASP.NET whether cookies are enabled in a browser, and if so, can I enable cookieless operation on the fly if I detect that a request came from a browser that doesn t support cookies? The short answer is no and no. ASP.NET doesn t attempt to determine whether a browser supports cookies, so if you want to know, you have to find out yourself. The usual technique is to return a cookie to a browser and use Response.Redirect to redirect to a page that checks for the cookie. If the cookie s not there, you know the browser ignored it. Another approach is to return a cookie along with some client-side script that checks for it. Even if you determine at run time that cookies aren t supported, however, there s not much you can do about it as far as session state is concerned because cookieless operation can t be enabled and disabled programmatically. If you want to know whether cookieless session state is in effect, however, you can read the IsCookieless property of any HttpSessionState object.

Bottom line? If you want session state to work with as many browsers as possible, configure your application to use cookieless session state up front. If you don t like URL munging and don t care that your application might not work properly with browsers that have cookies disabled (many applications test for cookie support and display a warning indicating that they might not work properly if cookies are disabled), then stick with the default: cookieless= false.

Figure 9-8

URL containing a session ID.

Session State Process Models

Cookieless sessions are an important enhancement to ASP.NET, but even more important are ASP.NET s new session state process models. ASP session state is always stored in memory, which makes it incompatible with Web farms (a session and session ID created on server A are undefined on server B). It also means that you lose everything in session state if the Web server goes down. That s a big deal to a site like Amazon.com, which at any given time might have millions of dollars worth of potential sales sitting in virtual shopping carts. Web farms are a big deal, too, because setting up clusters of Web servers is a classic and relatively inexpensive way to scale an application to meet the demands of a growing customer base.

That s why ASP.NET doesn t limit session to memory on the Web server as ASP does. ASP.NET supports three session state process models:

Model

Description

In-proc

Stores session state in-process to ASP.NET (that is, in Aspnet_wp.exe)

State server

Stores session state in an external state server process on the Web server or on a remote machine

SQL Server

Stores session state in a Microsoft SQL Server database on the Web server or on a remote machine

The default is in-proc, which is very ASP-like, but simple configuration changes applied via Web.config or Machine.config switch to the state server or SQL Server model and get session state out of the ASP.NET worker process Aspnet_wp.exe and into the location of your choosing. The sections that follow describe the necessary configuration changes and also shed light on the pros and cons of the individual process models.

In-Proc Session State

In-proc session state is the fastest, but it s also the least robust; restart IIS or reboot your Web server and in-proc session state goes away for good. In-proc is the default because of the following statement in Machine.config:

<sessionState ... mode="InProc" />

To be absolutely certain that in-proc session state is in effect regardless of what might be in Machine.config, add a Web.config file to your application s virtual root directory and include this statement in it:

<sessionState mode="InProc" />

In-proc session state is appropriate when you prefer speed to robustness and your application runs on a single server rather than a Web farm.

State Server Session State

The state server session state model is new in ASP.NET. It moves session state out of Aspnet_wp.exe and into a dedicated state server process managed by the system. The state server is actually a running instance of a service named Aspnet_state.exe. If you want to use the state server model, you must do the following:

  • Start Aspnet_state.exe. You can start it manually (from the command line) by executing the following command:

    net start aspnet_state

    Or you can configure it to start automatically each time the system is started by using Windows Services control panel applet (Figure 9-9).

  • Add a mode= StateServer attribute and a stateConnectionString attribute to the sessionState element in Machine.config or a local Web.config file. The latter of these two attributes identifies the machine that hosts the state server process.

    Figure 9-9

    The ASP.NET State service.

Here s a Web.config file that configures an application to store session state in a state server process on the same Web server that hosts the application:

<configuration> <system.web> <sessionState mode="StateServer" stateConnectionString="tcpip=localhost:42424" /> </system.web> </configuration>

And here s one that places session state in a state server process on another machine identified by IP address:

<configuration> <system.web> <sessionState mode="StateServer" stateConnectionString="tcpip=192.168.1.2:42424" /> </system.web> </configuration>

By default, ASP.NET uses port 42424 to communicate with the state server process. That s why 42424 appears in the state connection string. In the unlikely event that 42424 conflicts with another application on your Web server, you can change the port number by doing the following:

  • Add the desired port number to the registry at HKEY_LOCAL_ MACHINE\System\CurrentControlSet\Services\aspnet_state\ Parameters\Port.

  • Replace 42424 with the new port number in stateConnectionString.

As an example, here s a Web.config file that changes the session state mode to StateServer and directs ASP.NET to use port 31313 to connect Aspnet_wp.exe to Aspnet_state.exe:

<configuration> <system.web> <sessionState mode="StateServer" stateConnectionString="tcpip=192.168.1.2:31313" /> </system.web> </configuration>

The state server model is slower than in-proc session state because data read from and written to session state must travel across process or machine boundaries. However, the state server model prevents session state from being lost if IIS is restarted, and should the state server process be on another machine, it even allows session state to survive if the entire Web server is rebooted. Switching to the state server model is also one way to build ASP.NET applications that work with Web farms.

Figure 9-10 illustrates how the state server model solves the Web farm compatibility problem. In this example, the Web farm contains three servers. The application runs in worker processes on all three servers, but each server is configured to store session state in a state server process on a fourth machine. It s perfectly acceptable now for data to be written to session state on server A and read back on server B because both servers refer to machine D for their session state. If you don t want to dedicate a machine to host the state server process, no problem: simply designate one of the Web servers as the state server and point the other servers to it with stateConnectionString.

Figure 9-10

Web farm with session state in a remote state server process.

SQL Server Session State

The SQL Server process model offers the ultimate in scalability and reliability. Like the state server model, it moves session state out of Aspnet_wp.exe. But rather than store session state in an external process, the SQL Server model stores it in a Microsoft SQL Server database. You gain Web farm compatibility because you can point all your servers to a common back-end machine (the one that hosts the database). You also achieve robustness because session state is preserved no matter what even if IIS is restarted or the Web server is reboot ed. If SQL Server is clustered or otherwise configured to survive hard failures, you can reboot the database server itself and still preserve the contents of session state.

Configuring ASP.NET to use the SQL Server process model is a breeze. Here are the steps required:

  • Create the database that holds the session state. The .NET Framework SDK provides a script that creates the database for you; it s called InstallSqlState.sql. To run it, open a command prompt window and type the following command:

    osql -S localhost -U sa -P -i installsqlstate.sql

    This command creates a SQL Server database named ASPState on the host machine and adds to it all the tables, stored procedures, and other infrastructure that ASP.NET uses to access the database, as shown in Figure 9-11.

  • Add a mode= SQLServer attribute and a sqlConnectionString attribute to the sessionState element in Machine.config or a local Web.config file. The latter of these two attributes provides the information ASP.NET needs to connect to the database.

    Figure 9-11

    The ASPState database.

The following Web.config file configures an ASP.NET application to store session state in a SQL Server database on the Web server:

<configuration> <system.web> <sessionState mode="SQLServer" sqlConnectionString="server=localhost;uid=sa;pwd=" /> </system.web> </configuration>

The next one does the same, but it points ASP.NET to a SQL Server database on a remote machine named Hawkeye :

<configuration> <system.web> <sessionState mode="SQLServer" sqlConnectionString="server=hawkeye;uid=sa;pwd=" /> </system.web> </configuration>

Performance-wise, the SQL Server model is the slowest of them all, but in return for speed it virtually guarantees that session state won t be lost. Figure 9-12 shows how the SQL Server option factors into Web farms. A dedicated server holds the state database, and all the Web servers point ASP.NET to that database. If you intend to use ASP.NET to build large, industrial-strength e-commerce sites, this is the architecture you want.

Figure 9-12

Web farm with session state in a remote SQL Server database.

State Servers, SQL Servers, and Serializable Objects

One gotcha to be aware of if you plan to use the state server or SQL Server session state model is that both require types stored in session state to be serializable. Serialization is the process of writing out the data that defines an object instance to a designated storage medium for the purpose of re-creating, or rehydrating, it at a later time or in another place. ASP.NET must be able to serialize objects stored in session state if it s to transfer them to a state server process or a SQL Server database. And it must be able to deserialize them if they re to be read back. Nonserializable types work just fine with the in-proc session state model, but try to write a nonserializable type to session state using either of the other process models and ASP.NET will throw an exception.

Here s an example to help clarify. Suppose you write a class named ShoppingCart to serve as a virtual container for items that users select from your site:

public class ShoppingCart { ... }

Defined this way, a ShoppingCart instance can be written to session state without any problem as long as session state is stored in-proc:

ShoppingCart cart = new ShoppingCart (); Session["MyShoppingCart"] = cart;

But the same code throws an exception if you switch to the state server or SQL Server model. To remedy that, make the class serializable by adding a Serializable attribute:

[Serializable] public class ShoppingCart { ... }

This quick-and-easy change enables ASP.NET to serialize and deserialize ShoppingCart objects using System.Runtime.Serialization.Formatters.Binary.BinaryFormatter, better known as the .NET Framework s binary formatter. When you create custom data types with the intention of storing them in session state, always include a Serializable attribute unless you re certain you ll only use the types in-proc. It s never harmful, and it will pay off in spades if you or anyone else attempts to write an instance of the class to session state in an application that uses the state server or SQL Server model.

Session Lifetimes

ASP.NET creates sessions for you. It also deletes them (in reality, hands them over to the garbage collector) when it s done. Knowing when to delete them requires a bit of guesswork. ASP.NET can t know definitively when a session is no longer needed because it has no way of knowing whether a given request is that user s last. So it does the next best thing: if a prescribed time period elapses and ASP.NET receives no requests from a user for whom a session was created, it discards the corresponding session. The default time-out period is 20 minutes, as specified in Machine.config:

<sessionState ... timeout="20" />

You can change the session time-out period in three ways. Option number one is to edit Machine.config. Option number two is to place a statement like this one, which sets the session time-out to 60 minutes, in a local Web.config file:

<sessionState timeout="60" />

And option number three is to write a time-out value (in minutes) to the Timeout property of an HttpSessionState object:

Session.Timeout = 60;

Which route you should choose depends on the desired scope of the change. Setting the time-out interval in Machine.config changes the default for all ASP.NET applications on the Web server. Setting it in a local Web.config file changes it for a single application, and setting it with Session.Timeout changes it for an individual session. The proper time-out interval is both subjective and application-specific. Twenty minutes is fine for most applications, but if you d like a user to be able to go out to lunch and come back to find his or her shopping cart still full (assuming you re storing shopping carts in session state), then you might want to up the time-out interval to an hour or more.

You can see session time-outs in action by calling up Figure 9-7 s SessionSpy.aspx in your browser, refreshing it a time or two, waiting for 20 minutes, and then refreshing the page again. Because your session timed out while you were away, you ll be greeted as a first-time visitor. Increase the session time-out, and you ll be able to stay away for longer periods of time.

An application can explicitly close a session by calling the session s Abandon method:

Session.Abandon ();

This option is sometimes used by sites that permit users to log out (or that forcibly log them out) after completing a transaction.

Disabling Session State

Session state can also be disabled altogether. Session state exacts a modest price in both memory and performance, so if you don t use it, you should disable it. You can disable session state for an individual page (ASPX file) with the following @ Page directive:

<%@ Page EnableSessionState="false" %>

You can disable it for an entire application by including this statement in Web.config:

<sessionState mode="Off" />

Or you can disable it for all applications by adding a mode= Off attribute to the sessionState element in Machine.config.

A Word on Web Farms

Moving session state to a remote machine and pointing all your Web servers to that machine is essential to building Web applications that are compatible with server farms. But there s something else you have to do to deploy an ASP.NET application on a Web farm. First, a bit of background.

Each server s Machine.config file contains a machineKey element that assigns values to a pair of cryptographic keys:

<machineKey ... validationKey="AutoGenerate" decryptionKey="AutoGenerate" />

When configured to prevent tampering by appending hashes to view state values and forms authentication cookies (a topic I ll cover in Chapter 10), ASP.NET uses validationKey to generate the hashes. If the protection level is sufficiently high, ASP.NET goes even further and uses decryptionKey to encrypt view state and authentication cookies. AutoGenerate tells ASP.NET to generate a random key and store it in the host machine s Local Security Authority (LSA). Randomly generated keys are fine for single-server installations, but in a Web farm, each server must use identical keys; otherwise, a value encrypted on one machine can t be unencrypted on another.

Before deploying an ASP.NET application on a Web farm, you should make the following configuration change on every server in the Web farm. The change can be made in Machine.config or in a local Web.config file:

  • Set machineKey s validationKey attribute to validationKey= mmmm, where mmmm is a random value from 40 to 128 characters in length. Longer values provide stronger encryption.

  • Set machineKey s decryptionKey attribute to decryptionKey= nnnn, where nnnn is a random value either 16 or 48 characters in length. The latter provides stronger encryption but works only on servers that support 128-bit encryption.

Here s a sample Web.config file that, if used on every server on which your application is installed, configures each server to use identical validation and encryption keys:

<configuration> <system.web> <machineKey validationKey="DD2B3BB0B07F4FE6917B60DAFEB0D01532C1C3BB07F533A1" decryptionKey="C89EFEF650CA4D9C9BC986061211329A9717DC2260BC6199" /> </system.web> </configuration>

Values for validationKey and decryptionKey should by cryptographically strong to make values encrypted with them difficult to break. Various tools are available for producing cryptographically strong keys. You can even write your own key generator using the FCL s System.Security.Cryptography.RNGCryptoServiceProvider class. (RNG stands for Random Number Generator.) However you derive your keys, be sure to apply them in a CONFIG file or your Web farm compatible application might not be so Web farm compatible after all.



Programming Microsoft  .NET
Applied MicrosoftNET Framework Programming in Microsoft Visual BasicNET
ISBN: B000MUD834
EAN: N/A
Year: 2002
Pages: 101

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