Comparing Options for Storing State

In this book, you'll use the inProc SessionState setting for all the examples that use sessions— and except for the example in this section, that will be all the examples in the book. My main goal in this section is to show you that the performance differences between the various options is negligible until your Web server is under a heavy load. The section uses SQL Server to retrieve a table and then stores the resulting data set in the Session object for future use. Don't worry about the database-specific code for now—you'll see more about database access later in this book. For now, just create or run the examples to see the performance differences.

Note You shouldn't build a real-world application like the one used in this section, because the data is duplicated for each Session. In a real application, store shared data at Application scope.

This example retrieves the Customers table from the Northwind sample database and stores it at Session scope. Wait! How can you do this if you turn off session state? The answer is—you can't. If you turn off session state, you must retrieve the data from SQL Server for each request. I'll start with session state turned off.

First, create a new Web Form (ch7-5.aspx) and set the default form ID to "Forml". Click the View menu and select the Server Explorer item (see Figure 7.7).

This will display the Server Explorer window in VS.NET (see Figure 7.8).


J if"


J if"


i.ljr: VFH










Figure 7.7: The VS.NET View menu

Figure 7.8: The VS.NET Explorer window

Your Server Explorer will look somewhat different from mine because Server Explorer contains a list of items known to your server. Open the Servers folder (click the plus (+) sign) and then the SQL Servers item and select a SQL Server installation that has the Northwind database installed. If your Web server and your SQL Server are not on the same machine, you'll need to add another server. To add a server, right-click the Servers item in the Server Explorer window and select Add Server from the pop-up menu. Follow the Add Server Wizard directions to add the server.

Open the SQL Server item. You'll see the list of databases for the selected SQL Server instance. Select the Northwind database and open the Tables item (see Figure 7.9).

Figure 7.9: Server Explorer view of the Northwind database tables

While you can drag-and-drop nonvisual controls such as SqlConnection and SqlDataAdapter from the Server Explorer, it's my opinion that normally you shouldn't do so. That's because the automatic code generation feature of ASP.NET often generates too much code! The reason is that ASP.NET, not knowing whether you want to perform read-only or both read and update operations, must generate all code as if you were performing updates. I know some of you won't care, but it seems wasteful to make the server process 50 automatically generated lines of code (much more for complex queries) rather than writing a few yourself. The basic process to get data from a SQL Server instance is as follows:

■ Create a SqlDataAdapter object with a specified SQL query and connection string.

■ Create a DataSet object.

■ Use the SqlDataAdapter's Fill method to retrieve the data.

You'll need to use the System.Data.SqlClient namespace to open a connection and retrieve data. Add this line to the top of the code-behind class file:

using System.Data.SqlClient;

For example, these three lines of code retrieve the contents of the Northwind Customers table into a data set:

Note Throughout this book, I've used the local SQL Server instance name localhost in connection strings, using the username sa (System Admin) and a blank password. I've also used SQL Server security (SQL Server usernames and passwords) rather than Windows security. If you're developing with a local instance of SQL Server or MSDE and you have a blank sa password, you will be able to copy most of the connection strings verbatim. However, if you are using a remote database server instance, you need to change the server name to the correct value for your server, and if you don't have access to the sa username or if the password is not blank, you will need to change those to the correct values for your database server as well.

SqlDataAdapter sda = New SqlDataAdapter

("SELECT * FROM Customers",

"server=localhost;uid=sa;pwd=;database=Northwind"); DataSet ds = New DataSet(); sda.Fill(ds, "Customers");

Enter the preceding three lines into the Page_Load event. The code you just wrote opens the Northwind database using the connection string you entered as the second parameter to the New SqlDataAdapter method. After opening the connection, it runs the query you entered as the first parameter to the new SqlDataAdapter method. Finally, the Fill method populates the DataSet object with the retrieved data, stored under the key name Customers. Now that you have the data, you need to display it on the Web Form.

The easiest possible way to display a data set is to use a DataGrid control. Drag a DataGrid control from the Toolbox onto the Web Form design surface. It doesn't matter how you size the control—it will resize automatically to contain the data. You need to bind the control to the DataSet control you just created, so add these two lines to the Page_Load event:

DataGrid1.DataSource = ds.Tables["Customers"].DefaultView; DataGrid1.DataBind();

Set the new Web Form as the start page and run the project. You'll see the table in Figure 7.10.

tem^ litlaiil £ ix liiLtr MVit

1 ftiiVin: T cf rw*4

J-Ufi.TI QIHKUh^jIU^ Omih vhiM nil



Aiwap Jifm-Tiqxdi i\r m! 44




Ilf.-i JJd

.'stmur fdfuk-ilz

i rirciRUrcr


Budv Okrauu

IliliiqH Hiljdm ei.|k

Ult)4ini kitar iili M


1 ji-ji liinm



3-iS2i SnM WSK Omv|


uh in "ewe am

Figure 7.10: DataGrid control filled with data from the Customers table in the sample Northwind database

Not very pretty, is it? Don't worry; you can change that easily. Close the browser window to return to design mode. Select the DataGrid control. Under the Properties window, you'll see two links: Auto Format and Property Builder. Click the Auto Format link and select Colorful 3 from the Auto Format dialog (see Figure 7.11).

Figure 7.11: VS.NET DataGrid Auto Format dialog

Click the OK button to close the dialog, and then run the Web Form again. The results might be more to your liking. Figure 7.12 shows the result after applying Auto Format to the table.

Figure 7.12: A DataGrid control with the Auto Format setting (filled with data from the Customers table in the sample Northwind database

Even if you're a die-hard fan of some other language, you have to admit that this is an amazing result for writing five lines of code, adding a control, and setting one property. In case you're interested, click the HTML tab in design view, and you'll see how selecting Auto Format generates a large number of settings. If you can't find an Auto Format setting you like, you can click the PropertyBuilder link and create your own. And, of course, you can always create your own style sheet manually and apply it to the DataGrid control.

That's enough playing around with the display. The point is to use this page to compare the various options for storing session state.

Turning Off Session State

For baseline performance, the first test you'll make is to turn off session state. To do that, open your web.config file. Scroll down to the <sessionState> element and set the mode attribute value to


Warning The web.config file, like other XML-formatted files, is case sensitive. Therefore, make sure you use the value Off, not off; otherwise, you'll get an error when you run the Web Form.

Save the web.config file and then run the ch7-5.aspx Web Form you just created. After it loads once, refresh the browser several times—in fact, hold down the refresh key (F5 in IE). Fairly speedy— uncached, isn't it? Now set the mode attribute for the <sessionState> element back to InProc, save the web.config file, and repeat the browse-refresh operation. Do you notice any difference? No? You shouldn't, because we haven't cached the dataset yet. Of course, with a single machine, you're unlikely to be able to tell much difference unless you use some server tools to measure performance more precisely.

Try again. This time, you'll use the Performance Monitor application to help. The Performance Monitor can measure a huge selection of processor and server operations—and it graphs them nicely for you. In this case, you care far less about the actual numbers that you'll get than you do about the relative numbers. The actual numbers change according to many factors—your hardware, your SQL Server, the amount of memory available, and so on. Therefore, I'm not going to show my numbers either, but I will give you the rough relative results.

Note The Performance Monitor ships as part of Windows 2000 and XP; if you're using Windows NT, you can use the Performance Explorer application, which works similarly, but some of the steps will differ. The rest of this section discusses the Performance application in Windows 2000 only.

Click Start ® Programs ® Administrative Tools ® Performance. You'll see the Performance application (see Figure 7.13).

CM«* bit

□ tf ; : " -liJil

flir im ^brthin

3 OlflB 1 fig li

i™- |r«nFin. |

i IF^alEaiai +i I injtf |.

..J r-■>:■■:

® m in


m™» d ooo hu ij£

'mi, | öw 1 l-ii« 1 > . 1 ^rvi-v

Figure 7.13: The Windows 2000 Performance application at startup

Figure 7.13: The Windows 2000 Performance application at startup

Select the System Monitor if it's not already selected (it is selected by default). The Performance application works by monitoring counters. You need to tell it which counters to monitor. In this case, you want to monitor the average number of Web requests per second. To add the counter, click the large plus (+) button on the toolbar. You'll see the Add Counters dialog (see Figure 7.14).

Figure 7.14: The Performance application's Add Counters dialog

If your server is not already selected, select it. If your server and your development machine are the same computer, you can click the Use Local Computer Counters radio button.

Just below the computer name drop-down list is a Performance Object drop-down list. Click the dropdown arrow and then scroll to the top of the list and select ASP.NET Applications. Click the Select Counters from List radio button and select the Anonymous Requests/Sec counter. Finally, the Select Instances from List listbox contains the ASP.NET applications available on your server. Select the one that ends with CSharpASP. After making all the necessary selections, the dialog should look like Figure 7.15.

Figure 7.15: The Add Counters dialog set to monitor anonymous requests per second for the ASP.NET CSharpASP application

Click the Close button. The Performance application immediately adds and begins to graph the new counter. Browse to the ch7-5.aspx Web Form again and hold down the Refresh key. You'll see the graph rise as the server receives and processes requests. Remember, at this point you're running with session state set to InProc. You'll have to hold down the Refresh key for several seconds to get an accurate average. Make a note of the number. At this point, you should go back, turn off session state, and check the Performance application without session state, because you're about to store the DataSet in a Session variable. If you try to use Session variables in your application with session state turned off, you'll get an error. Make a note of that value as well. Is there any discernable difference? I can't see any difference on my hardware.

Next, stop the application and change the Page_Load code to match Listing 7.5.

Listing 7.5: Persist a DataSet in a Session Variable (ch7-5.aspx.cs)

private void Page Load(object sender, System.EventArgs e) { SqlDataAdapter dsc; DataSet ds = new DataSet();

dsc = new SqlDataAdapter("SELECT * FROM Customers",

"server=localhost;uid=sa;pwd=;database=Northwind;"); ds = new DataSet(); dsc.Fill(ds, "Customers"); Session["ds"] = ds;

DataGrid1.DataSource = ds.Tables["Customers"].DefaultView; DataGrid1.DataBind();

Be sure to set session state back to InProc before running the code. When the page loads, the code in Listing 7.5 tests a Session variable with the key ds (for DataSet) to see if it is Null. If the Session variable doesn't exist, the code follows the track you've already seen—it creates a SqlDataAdapter, retrieves the data, and fills the DataSet. However, if the Session variable does exist, the code simply assigns the DataSet object reference stored in the Session variable to the local variable ds. The first time the page loads, the operation will be slightly slower than the preceding version because it has to test the Session["ds"] variable. However, each subsequent call should be considerably faster because the code doesn't have to query the database—it simply assigns an object reference to a local variable.

Save your changes and run the Web Form again. This time, you should see a considerable increase in the number of requests per second—in fact, if your Web server is on a different machine from the browser, you'll probably see at least a 50 percent improvement in speed. However, if your Web server and your browser are on the same machine, you'll see somewhat less of an increase because the browser uses up some machine resources as it starts parsing the response for each request.

Stop the project and change the web.config file <sessionState> mode attribute value to StateServer. The StateServer setting causes ASP.NET to maintain SessionState in a separate process. You may need to start the ASP.NET state service because the service doesn't start automatically when you boot your server. To start the service, click Start ® Programs ® Administrative Tools ® Services to start the Services dialog. Right-click the ASP.NET State entry in the Services list and select Start from the context menu (see Figure 7.16). After the service starts, you can close the Services dialog.

Asp Net State Service
Figure 7.16: Starting the ASP.NET State service from the Services dialog

Save the web.config file, and rerun the application. Hold down the browser refresh key to repeat the performance testing procedure. You'll see a drop in the number of requests per second. Because the StateServer setting causes the SessionState server to run out of process, ASP.NET must marshal the data between processes, which is somewhat slower than running the server in process. With my setup, the average number of requests drops by about 30 percent, but that's a small price to pay for being able to scale your application—unchanged except for the web.config setting—from one machine to a multiserver Web farm.

The last session state setting, SQLServer, causes the SessionState server to maintain Session data in SQL Server. You don't have to create any tables or databases—ASP.NET takes care of that for you—but you do have to have a trusted login to SQL Server. This time, you may see a performance drop as compared to StateServer, depending on the amount of memory in your machine, whether any of that memory is dedicated to SQL Server, whether the SQL Server you're running is on the same or another server, the speed of the connection between the servers, and so on. With my setup, there's no apparent difference between the SQLServer setting and the StateServer setting after the first request (which is noticeably, but not irritatingly, slower). Again, a slight performance drop in exchange for the capability not only to scale across a Web farm but also to maintain your users' data in the event of a crash is a small price to pay.

Was this article helpful?

0 0

Post a comment