JavaScript Editor Javascript validator     Javascripts

Main Page


Previous Section Next Section

3.8 Comparing ASP.NET to ASP

Classic ASP is not event driven in the way that ASP.NET is. To see the difference, consider the following application: you want to open the NorthWind database, supplied with both Microsoft SQL Server and Microsoft Access, and read through the Customers table. For each customer, you want to display the company name, customer ID, the name and title of the contact person, and the phone number. If the contact person is the owner, you want to display the title in red so that it is easy to see.

This example contains a great deal of complexity that will be covered in future chapters, including all the issues surrounding database access, but the fundamentals are straightforward. In classic ASP you would open a connection to the database, perform a query, and get back a RecordSet. You then iterate over the RecordSet, adding each record to an HTML table. If the current record's ContactTitle column is "Owner," you set the display to red. The code to accomplish this in classic ASP is shown in Example 3-3.

Example 3-3. Populating a table in classic ASP
<% Response.Expires=0 %>
<HTML>
<HEAD>
<META NAME="GENERATOR" Content="Microsoft FrontPage 4.0">
<META HTTP-EQUIV="Content-Type" content="text/html; charset=utf-8">
<TITLE>List Log</TITLE>
<STYLE>
BODY,TD, TH {font-family:Verdana;font-size:8pt}
.controls {font-family:Verdana;font-size:8pt}
#owner {color:red}
</STYLE>
</HEAD>
<BODY>
<%   

   dim DBConn, rs
   set DBConn = Server.CreateObject("ADODB.Connection")

   DBConn.open "Driver={SQL Server};server=YourServer; uid=sa; pwd=YourPw;
                 database=northwind;"
   
   set rs = DBConn.Execute("select * from Customers")
   
%>
   <table bgcolor = "lavender">
      <tr>
         <th>Company Name</th>
         <th>Customer ID</th>
         <th>Contact</th>
         <th>Title</th>
         <th>Phone</th>
      </tr>
   <% while not rs.eof %>
      <tr bgColor="lightsteelblue">
         <td><% =rs("CompanyName") %></td>
         <td><% =rs("CustomerID") %> </td>
         <td><%=rs("ContactName") %></td>
         <td 
            <% if rs("ContactTitle") = "Owner" then %>
            id = owner
            <% end if %>
            > <% = rs("ContactTitle") %> </td>
         <td><%=rs("Phone") %></td>
      </tr>

   <% 
      rs.moveNext
       wend 
   %>
   </Table>

In Example 3-3, as with all classic ASP applications, the HTML is intermingled with the script code. You add all the records in a while loop:

<% while not rs.eof %>

When it is time to create the <td> tag for the title, place the if statement, which tests if the ContactTitle is an Owner, inside the code for writing the tag:

<td 
    <% if rs("ContactTitle") = "Owner" then %>
    id = owner
    <% end if %>
    >

The logic here is to open the <td> tag, then switch to script that tests the value of the ContactTitle field for the current row. If it matches Owner, you then set the id attribute; otherwise you do not. You then close the <td> tag.

The code is a bit tangled, but it certainly works, as shown in Figure 3-1.

Figure 3-1. ASP version of event-driven data table
figs/pan2_0301.gif

To write this same application in ASP.NET, you would take a very different approach. First, to make this demonstration easier, you'll use a DataGrid rather than a table. Here are the steps:

  1. Open Visual Studio .NET and create a new ASP.NET web application project using either VB.NET or C#. Name it EventDrivenGrid.

  2. Right-click on the page and choose Properties. Set the Page Layout to FlowLayout and click OK.

  3. Drag a DataGrid onto the form from the Toolbar and widen it. Set the grid's ID to dgCustomers.

  4. Right-click on the page and choose View Code.

  5. If you are using C#, at the top of the code page add:

    using System.Data.SqlClient;

    or, if you are using VB.NET, at the top of the code page add:

    imports System.Data.SqlClient
  6. Modify the Page_Load event by adding the code shown in Example 3-4 for a VB.NET project or the code shown in Example 3-5 for a C# project.

    There are many details to the code in Example 3-4 and Example 3-5 that will be explained in future chapters. The essence is that you are retrieving the data you need from the database into a DataSet and then binding the appropriate table from the DataSet to the DataGrid.

    Example 3-4. Populating a table in ASP.NET using VB.NET
    Private Sub Page_Load(ByVal sender As System.Object, _
                          ByVal e As System.EventArgs) _
                          Handles MyBase.Load
       'Put user code to initialize the page here
       if not IsPostBack then
          '  create the connection string
          dim strConnection as String = _
             "server=YourServer; uid=sa; pwd=YourPw; database=northwind"
    
          '  create the command string
          dim strCommand as String = _
             "select * from customers"
    
          '  create the dataset command object and dataset
          dim dataAdapter as new SqlDataAdapter(strCommand, strConnection)
          dim ds as New DataSet(  )
    
          '  fill the dataset
          dataAdapter.Fill(ds, "Customers")
          dim bldr as New SqlCommandBuilder(dataAdapter)
    
          '  get the table
          dim dt as DataTable = ds.Tables(0)
          dgCustomers.DataSource = dt
          dgCustomers.DataBind(  )
       End If
    End Sub
    Example 3-5. Populating a table in ASP.NET using C#
    private void Page_Load(Object sender, System.EventArgs e)
    {
    if (!IsPostBack)
       {
          // create the connection string
          string strConnection = 
             "server=YourServer; uid=sa; pwd=YourPW; database=northwind";
    
          // create the command string
          string strCommand = "Select * from Customers";
    
          // create the data set command object and dataset
          SqlDataAdapter dataAdapter = 
             new SqlDataAdapter(strCommand, strConnection);
          DataSet dataSet = new DataSet(  );
    
          // fill the dataset 
          dataAdapter.Fill(dataSet,"Customers");
          SqlCommandBuilder bldr = new SqlCommandBuilder(dataAdapter);
    
          // get the table
          DataTable dataTable = dataSet.Tables[0];
          dgCustomers.DataSource = dataTable;
          dgCustomers.DataBind(  );
       }
    }
  7. Return to the Designer and click on the HTML tab. Add these attributes to the DataGrid:

    HeaderStyle-BackColor="Yellow"
    BorderWidth ="5" 
    BorderColor ="#000099" 
    AlternatingItemStyle-BackColor="LightGray" 
    HeaderStyle-Font-Bold="True" 
    AutoGenerateColumns="False"
  8. Add Columns and BoundColumn elements to the DataGrid:

    <Columns>
       <asp:BoundColumn DataField ="CompanyName" HeaderText="Company Name" />
       <asp:BoundColumn DataField ="ContactName" HeaderText="Contact" />
       <asp:BoundColumn DataField ="ContactTitle" HeaderText="Title" />
       <asp:BoundColumn DataField ="Phone" HeaderText="Phone" />
    </Columns>

The complete DataGrid declaration should look something like Example 3-6.

Example 3-6. DataGrid HTML
<asp:DataGrid 
   id="dgCustomers" 
   runat="server" 
   Width="466px" 
   Height="278px"
   HeaderStyle-BackColor="Yellow"
   BorderWidth="5"
   BorderColor="#000099"
   AlternatingItemStyle-BackColor="LightGray"
   HeaderStyle-Font-Bold="True"
   AutoGenerateColumns="False"  >
   <Columns>
      <asp:BoundColumn HeaderText="Company Name" 
            DataField="CompanyName"></asp:BoundColumn>
      <asp:BoundColumn HeaderText="Contact" 
            DataField="ContactName"></asp:BoundColumn>
      <asp:BoundColumn HeaderText="Title" 
            DataField="ContactTitle"></asp:BoundColumn>
      <asp:BoundColumn HeaderText="Phone" 
            DataField="Phone"></asp:BoundColumn>
   </Columns>
</asp:DataGrid>

Run the application. You have a DataGrid populated by the data in the Customer's table, as shown in Figure 3-2.

Figure 3-2. DataGrid populated without events
figs/pan2_0302.gif

You've populated the table very nicely, but you have not set the Owner to be red. How can you, if you are not iterating over the data at any time? You are simply handing the table to the grid and telling the grid to bind to the data.

The DataGrid publishes a number of useful events that you can choose to handle. In this case, the event you care about is the ItemDataBound event that is raised every time an item is bound to the grid. You should write a handler for this event that will give you the opportunity to examine the data and decide if you need to change the way it is displayed.

To do this, add an attribute to the DataGrid. Return to the Designer and click on the HTML tab. Add the following attribute to the DataGrid:

OnItemDataBound="OnItemDataBoundEventHandler"

You are now ready to implement the handler for that event. This is done using code you will add to the code page. You can get back to the code page by clicking on the tab labeled WebForm1.aspx.vb or WebForm1.aspx.cs, depending on the language you are using.

There is extensive support in the IDE for managing events. This will be shown shortly.

The event handler takes two parameters. One is an object that represents the object raising the event. The other is an object of type EventArgs (or a class derived from EventArgs) that provides useful objects to the event handler. In VB.NET, the event handler declaration looks like:

public sub OnItemDataBoundEventHandler(ByVal sender as System.Object, _
              ByVal e as System.Web.UI.WebControls.DataGridItemEventArgs)

In C#, it looks like:

public void OnItemDataBoundEventHandler(object sender,
              System.Web.UI.WebControls.DataGridItemEventArgs e)
{

In this case, the first thing to do is test whether the item that raised the event is a Header, Separator, or Footer. The DataGridItemEventArgs object has a property Item that returns the data item. You can ask that Item for its ItemType, which will be one of the enumerated ListItemType constants. You can check whether it is a Header, Separator, or Footer. If it is any of these types, you can return, since you don't want to process those items. In VB.NET, this is done with the following lines of code:

dim itemType as ListItemType = CType(e.Item.ItemType,ListItemType)
if (itemType = ListItemType.Header) or _
   (itemType = ListItemType.Separator) or _
   (itemType = ListItemType.Footer) then
   exit Sub
End If

In C#, this is done with this code snippet:

ListItemType itemType = (ListItemType) e.Item.ItemType;
if (itemType == ListItemType.Header ||
   itemType == ListItemType.Separator ||
   itemType == ListItemType.Footer)
   return;

Assuming you do not have a Header, Separator, or Footer, you are ready to get the DataItem as a DataRowView. You can then index into that DataRowView using the name of the column (ContactTitle) to get the particular column you want. If you call ToString on that column, you get back the value of the column, which you can assign to a string variable. In VB.NET, the code is:

dim drv as DataRowView = CType(e.Item.DataItem,DataRowView)
dim title as String = drv("ContactTitle").ToString(  )

In C#, the code is:

DataRowView dataRowView = (DataRowView)e.Item.DataItem;
string title = dataRowView["contactTitle"].ToString(  );

You can combine these two lines into a single statement, if you like terser but harder to debug code, as in this C# code snippet:

string title = ((DataRowView)e.Item.DataItem)["ContactTitle"].ToString(  );

In any case, with the title in hand, you can compare it to the string "Owner." In VB.NET, this is done using:

if title = "Owner" then

In C#, this is done using:

if (title == "Owner")
{

If you get a match, you can extract the cell you want to color by asking the DataGridItemEventArgs object passed in as a parameter for the current Item. You can then index into the Controls collection of the Item to get the particular cell you care about. In VB.NET:

dim ownerCell as TableCell=CType(e.Item.Controls(2), TableCell)

In C#, the code is:

TableCell ownerCell = (TableCell)e.Item.Controls[2];

You can now set the foreground color of that cell to red by calling the static (or shared) FromName method on the Color class, passing in the string "Red." In VB.NET, the code is:

ownerCell.ForeColor = Color.FromName("Red")

In C#, the code is:

ownerCell.ForeColor = Color.FromName("Red");

The complete OnItemDataBoundEventHandler is shown in Example 3-7 using VB.NET and in Example 3-8 using C#.

Example 3-7. OnItemDataBoundEventHandler in VB.NET
public sub OnItemDataBoundEventHandler(ByVal sender as System.Object, _
              ByVal e as System.Web.UI.WebControls.DataGridItemEventArgs)
   dim itemType as ListItemType = CType(e.Item.ItemType,ListItemType)
   if (itemType = ListItemType.Header) or _
      (itemType = ListItemType.Separator) or _
      (itemType = ListItemType.Footer) then
      exit Sub
   End If

   dim drv as DataRowView = CType(e.Item.DataItem,DataRowView)
   dim title as String = drv("ContactTitle").ToString(  )
   if title = "Owner" then
      dim ownerCell as TableCell=CType(e.Item.Controls(2), TableCell)
      ownerCell.ForeColor = Color.FromName("Red")
   End If
End Sub
Example 3-8. OnItemDataBoundEventHandler in C#
public void OnItemDataBoundEventHandler(object sender,
                System.Web.UI.WebControls.DataGridItemEventArgs e)
{
   ListItemType itemType = (ListItemType) e.Item.ItemType;
   if (itemType == ListItemType.Header ||
      itemType == ListItemType.Separator ||
      itemType == ListItemType.Footer)
      return;

   DataRowView dataRowView = (DataRowView)e.Item.DataItem;
   string title = dataRowView["contactTitle"].ToString(  );
   if (title == "Owner")
   {
      TableCell ownerCell = (TableCell)e.Item.Controls[2];
      ownerCell.ForeColor = Color.FromName("Red");
   }
}

When the web page utilizing the event handler shown in either Example 3-7 or 3-8 is run, you get a web page similar to Figure 3-3. It is the same as the web page in Figure 3-2, except that all instances in which the Title is Owner are displayed in red. (Since your book is printed in black and white, you will have to actually run the project to see this.)

Figure 3-3. DataGrid populated with events
figs/pan2_0303.gif

The event-driven model as shown in this simple example isn't easier than the non-event driven model in ASP, but it does scale well. As programs become more complex, having a more object-oriented event-driven model makes for code that is easier to maintain.

    Previous Section Next Section


    JavaScript Editor Javascript validator     Javascripts 




    ©