Programming an ASP.NET Application: Changes from ASP.old
In This Chapter
ASP.NET's Control Model
Separating Presentation from Code Using Code Behind
Programming HTML Controls
Attributes of the Page Object
Creating User Interfaces with Web Controls
Server Controls and Page Object Reference
Programming an ASP.NET application is significantly different than programming in ASP.old. The difference can be likened to the change that occurred when moving from QuickBasic programming to Visual Basic programming.
The changes in ASP.NET can be broken down into three categories: the control model, the event model, and the separation of code from presentation.
ASP.NET's Control Model
In QuickBasic, your code dealt with the screen as a long piece of paper to which you sent output. You may have used screen libraries that encapsulated a lot of this functionality and made it a much higher-level operation with better positioning.
With the advent of Visual Basic, you moved into a world of reusable controls. You designed your UI by dragging and dropping controls onto a design surface instead of outputting text to the screen or drawing polygons.
These controls were objects that had methods and properties that were used to customize their display and functionality. ASP.old was in many ways similar to QuickBasic. The entire page was essentially treated as a long piece of paper onto which your code placed content. No object model gives you access to the HTML that surrounds your codejust a way for you to output additional HTML based on the location of your code.
ASP.NET changes this by introducing the concept of server controls. If you used Visual Interdev to create ASP.old Web applications, you may be thinking, "Great! They just renamed those onerous design-time controls!" This is not the case. Server controls are not design-time controls in another guise. Nor do server controls require any particular type of clientin other words, server controls aren't ActiveX Controls or client-side behaviors. Server controls are a high-level abstraction of functionality utilized during page execution to place user-interface elements onto the page.
Let's take a look at this. Listing 3.1 shows the HTML for a traditional ASP.old form.
Listing 3.1 A Simple ASP.old Page, SimplePage.asp
<html> <head> <title>SimplePage.asp</title> </head> <body> <form name="WebForm1" method="post"> <p> <table border=0> <tr> <td>Name:</td> <td><input type=text name=txtName></td> <td> <input type=submit name=Button1 Value="Send"> </td> </tr> <tr> <td valign=top>Hobby:</td> <td> <select name=lbHobbies Multiple> <option Value="Ski">Ski</option> <option Value="Bike">Bike</option> <option Value="Swim">Swim</option> </select> </td> <td> </td> </tr> </table> </p> </form> </body> </html>
What happens when a user fills in a name, chooses a hobby, and presses the Send button? The page is first posted back to the server. No code is in the form at this point, so all the selections that the user made in the Select tag (information that we'll refer to as form state) is lost. The page is then returned back to the browser. In ASP.old, if you want to preserve the form state, you are forced to write code to do that.
Listing 3.2 contains SimplePage2.asp showing the typical code you would write with ASP.old to make this work.
Listing 3.2 SimplePage2.asp Showing Code to Preserve Form State in ASP.old
<html> <head> <title>SimplePage.asp</title> </head> <SCRIPT LANGUAGE="VBScript" RUNAT=SERVER> function IsOptionSelected(strControlName, strOption) for iCount = 1 to Request(strControlName).Count if request(strControlName)(iCount) = strOption then response.write " SELECTED " end if next end function </SCRIPT> <body> <form name="WebForm1" method="post"> <p> <table border=0> <tr> <td>Name:</td> <td><input type=text name=txtName value="<% = Request("txtName") %>"></td> <td><input type=submit name=Button1 Value="Send"></td> </tr> <tr> <td valign=top>Hobby:</td> <td> <select name=lbHobbies Multiple> <option <% IsOptionSelected "lbHobbies", "Ski" %> Value="Ski">Ski</option> <option <% IsOptionSelected "lbHobbies", "Bike" %> Value="Bike">Bike</option> <option <% IsOptionSelected "lbHobbies", "Swim" %> Value="Swim">Swim</option> </select> </td> <td> </td> </tr> </table> </p> </form> </body> </html>
With the advent of server controls, ASP.NET adds functionality to HTML's own user-interface controls, making them do what you would expect them to do; that is, save the data that the user just spent time typing in.
You need to do three things to make ASP.NET server controls work.
ASP.NET server controls are identified using the ID attribute instead of (or in addition to) the Name attribute. You are allowed to use both. You may want to use the Name attribute if you have client-side script that needs to refer to the control.
ASP.NET server controls require you to add the runat=server attribute. This attribute indicates to ASP.NET that the tag is something more than a built-in HTML tag.
ASP.NET server controls require a closing tag. Server controls are implemented using XML namespaces and, like XML, require every element to have a matching closing element. You can use XML style syntax as a shortcut creating a tag such as <input type=text runat=server />.
So let's do this to the code that was in Listing 3.1. Listing 3.3 shows simplepage.aspx, an ASP.NET implementation of simplepage.asp.
Listing 3.3 SimplePage.aspxA Reworking of Listing 3.1 in ASP.NET
<html> <head> <title>SimplePage.aspx</title> </head> <body> <form id="WebForm1" method="post" runat="server"> <p> <table border=0> <tr> <td>Name:</td> <td><input type=text id=txtName runat=server /></td> <td><input type=submit id=Button1 Value="Send" runat=server /> </td> </tr> <tr> <td valign=top>Hobby:</td> <td> <select id=lbHobbies Multiple runat=server> <option Value="Ski">Ski</option> <option Value="Bike">Bike</option> <option Value="Swim">Swim</option> </select> </td> <td> </td> </tr> </table> </p> </form> </body> </html>
All that's changed is the addition of the runat=server attribute to the form tag, the input tag, and the select tag. We've also changed each of the name attributes to ID attributes. That's it. If you run this page, fill in a name, select a hobby, and then click the Send button. The data that you entered stays there after the page is destroyed and re-created on its round trip to the server. The server controls realize that the desired default behavior is to maintain input; that is, they maintain their state, and they do so automatically.
If you don't want a given server control to maintain its state, you can use a new attribute with any server control called EnableViewState. By setting this to false, you can override the default behavior of maintaining form state across posts.
Two categories of server controls are HTML controls and Web controls. The HTML controls mirror their HTML counterparts. HTML controls include the following:
HTML Control Class |
HTML Tag |
HtmlAnchor |
<a href="...">Anchor</a> |
HtmlButton |
<button /> |
HtmlContainerControl |
Any control that requires a closing tag |
HtmlControl |
Any Html server control |
HtmlForm |
<form></form> |
HtmlGenericControl |
-Represents any HTML tag without a specific server control class. For example, <p>. |
HtmlImage |
<image href="..." /> |
HtmlInputButton |
<input type=Button /> |
HtmlInputCheckBox |
<input type=Checkbox /> |
HtmlInputControl |
Any <input type=* /> control |
HtmlInputFile |
<input type=file /> |
HtmlInputHidden |
<input type=hidden /> |
HtmlInputImage |
<input type=image /> |
HtmlInputRadioButton |
<input type=Radio /> |
HtmlInputText |
<input type=Text /> |
HtmlSelect |
<select>...</select> |
HtmlTable |
<table>...</table> |
HtmlTableCell |
<td>...</td> |
HtmlTableCellCollection |
All <TD> or <TH> tags within <table>...</table> |
HtmlTableRow |
<tr>...</tr> |
HtmlTableRowCollection |
All <TR> tags within <table>...</table> |
HtmlTextArea |
<textarea>...</textarea> |
Note
All these tags require the runat=server attribute to make them HTML controls. If you forget to add this attribute, these controls will be treated as normal HTML tags. They will be programmable only via client-side code, which may not be what you want.
These controls wrap the related HTML tag with a complete object model that allows access to all the attributes of the tag via properties or methods. You'll see examples of this later in this chapter.
Web controls don't always map directly to a single HTML tag. In many cases they are composite controls that represent a large number of HTML tags. Let's take a look at an example. Listing 3.4 shows the Calendar Web control.
Listing 3.4 Calendar.aspx Showing a Single Web Control
<html> <head> <title>Calendar.aspx</title> </head> <body> <form id="WebForm1" method="post" runat="server"> <asp:calendar id=Calendar1 runat=server /> </form> </body> </html>
Save this file as Calendar.aspx, and that's it. But that one HTML tag generates something that looks like Figure 3.1.
Figure 3.1 The output of Calendar.aspx from Listing 3.4.
That looks like more than just a single HTML tag. In fact, it is. When the page is "rendered," or sent to the client, the control replaces the <asp:calendar runat="server" /> with the HTML that represents a monthly calendar. If you think about it, this makes sense. A browser has no idea what to do with the <asp:calendar> tag. HTML dictates that browsers ignore tags they don't understand. But you don't want the browser to ignore the tag; you want the browser to display a calendar rendered in HTML. So before the page is sent back to the browser, ASP.NET renders the calendar in HTML for you.
If you view the source of the page after it is rendered in the browser, you should get something that looks like Listing 3.5.
Listing 3.5 The Rendered HTML Source for the Calendar Control Shown in Figure 3.1
<html> <head> <title>Calendar.aspx</title> </head> <body> <form name="WebForm1" method="post" action="calendar.aspx" id="WebForm1"> <input type="hidden" name="__VIEWSTATE" value="dDw1MzYzNjkxODU7Oz4=" /> <table id="Calendar1" cellspacing="0" cellpadding="2" border="0" style="border-width:1px;border-style:solid;border-collapse:collapse;"> <tr><td colspan="7" style="background-color:Silver;"> <table cellspacing="0" border="0" style="width:100%;border-collapse:collapse;"> <tr><td style="width:15%;"> <a href="javascript:__doPostBack('Calendar1','prevMonth')" style="color:Black"><</a> </td><td align="Center" style="width:70%;"> August 2001 </td><td align="Right" style="width:15%;"> <a href="javascript:__doPostBack('Calendar1','nextMonth')" style="color:Black">></a> </td></tr> </table> </td></tr><tr><td align="Center"> Sun </td><td align="Center"> Mon </td><td align="Center"> Tue </td><td align="Center"> Wed </td><td align="Center"> Thu </td><td align="Center"> Fri </td><td align="Center"> Sat </td></tr><tr><td align="Center" style="width:14%;"> <a href="javascript:__doPostBack('Calendar1','selectDay0')" style="color:Black">29</a> </td><td align="Center" style="width:14%;"> <a href="javascript:__doPostBack('Calendar1','selectDay1')" style="color:Black">30</a> </td><td align="Center" style="width:14%;"> <a href="javascript:__doPostBack('Calendar1','selectDay2')" style="color:Black">31</a> </td><td align="Center" style="width:14%;"> <a href="javascript:__doPostBack('Calendar1','selectDay3')" style="color:Black">1</a> </td><td align="Center" style="width:14%;"> <a href="javascript:__doPostBack('Calendar1','selectDay4')" style="color:Black">2</a> </td><td align="Center" style="width:14%;"> <a href="javascript:__doPostBack('Calendar1','selectDay5')" style="color:Black">3</a> </td><td align="Center" style="width:14%;"> <a href="javascript:__doPostBack('Calendar1','selectDay6')" style="color:Black">4</a> </td></tr><tr><td align="Center" style="width:14%;"> <a href="javascript:__doPostBack('Calendar1','selectDay7')" style="color:Black">5</a> </td><td align="Center" style="width:14%;"> <a href="javascript:__doPostBack('Calendar1','selectDay8')" style="color:Black">6</a> </td><td align="Center" style="width:14%;"> <a href="javascript:__doPostBack('Calendar1','selectDay9')" style="color:Black">7</a> </td><td align="Center" style="width:14%;"> <a href="javascript:__doPostBack('Calendar1','selectDay10')" style="color:Black">8</a> </td><td align="Center" style="width:14%;"> <a href="javascript:__doPostBack('Calendar1','selectDay11')" style="color:Black">9</a> </td><td align="Center" style="width:14%;"> <a href="javascript:__doPostBack('Calendar1','selectDay12')" style="color:Black">10</a> </td><td align="Center" style="width:14%;"> <a href="javascript:__doPostBack('Calendar1','selectDay13')" style="color:Black">11</a> </td></tr><tr><td align="Center" style="width:14%;"> <a href="javascript:__doPostBack('Calendar1','selectDay14')" style="color:Black">12</a> </td><td align="Center" style="width:14%;"> <a href="javascript:__doPostBack('Calendar1','selectDay15')" style="color:Black">13</a> </td><td align="Center" style="width:14%;"> <a href="javascript:__doPostBack('Calendar1','selectDay16')" style="color:Black">14</a> </td><td align="Center" style="width:14%;"> <a href="javascript:__doPostBack('Calendar1','selectDay17')" style="color:Black">15</a> </td><td align="Center" style="width:14%;"> <a href="javascript:__doPostBack('Calendar1','selectDay18')" style="color:Black">16</a> </td><td align="Center" style="width:14%;"> <a href="javascript:__doPostBack('Calendar1','selectDay19')" style="color:Black">17</a> </td><td align="Center" style="width:14%;"> <a href="javascript:__doPostBack('Calendar1','selectDay20')" style="color:Black">18</a> </td></tr><tr><td align="Center" style="width:14%;"> <a href="javascript:__doPostBack('Calendar1','selectDay21')" style="color:Black">19</a> </td><td align="Center" style="width:14%;"> <a href="javascript:__doPostBack('Calendar1','selectDay22')" style="color:Black">20</a> </td><td align="Center" style="width:14%;"> <a href="javascript:__doPostBack('Calendar1','selectDay23')" style="color:Black">21</a> </td><td align="Center" style="width:14%;"> <a href="javascript:__doPostBack('Calendar1','selectDay24')" style="color:Black">22</a> </td><td align="Center" style="width:14%;"> <a href="javascript:__doPostBack('Calendar1','selectDay25')" style="color:Black">23</a> </td><td align="Center" style="width:14%;"> <a href="javascript:__doPostBack('Calendar1','selectDay26')" style="color:Black">24</a> </td><td align="Center" style="width:14%;"> <a href="javascript:__doPostBack('Calendar1','selectDay27')" style="color:Black">25</a> </td></tr><tr><td align="Center" style="width:14%;"> <a href="javascript:__doPostBack('Calendar1','selectDay28')" style="color:Black">26</a> </td><td align="Center" style="width:14%;"> <a href="javascript:__doPostBack('Calendar1','selectDay29')" style="color:Black">27</a> </td><td align="Center" style="width:14%;"> <a href="javascript:__doPostBack('Calendar1','selectDay30')" style="color:Black">28</a> </td><td align="Center" style="width:14%;"> <a href="javascript:__doPostBack('Calendar1','selectDay31')" style="color:Black">29</a> </td><td align="Center" style="width:14%;"> <a href="javascript:__doPostBack('Calendar1','selectDay32')" style="color:Black">30</a> </td><td align="Center" style="width:14%;"> <a href="javascript:__doPostBack('Calendar1','selectDay33')" style="color:Black">31</a> </td><td align="Center" style="width:14%;"> <a href="javascript:__doPostBack('Calendar1','selectDay34')" style="color:Black">1</a> </td></tr><tr><td align="Center" style="width:14%;"> <a href="javascript:__doPostBack('Calendar1','selectDay35')" style="color:Black">2</a> </td><td align="Center" style="width:14%;"> <a href="javascript:__doPostBack('Calendar1','selectDay36')" style="color:Black">3</a> </td><td align="Center" style="width:14%;"> <a href="javascript:__doPostBack('Calendar1','selectDay37')" style="color:Black">4</a> </td><td align="Center" style="width:14%;"> <a href="javascript:__doPostBack('Calendar1','selectDay38')" style="color:Black">5</a> </td><td align="Center" style="width:14%;"> <a href="javascript:__doPostBack('Calendar1','selectDay39')" style="color:Black">6</a> </td><td align="Center" style="width:14%;"> <a href="javascript:__doPostBack('Calendar1','selectDay40')" style="color:Black">7</a> </td><td align="Center" style="width:14%;"> <a href="javascript:__doPostBack('Calendar1','selectDay41')" style="color:Black">8</a> </td></tr> </table> <input type="hidden" name="__EVENTTARGET" value="" /> <input type="hidden" name="__EVENTARGUMENT" value="" /> <script language="javascript"> <!-- function __doPostBack(eventTarget, eventArgument) { var theform = document.WebForm1; theform.__EVENTTARGET.value = eventTarget; theform.__EVENTARGUMENT.value = eventArgument; theform.submit(); } // --> </script> </form> </body> </html>
Wow! That is quite a change. Notice that in Listing 3.5, you won't find <asp:calendar> anywhere. In fact you won't even find a runat=server! This stuff is of interest only to the server, so it is all stripped out of the page during the rendering process. What is rendered in this case is a combination of HTML and JavaScript.
However, the code on the server is concerned only with the Calendar control. You can programmatically access the code using its name (Calendar1). You can also get the date selected by the user by retrieving the SelectedDate property of the control. The developer doesn't care about all the HTML and JavaScript gibberish the control creates; the control is always accessed as an object, with high-level properties and methods. This layer of abstraction is one of the things that makes Web controls so powerful.
ASP.NET ships with a large number of Web controls.
Web Control Class |
HTML Tag |
AdRotator |
<asp:AdRotator .../> |
BoundColumn |
<asp:BoundColumn .../> |
Button |
<asp:Button .../> |
ButtonColumn |
<asp:ButtonColumn .../> |
Calendar |
<asp:Calendar .../> |
CheckBox |
<asp:CheckBox .../> |
CheckBoxList |
<asp:CheckBoxList .../> |
CompareValidator |
<asp:CompareValidator .../> |
CustomValidator |
<asp:CustomValidator .../> |
DataGrid |
<asp:DataGrid .../> |
DataList |
<asp:DataList .../> |
DropDownList |
<asp:DropDown .../> |
HyperLink |
<asp:Hyperlink .../> |
Image |
<asp:Image .../> |
ImageButton |
<asp:ImageButton .../> |
Label |
<asp:Label .../> |
LinkButton |
<asp:LinkButton .../> |
ListBox |
<asp:ListBox .../> |
ListControl |
Any list control |
ListItem |
<asp:ListItem .../> |
Panel |
<asp:Panel .../> |
PlaceHolder |
<asp:PlaceHolder .../> |
RadioButton |
<asp:RadioButton .../> |
RadioButtonList |
<asp:RadioButtonList .../> |
RangeValidator |
<asp:RangeValidator .../> |
RegularExpressionValidator |
<asp:RegularExpressionValidator .../> |
Repeater |
<asp:Repeater .../> |
RequiredFieldValidator |
<asp:RequiredFieldValidator .../> |
Table |
<asp:Table .../> |
TableCell |
<asp:TableCell .../> |
TableRow |
<asp:TableRow .../> |
TextBox |
<asp:TextBox .../> |
Xml |
<asp:Xml .../> |
For more information about each of these individual controls, see the control reference later in the chapter.
ASP.NET Is Event Driven
Prior to Visual Basic, programs were written in a top-down fashion. That is, a program started executing at the top and continued down through the bottom with the potential exception of subroutine or function calls. All that changed with the advent of Visual Basic and the concept of event-driven programming. No longer were programs written in a topto-bottom fashion. Instead, code was broken up into small blocks that reacted to events. These event handlers would then do the work in response to how the user interacted with the UI. Event-driven programming made things much easier for the programmer because it became possible to worry less about the order in which things occurred and more about how they actually worked.
ASP.NET again parallels this change. In ASP.old, programs were written to start execution at the top of the page and continue down to the bottom of the page. Again, a few exceptions existedfor example, calls to subroutines or functions. ASP.NET, however, moves the ASP programmer into the world of event-driven programming. Event handlers are written that correspond to the user's interaction with the UI. These event handlers perform all the work.
Let's use the SimplePage example from the previous section to illustrate this. After the Send button is pressed, we want to output some information about the selected items. Listing 3.6 shows the typical way this would have been done in ASP.old.
Listing 3.6 SimplePage3.aspA Typical Way to React to User Interaction in ASP.old
<html> <head> <title>SimplePage3.asp</title> </head> <SCRIPT LANGUAGE="VBScript" RUNAT=SERVER> function IsOptionSelected(strControlName, strOption) for iCount = 1 to Request(strControlName).Count if request(strControlName)(iCount) = strOption then response.write " SELECTED " end if next end function </SCRIPT> <body> <form name="WebForm1" method="post"> <p> <table border=0> <tr> <td>Name:</td> <td><input type=text name=txtName value="<% = Request("txtName") %>"></td> <td><input type=submit name=Button1 Value="Send"></td> </tr> <tr> <td valign=top>Hobby:</td> <td> <select name=lbHobbies Multiple> <option <% IsOptionSelected "lbHobbies", "Ski" %> Value="Ski">Ski</option> <option <% IsOptionSelected "lbHobbies", "Bike" %> Value="Bike">Bike</option> <option <% IsOptionSelected "lbHobbies", "Swim" %> Value="Swim">Swim</option> </select> </td> <td> </td> </tr> </table> <% If Request("Button1") ="Send" Then %> Name: <% = Request("txtName") %><BR> Hobby: <% For iCount = 1 to Request("lbHobbies").Count Response.Write Request("lbHobbies")(iCount) + ", " Next %> <% End If %> </p> </form> </body> </html>
At the bottom of the form, the code checks to see if the Send button contributed its value to the form value collection. If the value is there, work needs to be done, so it displays the data that was entered into the form. This code gets quite complex as the number of buttons and other items that the user interacts with increases.
Let's take a look at this same code in ASP.NET. Instead of executing top to bottom, we set up an event handler. Listing 3.7 shows the same page in ASP.NET. The controls have been replaced with Web controls, and an event handler named Button1_Click has been created. The event handler is connected to the code it runs by adding the onclick="..." attribute to the button control. This connects the button to the event handler.
Listing 3.7 SamplePage2.aspx Showing an Event Handler for Button1
<html> <head> <title>SimplePage2.aspx</title> </head> <script language="VB" runat=server> public sub Button1_Click(ByVal sender as Object, ByVal e as EventArgs) Dim strTemp as String Dim iCount as Integer ' Build up the output strTemp = "Name:" + txtName.Text + "<BR>Hobbies: " for iCount = 0 to lbHobbies.Items.Count - 1 if lbHobbies.Items(iCount).Selected Then strTemp = strTemp + lbHobbies.Items(iCount).Text + ", " end if Next ' Place it into the label that was waiting for it lblOutput.Text = strTemp end sub </script> <body> <form id="WebForm1" method="post" runat="server"> <p> <table border=0> <tr> <td>Name:</td> <td><asp:textbox type=text id=txtName runat=server /></td> <td><asp:button id=Button1 Text="Send" runat=server onclick="Button1_Click" /></td> </tr> <tr> <td valign=top>Hobby:</td> <td> <asp:listbox id=lbHobbies SelectionMode="Multiple" runat=server> <asp:listitem Value="Ski">Ski</asp:listitem> <asp:listitem Value="Bike">Bike</asp:listitem> <asp:listitem Value="Swim">Swim</asp:listitem> </asp:listbox> </td> <td> </td> </tr> </table> </p> <asp:label id=lblOutput runat=server /> </form> </body> </html>
The Button control in this example fires only a single event. Some more complex controls such as the Calendar control have the capability to fire several events.