This week, in Part 2 of our tutorial, we will continue our investigation of ASP.NET from a classic ASP developer's perspective. Last week, In Part 1, we showed how ASP.NET allows us to cleanly separate presentation markup from server side script code. Today, we will delve deeper and demonstrate how an ASP.NET page is put together. Finally, in the concluding article of this three part tutorial, we will build upon the concepts of the first two parts and illustrate how you can build large-scale web sites using ASP.NET.
In the first part of this tutorial,
I motivated ASP.NET through tags such as
<asp:DataGrid> and </asp:DataGrid> without
going into much detail about their structure. This was deliberate, as I wanted to
give you an overall appreciation of the concepts without getting into mundane
details that take away from the development of the main ideas. You also
may have observed some additional code in our examples above which we glossed over
earlier. In this part, though, it's time to get formal
with the implementation. Later, we will also look at a few more presentation tags to give you a glimpse
of the richness of ASP.NET.
The first thing to note is that any ASP.NET page that is requested from a server has an
I make the qualification about the page that's requested because, just as in classic
ASP, there are certain "include" pages which have different extensions. These pages,
however, cannot be accessed directly.
In ASP.NET, as opposed to classic ASP, a web page is represented as a
Page class. While this
may at first seem an unnecessary complication, we'll soon see that having a
Page class actually provides
an efficient way to think about the structure of a page
because it's the "container" for all
the elements which appear on the page. The
Page class is globally available
on the page. Hence, you don't have to explicitly reference it when accessing its properties
set the attributes on this object. Thus, within
an ASP.NET page, the very first thing you typically write is the "Page" directive.
This directive is where you specify the scripting language and several other options, such as whether you want
to see detailed error messages. We will discuss a few of these options.
The general format for this directive
is given below (text between
[ ... ] is optional):
<%@ Page attribute="value" [attribute="value"...]%>
A comprehensive list of the
Page attributes is available from the book,
in a Nutshell book as well as from the Microsoft web site.
Language attribute is used to specify the scripting language that will be used.
ASP.NET supports several languages, including Microsoft's new language, C# (pronounced
C-sharp), which was developed specifically for ASP.NET. In our examples until now,
we used Visual Basic (VB), but later we will transition to C#.
when set to
"True", gives detailed error reports when a bug is encountered. While no
one enjoys bugs in their code, you will find these error messages quite informative,
often giving you explicit corrections.
Trace attribute allows you to write statements
for debugging without having to remove them from your code when you are done. Recall that in classic
ASP, you would use the "Response.Write/Response.End" pair of statements to display the
value of variables. The downside about the classic ASP approach is that once you had fixed the
bug, you had to go back to your code and remove these statements so that the page
could be processed normally. With the
Trace feature enabled, you can write the variables
Trace object which are then displayed in the browser at the bottom of your
page. Thus, you don't have to create "artificial" debug statements to test the program
ServerVariables are also shown, which can provide useful information
in your debugging efforts. Since the Trace object is only displayed when this feature
is enabled, it's easy to turn off by setting the
"false" without impacting the rest of the code. Another advantage of retaining your
debug statements is that you can equally easily turn it back on if you need
to debug your page again.
Below is an example of how to specify a Page directive with the Trace and Debug attributes:
<%@ Page Language="vb" Debug="True" Trace="True" %>
Note that you once you have finished debugging and testing your code, you should set
Debug attributes to
"False" to prevent detailed error messages being
shown in production, in case your code encounters a bug.
With the Page directive behind us, we then specify the "script" block similar to classic
ASP. Whereas in classic ASP, we typically used the
<% ... %> tags to enclose
any server side code, in ASP.NET we use
<script> ... </script>."
To distinguish between the
code on the page, a
runat="server" attribute is used to unambiguously specify
that the code this tag encloses is evaluated by the server. In fact, the
attribute is used on any tag that needs to be accessed by the server side script code.
Once you have defined the script tags in classic ASP, you can immediately begin writing your code. In ASP.NET, however, all statements must go within functions. The only statements that are valid outside any function are those that define global variables. You cannot simply start writing code as you did in classic ASP. You can either write your own functions and then call them in your code or you can use functions that are triggered on certain events. For example, the "Page_Load" function is invoked when all the elements on the page have been "loaded." The "Page_Init" function, on the other hand, is initiated when the page is requested. You typically use one of these functions to get things started. Then, once your code has begun processing, you can write other functions to carry out additional tasks.Finally, in ASP.NET, all tags have to be well-formed. Thus, you cannot write
<asp:DataGrid id="DataGrid1" runat="server">without properly closing the
asp:DataGrid. Instead, you need to close it either with
<asp:DataGrid ... />.
Thus, the beginning of the code in ASP.NET takes the following initial form:
<%@ Page Language="vb" Debug="True" Trace="True" %> <script runat="server"> Sub Page_Load() End Sub ' end of Page_Load </script> <html> <head> </head> <body> </body> </html>
In classic ASP, the six
intrinsic classes, Application, ObjectContext, Request, Response, Server, and Session
are the top-level classes. In ASP.NET, the
Page class is the top level one.
The classic ASP intrinsic objects have been replaced by the HttpApplicationState, HttpContext,
HttpRequest, HttpResponse, HttpServerUtility, and the HttpSessionState classes, respectively.
In addition, a few more have been also added.
Thus, for example, the classic ASP Request class is now the HttpRequest class in ASP.NET.
Fortunately, though, the HttpRequest class is exposed as the
of the Page class. As a result, your classic ASP code for the Request class
will be unchanged when migrated to ASP.NET. The same is true for the HttpResponse
class as well as the HttpSessionState class.
In addition to the Page class, ASP.NET has numerous classes which you can use in your code. These can save you a lot of work. There are classes to access the file system, dynamically draw images, access databases, screen scrape other pages, and several other tasks which are quite cumbersome to code in classic ASP. We'll talk about how to access other classes in your code. However, the bigger question is how do you know which classes you need to use in the first place. We'll address this question later in the third part of the tutorial, where we outline a tool for ASP.NET development.
To access the members of a particular class, you use the fully qualified name for
that class. Unlike classic ASP, there is no need to use a
in your code. You can simply use the corresponding class directly in your code. So,
for example, if you want to access your web server's file system folders, you would
System.IO class in your code just as simply as using, say,
There is no need to first create a
File Scripting object, as in classic ASP, nor the need
to register any external components, as is also often used in classic ASP. In ASP.NET,
you can use these classes just like you would the intrinsic objects in classic ASP.
As I mentioned earlier, because, for example, the
HttpRequest class is exposed as the
Request property of the
Page class, you do not need to explicitly refer to the
class in your code and can simply use statements like
stringvar = Request("myvar") in
your code. But, when you use other classes, such as the
System.IO class, you have
to use the fully qualified name to access their properties and methods. So, if
you want to get all the files in a folder, you can use the following code, which will
return an array of the files:
If you are doing a lot of file system lookups, you will have to qualify
the method or propery with the mind-numbing
System.IO prefix every time. Fortunately,
ASP.NET provides a great "shortcut," which is implemented using
is, you can instruct ASP.NET to bring in or
import external class assemblies into your code.
Importing namespaces allows
you to reference the properties and methods of the imported classes just like
you do for the
Page class. In other words, you can drop the
instead use just
makes your code a lot more readable, and thus, easier to maintain.
You specify the namespaces you
want imported after you specify the
Page directive and before the
</script> tags. (To import multiple namespaces, use a separate
<%@ import ... %>
directive for each namespace.)
<%@ Page Language="vb" Debug="True" Trace="True" %> <%@ Import Namespace="System.IO" %> <script runat="server"> Sub Page_Load() End Sub ' end of Page_Load </script>
In this section, we outline, at a high level, how to connect to a SQL Server database and extract records. You can also, of course, connect to other databases. However, ASP.NET has optimized the connection to SQL Server. Detailed description of connecting to the database, or connecting to another database, is beyond the scope of this article.
Below is the code snippet we use to connect to a SQL Server database:
' SET UP THE SQL SERVER DATABASE CONNECTION string ConnStr = "server='(local)'; trusted_connection=true; database='Demo'"; DataSet RecordSet = new DataSet(); ' NEED TO IMPORT THE System.Data NAMESPACE TO USE THE DataSet TYPE ' NOW PULL THE RECORDS FROM THE DATABASE string SQL = "Select * from Books"; SqlDataAdapter RecordSetAdpt = new SqlDataAdapter(SQL,ConnStr); RecordSetAdpt.Fill(RecordSet); ' EXTRACTED RECORDS ARE IN RecordSet
In order for us to use the various SQL Server methods above, we have to first import
System.Data.SqlClient namespace. The records extracted are available
RecordSet variable. Each extracted record is in a row in the RecordSet.
If we have a DataGrid defined in the presentation block, we can simply assign the
DataSource of the DataGrid to this RecordSet:
DataGrid1.DataSource = RecordSet.Tables(0).DefaultView
As we saw in the first part of this tutorial,
there is no need to individually go through each row of the record set and format
the information in each record as in classic ASP. In ASP.NET, the formatting of the data in each field
is taken care in the DataGrid's attributes in the presentation block. Finally,
note that since we are using the
DataSet class to define the
we need to import the
Thus, the complete code listing to display a table of books is:
<%@ Page Language="vb" Debug="True" Trace="True" %> <%@ import Namespace="System.Data" %> <%@ import Namespace="System.Data.SqlClient" %> <script runat="server"> 'System.Web.UI.Controls namespace for the DataGrid control 'System.Data namespace for the Dataset class 'System.Data.SqlClient namespace for SQL server classes Sub Page_Load() 'Set up the SQL Server database connection Dim ConnStr As String = "server='(local)'; trusted_connection=true; database='Demo'" Dim RecordSet As DataSet RecordSet = new DataSet() 'Now, pull the records from the database Dim SQL As String = "Select * from Books" Dim RecordSetAdpt As new SqlDataAdapter(SQL, ConnStr) RecordSetAdpt.Fill(RecordSet) 'Set the data grid's source of data to this recordset DataGrid1.DataSource = RecordSet.Tables(0).DefaultView 'Finally, bind this data to the control DataGrid1.DataBind() End Sub ' end of Page_Load </script> <html> <head> </head> <body> <form runat="server"> <p> <asp:DataGrid id="DataGrid1" runat="server"></asp:DataGrid> </p> </form> </body> </html>
Obviously, not all content on a web page will fit neatly into tables. ASP.NET
provides the ability to display all kinds of rich content on a page through assorted presentation
tags. The basic concept, however, is similar to the way we associated records from
a database table to the
DataGrid tag. In fact, the concept is not unlike DHTML, except
that whereas DHTML takes place on the client side, dynamically associating content
with ASP.NET presentation tags is entirely on the server side.
The presentation tags are essentially of two types: tags that have a direct counterpart
in HTML and those that don't. These presentation tags have the same structure as
regular HTML, except that every tag must be properly closed. In ASP.NET, these tags
are referred to as "controls." Thus, the tags associated with HTML elements are called
HTML Controls, while the others are Web Controls. All tags have a
runat="server", to indicate that these tags can be
programmatically accessed on the server. Also, all web controls need to be within
runat="server"> ... </form> tags. (The name "form" seems at first to
be a misnomer, but in the next part we'll shed some light as to why it's named as such.)
There are several web controls which you can use to present the content on your web page. You will have to make a determination as to which control best matches the content you want to present. In our example, the data grid was sufficient to present the book information in a tabular format. Each control, in turn, has attributes to further refine the HTML output produced. The list of controls and attributes are beyond the scope of this article. The list need not, however, be daunting. Microsoft has produced a development environment, Web Matrix, for building ASP.NET applications, complete with its own web server and SQL Server database (both can only be used for testing and not for production). Web Matrix enumerates the controls available together with their properties. In addition, it also includes some documentation to guide you when you are inserting controls on your page. More information on WebMatrix can be found at http://www.asp.net/webmatrix/default.aspx?tabIndex=4&tabId=46
We have already seen the power of the
In this section, we'll just touch on two of the controls to give you a feel as to
how to use them.
One of the simplest types of web controls is the
Label control. This control is
similar to the HTML
<span>. It lets you "reserve" an area on
the web page in which you can then assign HTML content in the script block. The
attribute of the
Label control sets the content that gets inserted into the control.
So, here's an example of how to use a
Label control in an ASP.NET page:
<%@ Page Language="VB" %> <script runat="server"> Sub Page_Load() Label1.Text = "This <b>text</b> gets placed on the control" End Sub </script> <html> <head> </head> <body> <form runat="server"> <asp:Label id="Label1" runat="server">Label</asp:Label> </form> </body> </html>
When this page is requested, the content within the
<asp:Label> ... </asp:Label>
tags in the presentation block will be replaced by the content that is set using the
Text property in the server-side script block before being delivered.
(Server-side script is always evaluated first.) Thus, in this case, the content within
Label control in the presentation block plays absolutely no part and could have
presentation section will be streamed to the browser but based on some action on client
and changes the text.
Note that since we are explicitly assigning content to the
Text property, there is
no need for data binding.
Another example of a control to illustrate the power of ASP.NET is in the validation of HTML form input fields. The following code listing shows how an input field can be restricted to accept only integer values between 10 and 20.
<%@ Page Language="VB" %> <script runat="server"> Sub Submit_Click(Sender As Object, e As EventArgs) ' Code to execute when the user has submitted form End Sub </script> <html> <head> </head> <body> <form runat="server"> <p> Enter value between 10 and 20 </p> <p> <asp:TextBox id="TextBox1" runat="server"></asp:TextBox> <asp:RangeValidator id="RangeValidator1" runat="server" ErrorMessage="Entry out of range" ControlToValidate="TextBox1" Type="Integer" MaximumValue="20" MinimumValue="10"> </asp:RangeValidator> </p> <p> <asp:Button id="Button1" onclick="Submit_Click" runat="server" Text=" Submit"> </asp:Button> </p> </form> </body> </html>
The key steps are to specify a
runat="server" attribute on the HTML input
form field so that it can be accessed using its ID in the script block
and also to specify the
ControlToValidate on the
The valid range, as well as other presentation information, such as the
error message if an entry is invalid, are also set as attributes.
<asp:RangeValidator> ... </asp:RangeValidator>
will cause an implicit server side script evaluation.
You may have noticed a new control,
asp:Button is a web control
which is similar to the standard
Submit type of an HTML input field,
<input type="submit" value="Submit">. The primary difference is that the
onClick attribute will invoke a function
(in this case, the
Submit_Click(...) function) on the server side, whereas
onClick attribute on the standard
<input ... > HTML tag will invoke a
Submit_Click(...) function is where you would write
code to process the form inputs, post to a database, etc. (This
code is for illustration purposes only. Hence, we have left this function empty.)
The above code to validate an input field gives the following familiar form when viewed in a browser:
There are more advanced ways to validate HTML form input fields. For example, the
allows you to base form validation on
regular expressions, thereby giving complete control on the types of entries you want
to limit your site's users to. You use this validator in essentially the same way
as the range validator.
Another control that you may also find useful is the control used to automatically
create a list of checkbox options. In these cases, you typically have a set of selections
which you want to show as a list of checkbox options. In classic ASP, you would
have to write a loop to go through the selection set and write the corresponding HTML.
In ASP.NET, like the DataGrid example in the first part of this tutorial, you can simply assign the selection options
to the "DataSource" of the
<asp:CheckBoxList> ... </asp:CheckBoxList>
control. And, once every control's data source has been set, use the
method to actually populate the controls with the appropriate data.
Again, you will undoubtedly observe that there are several control and attributes to precisely define how content can be rendered, and you must be wondering if there is a lot of memorization to use ASP.NET effectively. In fact, the above code was created by "drag and drop" using Microsoft's new ASP.NET development environment, Web Matrix. As a result, you do not have to memorize the various attributes. Rather, it's more important to know how ASP.NET is structured so that you can use Web Matrix effectively.
Neel Mehta has a doctorate from the University of Pennsylvania and is an ardent fan of .NET and sees it as one of the few technologies that will be around for some time.
Return to ONDotnet.com.
Copyright © 2009 O'Reilly Media, Inc.