Recipe 7.5. Preserving Information Across Multiple Requests for a Page


Problem

You have a page that contains complex object information you need to preserve between requests for the page. The data contains information you want to be unreadable in the rendered HTML, and you do not want to use a database to preserve the information.

Solution

Use the ViewState property of the Page object to store the data. You can access the data when the page is submitted back to the server.

In the code-behind class for the page, use the .NET language of your choice to add all the code necessary to handle the storage and recovery of the object data to and from the ViewState.

In a separate class file, use the .NET language of your choice to define the container in which you will store the data in the ViewState.

The application that illustrates this solution is shown in Examples 7-16, 7-17, 7-18, 7-19 through 7-20. Example 7-16 shows the .aspx file. Examples 7-17 and 7-18 show the VB and C# code-behind files. Examples 7-19 and 7-20 show the VB and C# data service class. Figure 7-4 shows the form produced by the application.

Discussion

The ViewState is an object similar to the Application and Session objects discussed in the previous recipes; however, its method of data storage is different. Unlike the Application and Session objects, which are stored in server memory, the ViewState is stored in a hidden form field within the HTML sent to the browser. This property lets you store page state information directly in a page and then retrieve it when the page is posted back to the server without using server resources. This technique does result, however, in additional data being transmitted to and from the server.

Figure 7-4. Maintaining page state with ViewState


ASP.NET uses the ViewState to store state information for the server controls on your form so it can rehydrate (or deserialize the data for) the controls upon submittal of the page to the server. You can use the ViewState for storing page state data in your application as well. What we mean by "page state data" in this context is user-specific state values not stored by a control. Values are tracked in ViewState similarly to how they are tracked in Session (described in Recipe 7.2) and Cache (described in Recipe 16.7).

An example of when you might want to use ViewState in this way is when you want to display a list of items in a DataGrid, and each user wants to sort the DataGrid's columns differently. In this context, the sort order is a small piece of user-specific page state that you want to maintain when the page is submitted back to the server. ViewState is a fine place to store this type of value, and the Visual Studio help files are replete with examples of this sort.

The example we've written to illustrate this solution is more ambitious than the previous example, fairly long, but worth the effort. It demonstrates the ability to store complex objects in the ViewState for tracking state information between page submittals and how to emulate the two-way data binding available with the GridView control but not available with the DataGrid control. When used together, these two concepts provide the ability to use many of the features of ASP.NET, which can simplify the code required to develop an application.

If you find yourself using the DataGrid because it's the best choice for your application, this recipe will help you implement two-way data binding with it. The GridView, however, inherently supports two-way data binding.


The .aspx file, shown in Example 7-16, is typical of a page containing a data-bound DataGrid (see Chapter 2). The one difference in this example is the use of constants from the data service class to define the fields bound to the columns in the DataGrid. The constants are described later, during the discussion of the data service class.

In Example 7-16, the following change is required to use the .aspx file with C#:

  • Change the namespace in the imports statement to ASPNetCookbook. CSExamples.


You'll find all code that handles the persistence and recovery of the object data you store in the ViewState in the code-behind shown in Examples 7-17 (VB) and 7-18 (C#).

The data service class, shown in Examples 7-19 (VB) and 7-20 (C#), provides a container for persisting the data in the ViewState. (The data service class is described at the end of this example.)

Because you will want to access the object persisted in the ViewState from multiple places in your code, we've defined a constant in the code-behind, VS_TEST_DATA, to define the name of the variable used to access the object in the ViewState. With this approach, you avoid the problems when you hardcode a variable name throughout your code.

In the Page_Load method of the code-behind, an instance of the data service class is created by calling its constructor. The new object is passed to the bindData method to bind the data in the object to the DataGrid in the .aspx file.

Create the new object only when the page is originally rendered. Creating it on subsequent postbacks would result in loss of the data entered by the user.


The bindData method performs two operations. First, it binds the data in the passed testData object to the DataGrid. This is done by setting the DataSource to the table in the DataSet of the passed object and calling the BindData method of the DataGrid. In addition, the DataKeyField is set to the field in the table that contains the primary key data. This provides the unique identifier for each row of test data in the rendered DataGrid and is needed to update the data submitted back to the server. The bindData method then persists the passed object to the ViewState. This causes the testData object to be serialized to a string and placed in the ViewState when the page is rendered.

When a page is rendered and sent to the client browser, all objects created in the code-behind are destroyed. This means the testData object no longer exists after the page is rendered unless you have persisted it. This is where data binding in web applications differs from data binding in Windows applications. In a Windows application, the underlying DataSet, DataTable, or other data container bound to the controls on the Windows form continues to exist and remains connected to the bound controls. Any changes made to the data in the bound controls are updated in the underlying data container, making updates to the original data source simple. In web forms, the connection to the underlying data container is broken when the page is rendered. Emulating the two-way binding and data updates available in Windows applications requires a bit of additional work, but it can be well worth the effort. (Again, our focus here assumes the bound control is a DataGrid. The GridView inherently supports this capability.)


When the user clicks the Update button, the form is submitted back to the server. ASP.NET takes care of updating the DataGrid server control with the data posted back to the server. However, the underlying data container (the testData object in this example) is not recreated by ASP.NET. Therefore, the testData object is rehydrated from the ViewState in the Update button click event.

After rehydrating the testData object, the contents of the object need to be updated with the current data in the DataGrid. This is done by iterating through the rows in the grid, extracting the individual data values, and updating the contents of the testData object.

For each row, the primary key value is obtained from the DataKeys collection for the current item. This is possible because the DataKeyField was set to the column containing the primary key when the DataGrid was originally bound.

Next, a reference is obtained to the first grade score text box. This is done by using the FindControl method of the current DataGrid item. This is possible because the text boxes defined in the DataGrid have been assigned IDs used here to perform the lookup. After the ID has been retrieved, the first grade score is updated in the testData object with the value in the text box. This process is repeated for the second grade score text box.

Production code should have validation to ensure that only numeric values are entered in the text box. This is best done using validation controls (see Chapter 3) or a custom control that allows only numeric entry, as described in Recipe 6.5.


After updating the contents of the object, the update method is called to update the contents of the database with the data in the object, and the data is again bound to the DataGrid.

The CH07TestDataVB class (see Examples 7-19 for the VB version and 7-20 for the C# version) provides the data services for this example. It encapsulates the data along with the methods for operating on the data. The class is defined with the Serializable attribute to provide the ability to serialize the data in the object created from the class to a string, which can then be stored in the ViewState or another location, such as a database. This string can then be deserialized to rehydrate the original object.

The class is designed to contain a DataSet as the container for the object data. This DataSet provides the ability to bind a DataGrid or another control directly to the data in the object. To bind to the internal data, two things are required. First, a property (the read-only testData property) must be provided to obtain a reference to the data table that contains the data.

Second, the names of the columns in the data table used for binding must be made available to bind controls to the specific data elements. These are defined as public constants in the class to provide a loose coupling between the code-behind and the data services class. By using the constants, the names of the columns can change without affecting any of the code that uses the CH07TestDataVB class.

In this example, the constructor for the class queries the database for the test data and fills the private member mTestData. The only special operation performed is to define the data column that is the primary key for the table in the DataSet. This makes it possible to find a specific row using the primary key value.

If the primary key is not defined for a table in the DataSet, the code will be required to filter the data in the table using a DataView or to iterate through all of the rows in the data table to find the row of interest. Both of these approaches can penalize performance.


Two properties are defined to set the first and second grade scores. Both of these properties perform the same actions but on different columns in the data table. To set a value, the appropriate row must be located. This is done by using the Find method of the row collection with the testID (primary key) value passed to the property. The find operation will only work if a primary key is defined for the table. After finding the row matching the passed testID, the value is set to the passed score.

When all data has been changed, as required in the object, the Update method is called. This method updates the data from the object to the database. It utilizes the functionality in ADO.NET that will, with a few lines of code, perform all inserts, updates, and deletes required to match the data in the database with the data in the data table. This basically requires four steps:

  1. Open a connection to the database. This is the same process used in the constructor.

  2. Create a new data adapter using the same Select statement used to populate the data table originally.

    All of the columns currently contained in the data table must be included in the Select statement. For this reason, it is good to define the Select statement as a constant or a private member variable to allow the constructor and Update methods to use the same Select statement, as shown in the following code:

     

    da = New OleDbDataAdapter(CMD_TEXT, _ dbConn)

    da = new OleDbDataAdapter(CMD_TEXT, dbConn);


  3. Create a new command builder with a reference to the data adapter created in step 2. The command builder will build the appropriate insert, update, and delete commands from the provided Select command.

  4. Call the Update method of the data adapter. This will perform all required inserts, updates, and deletes required to cause the data in the database to match the data in the data table.

The update works because every row in a data table has a status property that indicates if the row in the data table has been modified, added, or deleted. From this status information, the data adapter can determine what actions are required.


This example does not provide the ability to add new tests or delete current tests. You can easily add the functionality to the CH07TestDataVB class by adding two methods: addTest and deleteTest. Your addTest method needs to be passed the test name, its maximum score, and the scores for first and second grade. With the passed data, it should add a new row to the data table containing the test data. Likewise, your deleteTest method should delete the required row from the data table using the Delete method of the rows collection. The Delete method does not delete the row but marks it for deletion when the update is performed.

Though the technique described in this example is powerful and useful, you should use it carefully. Placing a serialized object in the ViewState can increase the size of the information sent to the client browser, and, because the ViewState information is stored in a hidden form field, it is sent back to the server when the page is submitted. In most cases, this doesn't matter, because an extra few thousand bytes is not a problem. However, if you have a large object, the overhead could be excessive. One way to use this technique with a large object is to store the object in the Session object instead of in the ViewState. The trade-off is the server resources and time required to transmit the data to the Session object. Refer to Recipe 7.2 for information on using the Session object.


See Also

Recipes 6.5, 7.2, and 16.6

Example 7-16. Maintaining page state using the ViewState (.aspx)

 <%@ Page Language="VB" MasterPageFile="~/ASPNetCookbookVB.master" AutoEventWireup="false" CodeFile="CH07ViewStateVB.aspx.vb" Inherits="ASPNetCookbook.VBExamples.CH07ViewStateVB" Title="ViewState Persistence" %> <%@ Import Namespace="ASPNetCookbook.VBExamples" %> <asp:Content  runat="server" ContentPlaceHolder> <div align="center" > Maintaining Page State With The ViewState (VB) </div> <table width="90%" align="center" border="0"> <tr> <td align="center"> <asp:DataGrid  Runat="server"  Width="100%"  AutoGenerateColumns="False"  BorderColor="000080"  BorderWidth="2px"  HeaderStyle-BackColor="#000080"  HeaderStyle-Css  ItemStyle-Css  ItemStyle-BackColor="#FFFFFF" > <Columns> <asp:TemplateColumn HeaderStyle-HorizontalAlign="Center"    HeaderText="Test Name"> <ItemTemplate> <%#Eval(CH07TestDataVB.TEST_NAME)%> </ItemTemplate> </asp:TemplateColumn> <asp:TemplateColumn HeaderStyle-HorizontalAlign="Center"    ItemStyle-HorizontalAlign="Center"    HeaderText="Max Score"> <ItemTemplate> <%#Eval(CH07TestDataVB.MAX_SCORE)%> </ItemTemplate> </asp:TemplateColumn> <asp:TemplateColumn HeaderStyle-HorizontalAlign="Center"    ItemStyle-HorizontalAlign="Center"    HeaderText="First Grade<br />Passing Score"> <ItemTemplate> <asp:TextBox  runat="server" Columns="5" text='<%# Eval(CH07TestDataVB.FIRST_GRADE_PASSING_SCORE) %>' /> </ItemTemplate> </asp:TemplateColumn> <asp:TemplateColumn HeaderStyle-HorizontalAlign="Center"    ItemStyle-HorizontalAlign="Center"    HeaderText="Second Grade<br />Passing Score"> <ItemTemplate> <asp:TextBox  runat="server" Columns="5" text='<%# Eval(CH07TestDataVB.SECOND_GRADE_PASSING_SCORE) %>' /> </ItemTemplate> </asp:TemplateColumn> </Columns> </asp:DataGrid> </td> </tr> <tr> <td align="center"> <br /> <asp:Button  runat="server"    Text="Update"    OnClick="btnUpdate_Click" /> <asp:Button  runat="server"    Text="Cancel"    OnClick="btnCancel_Click" /> </td> </tr> </table> </asp:Content> 

Example 7-17. Maintaining page state using the ViewState code-behind (.vb)

 Option Explicit On Option Strict On Namespace ASPNetCookbook.VBExamples ''' <summary> ''' This class provides the code behind for ''' CH07ViewStateVB.aspx ''' </summary> Partial Class CH07ViewStateVB Inherits System.Web.UI.Page 'the following constant defines the name of the viewstate variable used 'to store the test data object Private Const VS_TEST_DATA As String = "TestData" '''*********************************************************************** ''' <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 testData As CH07TestDataVB If (Not Page.IsPostBack()) Then 'create new test data object and bind to it testData = New CH07TestDataVB bindData(testData) End If End Sub 'Page_Load '''*********************************************************************** ''' <summary> ''' This routine provides the event handler for the update button click ''' event event. It is responsible for updating the contents of the ''' database with the data from the form. ''' </summary> ''' ''' <param name="sender">Set to the sender of the event</param> ''' <param name="e">Set to the event arguments</param> Protected Sub btnUpdate_Click(ByVal sender As Object, _  ByVal e As System.EventArgs) 'the following constants define the names of the textboxes in the 'datagrid rows Const FIRST_GRADE_SCORE_TEXTBOX As String = "txtFirstGradeScore" Const SECOND_GRADE_SCORE_TEXTBOX As String = "txtSecondGradeScore" Dim testData As CH07TestDataVB Dim item As System.Web.UI.WebControls.DataGridItem Dim txtScore As TextBox Dim testID As Integer 'make sure page contents are valid If (Page.IsValid) Then 'rehydrate the test data object from the viewstate testData = CType(ViewState.Item(VS_TEST_DATA), _  CH07TestDataVB) 'copy the contents of the fields in the datagrid to the test data 'object to emulate the two-way databinding in the Windows world For Each item In dgScores.Items 'get the testID for the test data in the datagrid row testID = CInt(dgScores.DataKeys.Item(item.ItemIndex)) 'get a reference to the first grade score textbox in the row txtScore = CType(item.FindControl(FIRST_GRADE_SCORE_TEXTBOX), _   TextBox) 'update the first grade score in the test data object testData.firstGradeScore(testID) = CInt(txtScore.Text) 'get a reference to the second grade score textbox in the row txtScore = CType(item.FindControl(SECOND_GRADE_SCORE_TEXTBOX), _  TextBox) 'update the first grade score in the test data object testData.secondGradeScore(testID) = CInt(txtScore.Text) Next item 'update the test data in the database testData.update() 'rebind the data to the datagrid bindData(testData) End If End Sub 'btnUpdate_Click '''*********************************************************************** ''' <summary> ''' This routine provides the event handler for the cancel button click ''' event event. It is responsible for cancel the current edits. ''' </summary> ''' ''' <param name="sender">Set to the sender of the event</param> ''' <param name="e">Set to the event arguments</param> Protected Sub btnCancel_Click(ByVal sender As Object, _   ByVal e As System.EventArgs) 'perform the actions required to cancel the edits End Sub 'btnCancel_Click '''*********************************************************************** ''' <summary> ''' This routine binds the data in the passed object to the datagrid then ''' persists the object in the viewstate ''' </summary> ''' ''' <param name="testData">Set to the test data to bind to the datagrid ''' on the form ''' </param> Private Sub bindData(ByVal testData As CH07TestDataVB) 'bind the test data to the datagrid dgScores.DataSource = testData.testData() dgScores.DataKeyField = testData.TEST_DATA_ID dgScores.DataBind() 'save the test data object in the view state ViewState.Add(VS_TEST_DATA, _   testData) End Sub 'bindData End Class 'CH07ViewStateVB End Namespace 

Example 7-18. Maintaining page state using the ViewState code-behind (.cs)

 using System; using System.Web.UI.WebControls; namespace ASPNetCookbook.CSExamples { /// <summary> /// This class provides the code behind for /// CH07ViewStateCS.aspx /// </summary> public partial class CH07ViewStateCS : System.Web.UI.Page { // the following constant defines the name of the viewstate variable used // to store the test data object private const String VS_TEST_DATA = "TestData"; ///*********************************************************************** /// <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> protected void Page_Load(object sender, EventArgs e) { CH07TestDataCS testData = null; if (!Page.IsPostBack) { // create new test data object and bind to it testData = new CH07TestDataCS(); bindData(testData); } } // Page_Load ///*********************************************************************** /// <summary> /// This routine provides the event handler for the update button click /// event event. It is responsible for updating the contents of the /// database with the data from the form. /// </summary> /// /// <param name="sender">Set to the sender of the event</param> /// <param name="e">Set to the event arguments</param> protected void btnUpdate_Click(object sender, EventArgs e) { // the following constants define the names of the textboxes in the // datagrid rows const String FIRST_GRADE_SCORE_TEXTBOX = "txtFirstGradeScore"; const string SECOND_GRADE_SCORE_TEXTBOX = "txtSecondGradeScore"; CH07TestDataCS testData = null; TextBox txtScore = null; int testID; // make sure page contents are valid if (Page.IsValid) { // rehydrate the test data object from the viewstate testData = (CH07TestDataCS)(ViewState[VS_TEST_DATA]); // copy the contents of the fields in the datagrid to the test data // object to emulate the two-way databinding in the Windows world foreach (DataGridItem item in dgScores.Items) { // get the testID for the test data in the datagrid row testID = Convert.ToInt32(dgScores.DataKeys[item.ItemIndex]); //get a reference to the first grade score textbox in the row txtScore = (TextBox)(item.FindControl(FIRST_GRADE_SCORE_TEXTBOX)); // update the first grade score in the test data object testData.set_firstGradeScore(testID,  Convert.ToInt32(txtScore.Text)); // get a reference to the second grade score textbox in the row txtScore = (TextBox)(item.FindControl(SECOND_GRADE_SCORE_TEXTBOX)); // update the first grade score in the test data object testData.set_secondGradeScore(testID,   Convert.ToInt32(txtScore.Text)); } // foreach // update the test data in the database testData.update(); // rebind the data to the datagrid bindData(testData); } // if (Page.IsValid) } // btnUpdate_Click ///*********************************************************************** /// <summary> /// This routine provides the event handler for the cancel button click /// event event. It is responsible for cancel the current edits. /// </summary> /// /// <param name="sender">Set to the sender of the event</param> /// <param name="e">Set to the event arguments</param> protected void btnCancel_Click(object sender, EventArgs e) { // perform the actions required to cancel the edits } // btnCancel_Click ///*********************************************************************** /// <summary> /// This routine binds the data in the passed object to the datagrid then /// persists the object in the viewstate /// </summary> /// /// <param name="testData">Set to the test data to bind to the datagrid /// on the form /// </param> private void bindData(CH07TestDataCS testData) { // bind the test data to the datagrid dgScores.DataSource = testData.testData; dgScores.DataKeyField = CH07TestDataCS.TEST_DATA_ID; dgScores.DataBind(); // save the test data object in the view state ViewState.Add(VS_TEST_DATA,   testData); } // bindData } // CH07ViewStateCS } 

Example 7-19. Data service class for storage in the ViewState (.vb)

 Option Explicit On Option Strict On Imports System Imports System.Configuration.ConfigurationManager Imports System.Data Imports System.Data.OleDb Namespace ASPNetCookbook.VBExamples ''' <summary> ''' This class provides an encapsulation of test data and properties/method ''' to operate on the data. ''' ''' NOTE: This class is marked as serializable to provide the ability to '''   serialize the objects created with the class to an XML string. ''' </summary> <Serializable()> _ Public Class CH07TestDataVB 'constants used to bind the data in the encapsulated dataset Public Const TEST_DATA_ID As String = "TestDataID" Public Const TEST_NAME As String = "TestName" Public Const FIRST_GRADE_PASSING_SCORE As String = "FirstGradePassingScore" Public Const SECOND_GRADE_PASSING_SCORE As String = "SecondGradePassingScore" Public Const MAX_SCORE As String = "MaxScore" 'constant to provide the name of the table in the dataset Private Const TEST_DATA_TABLE As String = "TestData" 'private attributes Private mTestData As DataSet Private mConnectionStr As String 'the following constant is used to query the data from the database Private Const CMD_TEXT As String = "SELECT " & TEST_DATA_ID & "," & _    TEST_NAME & "," & _    FIRST_GRADE_PASSING_SCORE & "," & _    SECOND_GRADE_PASSING_SCORE & "," & _    MAX_SCORE & _    " FROM " & TEST_DATA_TABLE '''*********************************************************************** ''' <summary> ''' This property provides the ability to get a reference to the table ''' in the dataset containing the test data. ''' </summary> Public ReadOnly Property testData() As DataTable Get Return (mTestData.Tables(TEST_DATA_TABLE)) End Get End Property 'testData '''*********************************************************************** ''' <summary> ''' This property provides the ability to get/set the first grade score ''' for the passed test ID. ''' </summary> Public Property firstGradeScore(ByVal testID As Integer) As Integer Get Dim dRow As DataRow 'get row with the passed testID value dRow = mTestData.Tables(TEST_DATA_TABLE).Rows.Find(testID) 'return the first grade passing score Return (CInt(dRow.Item(FIRST_GRADE_PASSING_SCORE))) End Get Set(ByVal Value As Integer) Dim dRow As DataRow 'get row with the passed testID value dRow = mTestData.Tables(TEST_DATA_TABLE).Rows.Find(testID) 'set the first grade passing score dRow.Item(FIRST_GRADE_PASSING_SCORE) = Value End Set End Property 'firstGradeScore '''*********************************************************************** ''' <summary> ''' This property provides the ability to get/set the second grade score ''' for the passed test ID. ''' </summary> Public Property secondGradeScore(ByVal testID As Integer) As Integer Get Dim dRow As DataRow 'get row with the passed testID value dRow = mTestData.Tables(TEST_DATA_TABLE).Rows.Find(testID) 'return the first grade passing score Return CInt((dRow.Item(SECOND_GRADE_PASSING_SCORE))) End Get Set(ByVal Value As Integer) Dim dRow As DataRow 'get row with the passed testID value dRow = mTestData.Tables(TEST_DATA_TABLE).Rows.Find(testID) 'set the first grade passing score dRow.Item(SECOND_GRADE_PASSING_SCORE) = Value End Set End Property 'secondGradeScore '''*********************************************************************** ''' <summary> ''' This routine provides the ability to update the test data for this ''' object in the database. ''' </summary> Public Sub update() Dim dbConn As OleDbConnection = Nothing Dim da As OleDbDataAdapter = Nothing Dim cmdBuilder As OleDbCommandBuilder = Nothing Try dbConn = New OleDbConnection(mConnectionStr) dbConn.Open() da = New OleDbDataAdapter(CMD_TEXT, _   dbConn) 'create a command builder which will create the appropriate update, 'insert, and delete SQL statements cmdBuilder = New OleDbCommandBuilder(da) 'update data in the testdata table da.Update(mTestData, _   TEST_DATA_TABLE) Finally 'cleanup If (Not IsNothing(dbConn)) Then dbConn.Close() End If End Try End Sub 'update '''*********************************************************************** ''' <summary> ''' This constructor creates the object and populates it with test data ''' from the database ''' </summary> Public Sub New() Dim dbConn As OleDbConnection = Nothing Dim da As OleDbDataAdapter = Nothing Dim key(0) As DataColumn Try 'get the connection string from web.config and open a connection 'to the database mConnectionStr = _ ConnectionStrings("dbConnectionString").ConnectionString dbConn = New OleDbConnection(mConnectionStr) dbConn.Open() 'get the data from the database da = New OleDbDataAdapter(CMD_TEXT, _   dbConn) mTestData = New DataSet da.Fill(mTestData, _ TEST_DATA_TABLE) 'define the testID column in the data table as a primary key column 'this makes it possible to "lookup" a datarow with the testID value 'NOTE: The PrimaryKey property expects an array of DataColumn even '    when only one column is used as the primary key key(0) = mTestData.Tables(TEST_DATA_TABLE).Columns(TEST_DATA_ID) mTestData.Tables(TEST_DATA_TABLE).PrimaryKey = key Finally 'cleanup If (Not IsNothing(dbConn)) Then dbConn.Close() End If End Try End Sub 'New End Class 'CH07TestDataVB End Namespace 

Example 7-20. Data service class for storage in the ViewState (.cs)

 using System; using System.Configuration; using System.Data; using System.Data.OleDb; namespace ASPNetCookbook.CSExamples { /// <summary> /// This class provides an encapsulation of test data and properties/method /// to operate on the data. /// /// NOTE: This class is marked as serializable to provide the ability to ///   serialize the objects created with the class to an XML string. /// </summary> [Serializable] public class CH07TestDataCS { // constants used to bind the data in the encapsulated dataset public const String TEST_DATA_ID = "TestDataID"; public const String TEST_NAME = "TestName"; public const String FIRST_GRADE_PASSING_SCORE = "FirstGradePassingScore"; public const String SECOND_GRADE_PASSING_SCORE = "SecondGradePassingScore"; public const String MAX_SCORE = "MaxScore"; // constant to provide the name of the table in the dataset private const String TEST_DATA_TABLE = "TestData"; // private attributes private DataSet mTestData = null; private String mConnectionStr = null; // the following constant is used to query the data from the database private const String CMD_TEXT = "SELECT " + TEST_DATA_ID + "," + TEST_NAME + "," + FIRST_GRADE_PASSING_SCORE + "," + SECOND_GRADE_PASSING_SCORE + "," + MAX_SCORE + " FROM " + TEST_DATA_TABLE; ///*********************************************************************** /// <summary> /// This property provides the ability to get a reference to the table /// in the dataset containing the test data. /// </summary> public DataTable testData { get { return (mTestData.Tables[TEST_DATA_TABLE]); } } // testData ///*********************************************************************** /// <summary> /// This routine provides the ability to set the first grade score for /// the passed test ID. /// </summary> /// /// <param name="testID">Set to the ID of the test</param> /// <param name="score">Set to the test score</param> public void set_firstGradeScore(int testID, int score) { DataRow dRow = null; // get row with the passed testID value dRow = mTestData.Tables[TEST_DATA_TABLE].Rows.Find(testID); // set the first grade passing score dRow[FIRST_GRADE_PASSING_SCORE] = score; } // set_firstGradeScore ///*********************************************************************** /// <summary> /// This routine provides the ability to set the second grade score for /// the passed test ID. /// </summary> /// /// <param name="testID">Set to the ID of the test</param> /// <param name="score">Set to the test score</param> public void set_secondGradeScore(int testID, int score) { DataRow dRow = null; // get row with the passed testID value dRow = mTestData.Tables[TEST_DATA_TABLE].Rows.Find(testID); // set the second grade passing score dRow[SECOND_GRADE_PASSING_SCORE] = score; } // set_secondGradeScore ///*********************************************************************** /// <summary> /// This routine provides the ability to update the test data for this /// object in the database. /// </summary> public void update() { OleDbConnection dbConn = null; OleDbDataAdapter da = null; OleDbCommandBuilder cmdBuilder = null; try { dbConn = new OleDbConnection(mConnectionStr); dbConn.Open(); da = new OleDbDataAdapter(CMD_TEXT, dbConn); // create a command builder which will create the appropriate update, // insert, and delete SQL statements cmdBuilder = new OleDbCommandBuilder(da); // update data in the testdata table da.Update(mTestData,   TEST_DATA_TABLE); } finally { // cleanup if (dbConn != null) { dbConn.Close(); } } // finally } // update ///*********************************************************************** /// <summary> /// This constructor creates the object and populates it with test data /// from the database /// </summary> public CH07TestDataCS() { OleDbConnection dbConn = null; OleDbDataAdapter da = null; DataColumn[] key = new DataColumn[1]; try { // get the connection string from web.config and open a connection // to the database mConnectionStr = ConfigurationManager. ConnectionStrings["dbConnectionString"].ConnectionString; dbConn = new OleDbConnection(mConnectionStr); dbConn.Open(); // get the data from the database da = new OleDbDataAdapter(CMD_TEXT,   dbConn); mTestData = new DataSet(); da.Fill(mTestData, TEST_DATA_TABLE); // define the testID column in the data table as a primary key column // this makes it possible to "lookup" a datarow with the testID value // NOTE: The PrimaryKey property expects an array of DataColumn even //  when only one column is used as the primary key key[0] = mTestData.Tables[TEST_DATA_TABLE].Columns[TEST_DATA_ID]; mTestData.Tables[TEST_DATA_TABLE].PrimaryKey = key; } // try finally { // cleanup if (dbConn != null) { dbConn.Close(); } } // finally } // CH07TestDataCS } // CH07TestDataCS } 



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