Business Components

One of the purposes of creating code-behind files is to use them as business components, independing processing routines that are sharable among different pages. In this way, a generally useful processing routine does not have to be duplicated on all pages that need it; any page can inherit its class definition and take advantage of its processing. Therefore, the code-behind file needs to be independent of any page that uses it.

Component Sharing through Naming Conventions

One of the ways in which a code-behind file can be shared among multiple pages is to use common names for common controls. Imagine, for instance, that two ASP.NET pages require the same recordset from BooksDB.mdb; each page displays the recordset in a GridView. Rather than having to create two separate code-behind files for each of these pages, a single code-behind file can be used, assuming that the two GridViews have the same id. This is a necessary requirement since the code-behind recordset is bound to a particular id value.

The following code-behind file can be used as a general-purpose recordset retrieval function for the BooksDB.mdb Books table.

Imports System.Data.OleDb

Public Class DBClass
  Inherits Page

  Protected WithEvents DisplayGrid As GridView

  Sub Get_Data
    Dim DBConnection As OleDbConnection
    Dim DBCommand As OleDbCommand
    Dim DBReader As OleDbDataReader
    Dim SQLString As String
    DBConnection = New OleDbConnection( _
      "Provider=Microsoft.Jet.OLEDB.4.0;" & _
      "Data Source=" & Server.MapPath("../Databases/BooksDB.mdb"))
    DBConnection.Open()
    SQLString = "SELECT * FROM Books ORDER BY BookID"
    DBCommand = New OleDbCommand(SQLString, DBConnection)
    DBReader = DBCommand.ExecuteReader()
    DisplayGrid.DataSource = DBReader
    DisplayGrid.DataBind()
    DBReader.Close()
    DBConnection.Close()
  End Sub

End Class
Listing 11-6. DBClass.vb code-behind data access file.

The Get_Data subprogram retrieves all fields from all records in the table. Notice that the retrieved recordset is bound to a GridView with id="DisplayGrid".

Just because the full set of database fields have been retrieved does not mean that particular pages have to use them all. By using different <asp:BoundField> controls for their GridViews, different pages can display different outputs. The following code represent two ASP.NET pages, each of which imports the above code-behind class but which use the retrieved recordset for different display purposes.

IDTitle
DB111Oracle Database
DB222Databases in Depth
DB333Database Processing
DB444Access Database Design
DB555SQL Server 2005
GR111Adobe Photoshop CS2
GR222Learning Web Design
GR333Macromedia Flash Professional
GR444Digital Photographer Handbook
GR555Creating Motion Graphics
HW111How Computers Work
HW222Upgrading and Repairing PCs
HW333USB System Architecture
HW444Designing Embedded Hardware
HW555Contemporary Logic Design
SW111Java How to Program
SW222C Programming Language
SW333Programming C#
SW444Programming PHP
SW555Visual Basic.NET Programming
SY111Operating System Concepts
SY222The UNIX Operating System
SY333Windows Server 2003
SY444Linux in a Nutshell
SY555Mastering Active Directory
WB111Ajax in Action
WB222Professional ASP.NET 2.0
WB333Cascading Style Sheets
WB444DOM Scripting
WB555Microsoft ASP.NET 2.0
<%@ Page Inherits="DBClass"
  src="DBClass.vb" %>

<SCRIPT Runat="Server">

Sub Page_Load
  Get_Data
End Sub

</SCRIPT>


<html>
<body>
<form Runat="Server">

<asp:GridView id="DisplayGrid" Runat="Server"
  AutoGenerateColumns="False"
  ShowHeader="True"
  HeaderStyle-BackColor="#E0E0E0"
  HeaderStyle-Font-Bold="True"
  HeaderStyle-HorizontalAlign="Center"
>
  <Columns>

  <asp:BoundField
    DataField="BookID"
    HeaderText="ID"/>

  <asp:BoundField
    DataField="BookTitle"
    HeaderText="Title"/>

  </Columns>

</asp:GridView>

</form>
</body>
</html>
Figure 11-4. DBPage1.aspx - uses DBClass.vb code-behind data access file.


TitlePrice
Oracle Database$69.99
Databases in Depth$29.95
Database Processing$136.65
Access Database Design$34.95
SQL Server 2005$29.99
Adobe Photoshop CS2$29.99
Learning Web Design$39.95
Macromedia Flash Professional$44.99
Digital Photographer Handbook$24.95
Creating Motion Graphics$59.95
How Computers Work$29.99
Upgrading and Repairing PCs$59.99
USB System Architecture$49.99
Designing Embedded Hardware$44.95
Contemporary Logic Design$102.95
Java How to Program$98.59
C Programming Language$44.25
Programming C#$44.95
Programming PHP$39.95
Visual Basic.NET Programming$49.99
Operating System Concepts$95.75
The UNIX Operating System$19.95
Windows Server 2003$29.99
Linux in a Nutshell$44.95
Mastering Active Directory$49.99
Ajax in Action$22.67
Professional ASP.NET 2.0$32.99
Cascading Style Sheets$39.95
DOM Scripting$23.09
Microsoft ASP.NET 2.0$29.99
<%@ Page Inherits="DBClass"
  src="DBClass.vb" %>

<SCRIPT Runat="Server">

Sub Page_Load
  Get_Data
End Sub

</SCRIPT>


<html>
<body>
<form Runat="Server">

<asp:GridView id="DisplayGrid" Runat="Server"
  AutoGenerateColumns="False"
  ShowHeader="True"
  HeaderStyle-BackColor="#E0E0E0"
  HeaderStyle-Font-Bold="True"
  HeaderStyle-HorizontalAlign="Center"
>
  <Columns>

  <asp:BoundField
    DataField="BookTitle"
    HeaderText="Title"/>

  <asp:BoundField
    DataField="BookPrice"
    HeaderText="Price"
    ItemStyle-HorizontalAlign="Right"/>

  </Columns>

</asp:GridView>

</form>
</body>
</html>
Figure 11-5. DBPage2.aspx - uses DBClass.vb code-behind data access file.

Both pages use identical page directives to import the DBClass.vb file. Both pages include a Page_Load script to call subprogram Get_Data when they load. Both pages have identical id="DisplayGrid" GridViews. The pages differ, however, in how they employ the retrieved recordset by the differing data columns that are bound to their GridViews.

Passing SQL Strings

It is not necessary that different pages be limited by the single recordset retrieved by the code-behind page. An ASP.NET page can, in fact, pass an SQL statement to the code-behind page and have a personalized recordset returned. A minor rewrite of the code-behind page is necessary.

Imports System.Data.OleDb

Public Class DBClass
  Inherits Page

  Protected WithEvents DisplayGrid As GridView

  Sub Get_Data (SQLString As String)
    Dim DBConnection As OleDbConnection
    Dim DBCommand As OleDbCommand
    Dim DBReader As OleDbDataReader
    DBConnection = New OleDbConnection( _
      "Provider=Microsoft.Jet.OLEDB.4.0;" & _
      "Data Source=" & Server.MapPath("../Databases/BooksDB.mdb"))
    DBConnection.Open()
    DBCommand = New OleDbCommand(SQLString, DBConnection)
    DBReader = DBCommand.ExecuteReader()
    DisplayGrid.DataSource = DBReader
    DisplayGrid.DataBind()
    DBReader.Close()
    DBConnection.Close()
  End Sub

End Class
Listing 11-7. Rewrite of DBClass.vb code-behind data access file.

Here, the signature of the subprogram includes an SQLString argument through which an SQL statement is passed. Then that statement is issued through the Command object to retrieve that particular selection of fields. Different subsets of records can be retrieved and even different database tables can be accessed.

TitleQty
Programming C#0
SQL Server 20050
Operating System Concepts1
USB System Architecture1
Oracle Database10
The UNIX Operating System12
C Programming Language12
Microsoft ASP.NET 2.012
Database Processing12
Visual Basic.NET Programming13
Creating Motion Graphics13
Linux in a Nutshell14
Ajax in Action14
Macromedia Flash Professional17
Programming PHP17
Contemporary Logic Design2
Professional ASP.NET 2.021
Digital Photographer Handbook22
Access Database Design25
Windows Server 200325
Designing Embedded Hardware3
Adobe Photoshop CS24
Upgrading and Repairing PCs5
Databases in Depth6
Cascading Style Sheets6
DOM Scripting8
How Computers Work8
Mastering Active Directory8
Learning Web Design8
Java How to Program9
<%@ Page Inherits="DBClass"
  src="DBClass.vb" %>

<SCRIPT Runat="Server">

Sub Page_Load
Get_Data ("SELECT BookTitle, BookQty FROM Books ORDER BY BookQty")
End Sub

</SCRIPT>


<html>
<body>
<form Runat="Server">

<asp:GridView id="DisplayGrid"
  Runat="Server"
  AutoGenerateColumns="False"
  ShowHeader="True"
  HeaderStyle-BackColor="#E0E0E0"
  HeaderStyle-Font-Bold="True"
  HeaderStyle-HorizontalAlign="Center"
>
  <Columns>

  <asp:BoundField
    DataField="BookTitle"
    HeaderText="Title"/>

  <asp:BoundField
    DataField="BookQty"
    HeaderText="Qty"
    ItemStyle-HorizontalAlign="Right"/>

  </Columns>

</asp:GridView>

</form>
</body>
</html>
Figure 11-6. Passing an SQL statement to the DBClass.vb code-behind file.

Passing Control Information

In previous examples, it is assumed that all controls to which the recordset is bound are GridViews with id="DisplayGrid". But this doesn't have to be the case. Any control can identify itself to the code-behind file and receive the recordset it needs. In the following example, an <asp:Repeater> control calls a code-behind subprogram and retrieves its personalized recordset. Again, only a slight change is needed in the code-behind file to make this generalization.

Imports System.Data.OleDb

Public Class DBClass
  Inherits Page

  Sub Get_Data (SQLString As String, ControlID As String)
    Dim DBConnection As OleDbConnection
    Dim DBCommand As OleDbCommand
    Dim DBReader As OleDbDataReader
    Dim TheControl As Object = FindControl(ControlID)
    DBConnection = New OleDbConnection( _
      "Provider=Microsoft.Jet.OLEDB.4.0;" & _
      "Data Source=" & Server.MapPath("../Databases/BooksDB.mdb"))
    DBConnection.Open()
    DBCommand = New OleDbCommand(SQLString, DBConnection)
    DBReader = DBCommand.ExecuteReader()
    TheControl.DataSource = DBReader
    TheControl.DataBind()
    DBReader.Close()
    DBConnection.Close()
  End Sub

End Class
Listing 11-8. Recoding of DBClass.vb code-behind file to accept passed control information.

The subprogram is passed the id of a control as argument ControlID along with an SQL statement. The subprogram uses the passed id to find that control on the page and assign it to variable TheControl. This variable is not explicitly typed since it is not known in advance what kind of control it is. TheControl is the object to which the retrieved recordset is bound, using the passed SQL statement to retrieve particular records and particular fields from particular tables.

The page that imports this code-behind page is shown below with a call to subprogram Get_Data, passing along an SQL statement and identification of the Repeater to which the returned recordset is bound.

Title Qty
Programming C# 0
SQL Server 2005 0
Operating System Concepts 1
USB System Architecture 1
Oracle Database 10
The UNIX Operating System 12
C Programming Language 12
Microsoft ASP.NET 2.0 12
Database Processing 12
Visual Basic.NET Programming 13
Creating Motion Graphics 13
Linux in a Nutshell 14
Ajax in Action 14
Macromedia Flash Professional 17
Programming PHP 17
Contemporary Logic Design 2
Professional ASP.NET 2.0 21
Digital Photographer Handbook 22
Access Database Design 25
Windows Server 2003 25
Designing Embedded Hardware 3
Adobe Photoshop CS2 4
Upgrading and Repairing PCs 5
Databases in Depth 6
Cascading Style Sheets 6
DOM Scripting 8
How Computers Work 8
Mastering Active Directory 8
Learning Web Design 8
Java How to Program 9
<%@Page Inherits="DBClass"
  src="DBClass.vb"%>

<SCRIPT Runat="Server">

Sub Page_Load
  Get_Data ( _
    "SELECT BookTitle, BookQty " & _
    "FROM Books " & _
    "ORDER BY BookQty", _
    "MyRepeater")
End Sub

</SCRIPT>


<html>
<body>
<form Runat="Server">

<asp:Repeater id="MyRepeater"
Runat="Server">

<HeaderTemplate>
<table border="1">
<tr style="background-color:#E0E0E0">
  <th>Title</th>
  <th>Qty</th>
</tr>
</HeaderTemplate>

<ItemTemplate>
<tr>
  <td><%# Eval("BookTitle") %></td>
  <td><%# Eval("BookQty") %></td>
</tr>
</ItemTemplate>

<FooterTemplate>
</table>
</FooterTemplate>

</asp:Repeater>

</form>
</body>
</html>
Figure 11-7. Passing control information to a code-behind class.

Now the code-behind file serves a general-purpose data retrieval function that can be called by any page to supply a recordset for any of its controls. Of course, the control must use compatible binding techniques. For instance, a DropDownList has its DataTextField and DataValueField identified for binding. The present code-behind file does not answer this need. Still, it serves the needs of all information display controls.

Returning Recordsets from Functions

A more generally useful technique for supplying database information to a page, one that does not involve providing control information to the code-behind class, is to convert the code-behind subprogram to a function which returns a DataReader. By employing this technique, a code-behind file can become totally independent of any Web pages which inherit it.

In the following example, a GridView is used to display a subset of information from the BooksDB.mdb database. However, the code-behind class needs no knowledge of the page to which it returns its results.

TitlePrice
Oracle Database$69.99
Databases in Depth$29.95
Database Processing$136.65
Access Database Design$34.95
SQL Server 2005$29.99
Adobe Photoshop CS2$29.99
Learning Web Design$39.95
Macromedia Flash Professional$44.99
Digital Photographer Handbook$24.95
Creating Motion Graphics$59.95
How Computers Work$29.99
Upgrading and Repairing PCs$59.99
USB System Architecture$49.99
Designing Embedded Hardware$44.95
Contemporary Logic Design$102.95
Java How to Program$98.59
C Programming Language$44.25
Programming C#$44.95
Programming PHP$39.95
Visual Basic.NET Programming$49.99
Operating System Concepts$95.75
The UNIX Operating System$19.95
Windows Server 2003$29.99
Linux in a Nutshell$44.95
Mastering Active Directory$49.99
Ajax in Action$22.67
Professional ASP.NET 2.0$32.99
Cascading Style Sheets$39.95
DOM Scripting$23.09
Microsoft ASP.NET 2.0$29.99
<%@ Page Inherits="DBClass"
src="DBClass.vb" %>

<SCRIPT Runat="Server">

Sub Page_Load

  DisplayGrid.DataSource=Return_Reader()
  DisplayGrid.DataBind()

End Sub

</SCRIPT>

<html>
<body>
<form Runat="Server">

<asp:GridView id="DisplayGrid"   Runat="Server"
  AutoGenerateColumns="False">

  <Columns>

  <asp:BoundField
    HeaderText="Title"
    DataField="BookTitle"/>

  <asp:BoundField
    HeaderText="Price"
    DataField="BookPrice"/>

  </Columns>

</asp:GridView>
</form>
</body>
</html>
Figure 11-8. Using a code-behind function to access a database.

The On_Load script issues a function call to Return_Reader() in the code-behind file, and binds the returned recordset to the GridView. The DBClass.vb code-behind file is shown below. Function Return_Reader() returns the full set of records drawn from the Books table of the BooksDB.mdb database. That is, it returns a DataReader (the DBReader recordset) to any page that calls the function.

Imports System.Data.OleDb

Public Class DBClass
  Inherits Page
  
  Function Return_Reader()
    Dim DBConnection As OleDbConnection
    Dim DBCommand As OleDbCommand
    Dim DBReader As OleDbDataReader
    Dim SQLString As String
    
    DBConnection = New OleDbConnection( _
      "Provider=Microsoft.Jet.OLEDB.4.0;" & _
      "Data Source=" & Server.MapPath("../Databases/BooksDB.mdb"))
    DBConnection.Open()
    SQLString = "SELECT * FROM Books ORDER BY BookID"
    DBCommand = New OleDbCommand(SQLString, DBConnection)
    DBReader = DBCommand.ExecuteReader()
    Return DBReader
    
    DBReader.Close()
    DBConnection.Close()
  End Function
  
End Class
Listing 11-9. DBClass.vb code-behind file with data access function.

Notice that even though the code-behind class returns a full recordset, the GridView uses BoundFields to display only selected fields from the recordset. Thus, any number of different pages can import this class and call its function to display their own selected fields of information. The class is a general-purpose database access function that can be adapted to numerous uses.