<asp:TextBox> Control

In order to become processors and providers of information, Web pages require data for input to their scripts. The sources for most of the input to scripts are the collections of data stored in files and databases. Another important source, however, is the user. Users supply input data that is processed in some fashion to return information output. Users also make choices to control processing actions.

There are several ways in which users can provide data and choices to scripts using various Web form controls. You probably are familiar with textboxes, radio buttons, checkboxes, and drop-down lists. Beginning with this tutorial you are introduced to these types of controls, how to create them on a Web page, and how to devise scripts to process the input data they supply.

Textbox Input and Output

A textbox is probably the most popular mechanism for soliciting user input. It is a boxed area into which the user types information for server processing. It is normally accompanied by a button to call a subprogram to process the entered data. The following textbox is typical. After entering any text into this input area, click the "Submit" button. A subprogram is called to display the contents of the textbox.




Figure 6-1. A typical textbox to solicit user input.

A textbox also can be a target area for script output. In the following example, the entered data is reported in the textbox itself.




Figure 6-2. A textbox used as both an input and output area.

Format for TextBox Control

A textbox is placed on a Web page by coding the <asp:TextBox> control. The TextBox can be sized to any dimensions and can serve as either a data input area or a script output area. Its general format is shown below.

<asp:TextBox id="id" Runat="Server"
  AutoPostBack="False|True"
  Columns="n"
  MaxLength="n"
  ReadOnly="False|True"
  Rows="n"
  Text="string"
  TextMode="SingleLine|MultiLine|Password"
  Wrap="False|True"
    
    property="value"...
    
    OnTextChanged="subprogram"
/>
Figure 6-3. General format for <asp:TextBox> control.

The Text property is a reference to the value appearing in the control—the data entered by the user or the value displayed by a script. An initial value can be displayed in the TextBox by coding this attribute; otherwise, the TextBox is initially blank. The width of the TextBox can be set with the Columns property giving the approximate number of characters to display. The maximum number of typed characters allowed is set with the MaxLength property.

By default, a TextBox is a single-line entry box. Multiple lines of text are permitted with the TextMode="MultiLine" setting; the number of lines to display is given in the Rows property. For a multiline TextBox, the entry is automatically wrapped unless the Wrap property is set to False. With a specification of TextMode="Password", the TextBox displays as a single-line entry box, and entered characters are echoed as bullets for privacy. A password TextBox cannot be prefilled with Text characters.

Although normally used as an input area, a TextBox also can serve as a target for script output. In these cases, you may not want the user to be able to edit the output. So, the ReadOnly property can be set to "True" to disallow changes to the displayed information.

Usually, TextBoxes are accompanied by buttons to call subprograms to process the entered data. However, the TextBox itself can be configured to call a subprogram. Its AutoPostBack="True" setting automatically posts back to the server when its content changes and the user tabs from or clicks outside the control. The subprogram named in the OnTextChanged property is called.

Creating TextBox Controls

The following examples demonstrate various <asp:TextBox> settings. Text entered into a TextBox is displayed in an accompanying <asp:Label> control when the "Submit" button is clicked. Notice that submitted text reappears in the TextBoxes as a result of the page maintaining its View State and repopulating the control. TextBox entries can be cleared between page postings by including script code to assigned a null character ("") to the textbox. The script used for the following example TextBoxes is coded as shown below.

<SCRIPT Runat="Server">

Sub ShowText (Src As Object, Args As EventArgs)
  Output.Text = Input.Text
End Sub

</SCRIPT>

Listing 6-1. Script for example TextBoxes in Figure 6-4.

Default TextBox Control

<asp:TextBox id="Input" Runat="Server"/>
<asp:Button Text="Submit" OnClick="ShowText" Runat="Server"/>
<b>Entered data:</b> <asp:Label id="Output" Runat="Server"/>

Entered data:



MultiLine TextBox Control

<asp:TextBox id="Input" Runat="Server"
  TextMode="MultiLine"
  Columns="30"
  Rows="3"/>
<asp:Button Text="Submit" OnClick="ShowText" Runat="Server"/>
<b>Entered data:</b> <asp:Label id="Output" Runat="Server"/>

Entered data:



Password TextBox Control

<asp:TextBox id="Input" Runat="Server"
  TextMode="Password"/>
<asp:Button Text="Submit" OnClick="ShowText" Runat="Server"/>
<b>Entered data:</b> <asp:Label id="Output" Runat="Server"/>

Entered data:



AutoPostBack TextBox Control

<asp:TextBox id="Input" Runat="Server"
  Columns="30"
  Text="Change text and click outside." 
  AutoPostBack="True"
  OnTextChanged="ShowText"/>	
<b>Entered data:</b> <asp:Label id="Output" Runat="Server"/>

Entered data:


Figure 6-4. Varieties of TextBox controls.

For this last example using the AutoPostBack feature, the called subprogram ShowText has the same signature as a subprogram called by a Button.

The above TextBoxes use default stylings except for specified sizes given for the controls. You can, though, decorate a TextBox using the full range of server and CSS style settings. The following example TextBox has an assortment of styles.

Styled TextBox Control

<asp:TextBox Runat="Server"
  Text="This is a styled TextBox"
  BorderStyle="Ridge"
  BorderWidth="3px"
  Width="210px"
  Height="50px"
  BackColor="#CC6666"
  ForeColor="#FFFFFF"
  Font-Name="Comic Sans MS"
  Font-Size="12pt"
  Style="padding:10px"/>
Figure 6-5. A styled TextBox control.

Scripting TextBoxes

TextBoxes supply input data for scripts. The idea is for scripts to respond to user requests, taking actions to personalize the output for whatever input is submitted. There are, of course, inummerable ways in which user data can be processed. These ways are investigated throughout the tutorials. As a simple initial example, the following form permits users to enter width and height dimensions for a rectangle. The script calculates the resulting area of the rectangle and draws it on the screen. Initial width and height values are supplied; click the "=" button to view the results.

Make a Rectangle

Width Height Area
 x    

Figure 6-6. Creating a rectangle from TextBox input.
<%@ Import Namespace="System.Drawing" %>

<SCRIPT Runat="Server">

Sub Make_Rectangle (Src As Object, Args As EventArgs)

  If IsNumeric(Width.Text) AND IsNumeric(Height.Text) Then
    
    Area.Text = FormatNumber(Width.Text * Height.Text, 0)

    Rectangle.Width = Unit.Parse(Width.Text)
    Rectangle.Height = Unit.Parse(Height.Text)
    Rectangle.BorderStyle = BorderStyle.Solid
    Rectangle.BorderWidth = Unit.Parse("1px")
    Rectangle.BackColor = Color.FromName("#FF6666")

  End If

End Sub

</SCRIPT>

<form Runat="Server">

<h3>Make a Rectangle:</h3>

<table border="0" cellpadding="0">
<tr style="text-align:left">
  <th colspan="2">Width</th>
  <th colspan="2">Height</th>
  <th>Area</th>
</tr>
<tr>
  <td><asp:TextBox id="Width" Runat="Server" 
        Columns="1"
        MaxLength="3"
        Text="100"
        Style="text-align:right"/>
  </td>
  <td>x</td>
  <td><asp:TextBox id="Height" Runat="Server"
        Columns="1"
        MaxLength="3"
        Text="100"
        Style="text-align:right"/>
  </td>
  <td><asp:Button Runat="Server"
        Text=" = "
        OnClick="Make_Rectangle"/>
  </td>
  <td><asp:TextBox id="Area" Runat="Server"
        Columns="3"
        ReadOnly="True"
        Style="text-align:right"/>
  </td>
</tr>
</table>

<p><asp:Panel id="Rectangle" Runat="Server"/></p>

</form>
Listing 6-2. Code to produce a rectangle from TextBox entry.

An XHTML table is used to arrange the display of text and boxes and plays no real part in the processing. The two input TextBox controls (id="Width" and id="Height") provide the input areas for entering the dimensions of the rectangle. They are given initial values and are restricted to a maximum of three characters to restrict the display size of the rectangle.

When the button is clicked, the Make_Rectangle subprogram is called. Since calculating the area of the rectangle requires numeric values to be entered, a check is made that both the Width and Height input values are numbers (using the Visual Basic IsNumeric() function), and the script is run only if this is the case.

The TextBox id="Area" stores the results of multiplying the input width by the input height. Its ReadOnly property is set to "True" to keep users from changing the displayed results. Even though TextBoxes, as the name implies, represent values as text strings, the multiplication operation converts the strings to numbers in order to perform the operation. You can explicitly make this conversion using the Visual Basic CInt(Width.Text) and CInt(Height.Text) conversions.

The script draws the resulting rectangle by formatting an <asp:Panel> control. Formatting the Panel is a simple matter of styling it with server properties for which the System.Drawing namespace is imported to the page.

Since Textboxes permit free-form user input, it is usually necessary to edit or validate entered data to make sure it conforms to script expectations. Various methods of data editing are covered throughout the tutorials.

User Login

A popular use of TextBox controls is to create login forms for restricting access to Web pages to users who have valid accounts and/or know correct passwords. The following example shows a login form for access to this tutorial page (even though you already have arrived here). If you enter the correct password ("xyzzy"), this page is reloaded. If you enter a blank or incorrect password, this page is not reloaded and an error message is displayed. The account entry is not tested.

Account:   
Password: 
Figure 6-7. A login form.
<SCRIPT Runat="Server">

Sub Log_In (Src As Object, Args As EventArgs)

  If Password.Text = "xyzzy" Then
    Response.Redirect("aspnet06-01.aspx")
  Else
    Message.Text = "Incorrect password"
  End If

End Sub

</SCRIPT>

<form Runat="Server">

<asp:Panel Runat="Server"
  BorderStyle="Ridge"
  BorderWidth="5px"
  Width="275px"
  Height="120px"
  Style="padding:20px">

  Account:
  <asp:TextBox id="Account" Width="100px" Runat="Server"/><br/>
  Password:
  <asp:TextBox id="Password" TextMode="Password" Width="100px"
    Runat="Server"/>
  <asp:Button Text="Login" OnClick="Log_In" Runat="Server"/><br/>
  <asp:Label id="Message" EnableViewState="False" ForeColor="#FF0000" 
    Runat="Server"/>

</asp:Panel>

</form>
Listing 6-3. Code for login form.

Notice that the valid password is hard-coded in the script. This may seem risky and susceptible to unwanted viewing. Remember, however, that server script cannot be viewed in the source listing of the page. Therefore, the coded password is not viewable from within the browser.

Restricting Site Access

It is often the case that a login form is used to restrict access to an entire Web site, not just to a single page. An addition to the above script can handle this situation. It requires setting an indicator, or a flag, that can be tested on every Web page to check whether a valid login has occured.

Recall that a Session variable is a global variable that is accessible by any page in the current Web directory. By setting a Session variable in the login script to indicate that the visitor has logged in, all pages can check this variable to determine whether or not to permit access to the page. Below is a rewrite of the previous script to set a Session variable—Session("LoggedIn")—indicating successful login. Assume this script appears on a login page, say Login.aspx, that displays a form similar to the one shown above.

<SCRIPT Runat="Server">

Sub Log_In (Src As Object, Args As EventArgs)

  If Password.Text = "xyzzy" Then
    Session("LoggedIn") = True
  Else
    Message.Text = "Incorrect password"
  End If

End Sub

</SCRIPT>
Listing 6-4. Script using Session variable to indicate successful login.

Since Session("LoggedIn") is globally accessible, all pages that need to restrict access can test this variable. If it has been set to True, then access is permitted; if it has not been set to True, then access is not permitted, in which case redirection can be made back to the login page.

The following script needs to appear on every page to which access is restricted. When the page loads, Session("LoggedIn") is tested. If its value is not True, then redirection is immediately to the Login.aspx page where the form is displayed. If its value is True, then redirection does not take place and the page is loaded for viewing. This script is required on every restricted page; otherwise, access to the page would be successful simply by entering its URL in the browser, skipping the login page altogether.

<SCRIPT Runat="Server">

Sub Page_Load

  If Session("LoggedIn") <> True Then
    Response.Redirect("Login.aspx")
  End If

End Sub

</SCRIPT>
Listing 6-5. Script to test for successful login.

Recall that Session variables remain "alive" for 20 minutes following the last access to a page in the current Web directory. If the user is idle for longer that 20 minutes, then the Session variable becomes null and access to any page ends up back at the login page.

Maintaining User Accounts

In the previous examples, only a password is tested for page and site access. Usually, in addition to a password, a user account is checked. Normally, user accounts are maintained in a database, along with private passwords that correspond with the accounts. The following Access database table shows a typical layout of account records. This Accounts table is in a UserAccounts.mdb database. It could be part of any database depending on the organization of your site.

Field Name Data Type Field Size Example Data
TheAccount Text 8 aaaa1111
ThePassword Text 8 secret
Figure 6-8. Accounts table of UserAccounts.mdb database.

There are two techniques to check for matching accounts and passwords in the database, both of which involve checking for a returned recordset from an SQL query.

Using the HasRows Property

You should recall from previous discussions that the DataReader has a HasRows property that can be tested for the return of a recordset. If, then, a SELECT statement attempts to locate a user account record with particular account and password values in its fields, its existence is confirmed by the DataReader's HasRows property value of True. This technique is used in the following script which assumes an account and password data entry form similar to the one in Figure 6-7 with id="Account" and id="Password" TextBoxes.

<%@ Import Namespace="System.Data.OleDb" %>

<SCRIPT Runat="Server">

Sub Log_In (Src As Object, Args As EventArgs)

  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/UserAccounts.mdb"))
  DBConnection.Open()
  SQLString = "SELECT * FROM Accounts " & _
              "WHERE TheAccount = '" & Account.Text & "' " & _
              "AND ThePassword = '" & Password.Text & "'"
  DBCommand = New OleDbCommand(SQLString, DBConnection)
  DBReader = DBCommand.ExecuteQuery()
  
  If DBReader.HasRows Then
    Session("LoggedIn") = True
  Else
    Message.Text = "Incorrect account or password"
  End If
  
  DBReader.Close()
  DBConnection.Close()

End Sub

</SCRIPT>
Listing 6-6. Script to test login entries against database using DataReader's HasRows property.

The fact that the HasRows property is True means that a matching record was found. It is not necessary to access or refer to the individual data fields in the record. Of course, a Page_Load script needs to be added to each restricted page to check the Session variable for valid login.

Using the SQL Count(*) Function

The SQL language has a Count(*) function that returns the number of records in a returned recordset. By testing this count you can determine whether or not a match was made during a query for an account and password.

<%@ Import Namespace="System.Data.OleDb" %>

<SCRIPT Runat="Server">

Sub Log_In (Src As Object, Args As EventArgs)

  Dim DBConnection As OleDbConnection
  Dim DBCommand As OleDbCommand
  Dim SQLString As String
  Dim RecordCount As Integer
  
  DBConnection = New OleDbConnection( _
    "Provider=Microsoft.Jet.OLEDB.4.0;" & _
    "Data Source=" & Server.MapPath("../Databases/UserAccounts.mdb"))
  DBConnection.Open()
  SQLString = "SELECT Count(*) FROM Accounts " & _
              "WHERE TheAccount = '" & Account.Text & "' " & _
              "AND ThePassword = '" & Password.Text & "'"
  DBCommand = New OleDbCommand(SQLString, DBConnection)
  RecordCount = DBCommand.ExecuteScalar()
  
  If RecordCount <> 0 Then
    Session("LoggedIn") = True
  Else
    Message.Text = "Incorrect account or password"
  End If

  DBConnection.Close()

End Sub

</SCRIPT>
Listing 6-7. Script to test login entries against database using the SQL Count(*) function.

When database access returns a record count it is not necessary to create a DataReader to iterate a recordset. In fact, no recordset is returned. Instead, the Command object's ExecuteScalar() method (rather than its ExecuteQuery() method) is used to return a single record count value, which in this case is assigned to variable RecordCount.

RecordCount = DBCommand.ExecuteScalar()
Listing 6-8. Capturing a record count of matching records.

If the record count is not 0 (RecordCount <> 0), then the Session variable is set to indicate successful login. Again, a Page_Load script needs to be added to each restricted page to check the Session variable for valid login.

Incidentally, it is not necessary to store the record count in a separate variable and then test the variable. These steps can be combined as follows by directly testing the results of the ExecuteScalar() method.

If DBCommand.ExecuteScalar() <> 0 Then
  Session("LoggedIn") = True
Else
  Message.Text = "Incorrect account or password"
End If
Listing 6-9. Testing a record count of matching records.

Returning Single Database Values

The ExecuteScalar() method is an efficient way to return a single value from a database query. As well as returning a record count, it can be used to return the value from a single data field. For instance, assume you want to retrieve only the Password field for a single matching record from the Accounts table. The following code can be used.

Sub Get_Password (Src As Object, Args As EventArgs)

  Dim DBConnection As OleDbConnection
  Dim DBCommand As OleDbCommand
  Dim SQLString As String
  Dim Password As String
	
  DBConnection = New OleDbConnection( _
    "Provider=Microsoft.Jet.OLEDB.4.0;" & _
    "Data Source=" & System.MapPath("../Databases/UserAccounts.mdb"))
  DBConnection.Open()
  SQLString = "SELECT ThePassword FROM Accounts WHERE Account = 'aaaa1111'"
  DBCommand = New OleDbCommand(SQLString, DBConnection)
  Password = DBCommand.ExecuteScalar()
  DBConnection.Close()

End Sub
Listing 6-10. Returning a single data value from a database query.

As the completion of this subprogram, ThePassword value from the database table is stored in variable Password. It is not necessary to create and iterate a DataReader to retrieve a single value.

In some of the previous examples, TextBox controls are used to solicit user input that is applied against a database. TextBoxes present vulnerabilities that invalid data entered by the user can abort execution of scripts, or in the worse case, be the unwitting sources of intentionally malicious code that can easily destroy an entire database. Protection against these vulnerabilities is discussed under "Validation Controls."