WindowsDevCenter.com
oreilly.comSafari Books Online.Conferences.

advertisement


AddThis Social Bookmark Button

Learning ASP.NET for the ASP Developer - Part 3

by Neel Mehta
12/06/2004

Part 3: Scaling Up

In the final part of this tutorial, we will demonstrate how to construct large scale ASP.NET websites. In the previous tutorials of this series, we saw how to build single ASP.NET pages where all the code for a page was written on the page itself. This approach can quickly get tedious when you have code that is common across several pages. Thus, one of the most important elements in sites with a large number of pages is the ability to share code. Hence, we first describe ways in which to write code that can be used by multiple pages without the need for repeating the code on each page. Then, we will outline an efficient way to improve the performance of serving ASP.NET pages, a task that would be quite cumbersome in classic ASP. Like the prior two parts, our emphasis is using our ASP knowledge to develop a conceptual understanding of ASP.NET. As I had mentioned earlier, we are not looking for a line-by-line conversion method from classic ASP to ASP.NET as much as to leverage our existing classic ASP knowledge to learn ASP.NET.

ASP.NET "Includes"

In classic ASP, you can write code in a file and then "import" it in on another page by using <!-- #INCLUDE virtual = "Name_of_file_that_has_common_code.asp" -->. This statement has the effect of "pasting" the common code in the place of the <!-- #INCLUDE ... -->. In ASP.NET, on the other hand, there is an equivalent way to INCLUDE code, but the implementation details are quite different.

We saw, in the first part of this tutorial, that ASP.NET has "intelligent" tags or controls which "know" how certain data has to be rendered on the browser. (The <asp:DataGrid> is an example of a web control which "knows" that data associated with it is rendered within an HTML table.) In addition, ASP.NET allows you to define your own markup tags or custom controls. The presentation markup "instructions" for these custom controls is specified in another file (with an .ascx extension with a c instead of the p. You can think of the c in the .ascx extension to stand for custom control.) Only the tag for the custom control is written on the .aspx page just like any other control or presentation tag. But, when the web page with the .aspx page is sent to the browser, the custom control is replaced by the markup information specified in the separate file. Thus, you can use this ability of ASP.NET to define your own controls to "bring in" code from another file.

On the .aspx page, you need to specify which .ascx page the control is associated with along with the name you want to call this custom control in your .aspx page. The reference to the .ascx page is made using the <%@ Register ... %> directive. The tag names and prefixes used to "call" the custom control are specified as attributes of this directive. Finally, the page with an .ascx extension, on the other hand, has a <%@ Control ... %> directive instead of the <%@ Page ... %> directive on .aspx pages. Apart from this difference, a page with an .ascx extension is very similar in structure to a page with an .aspx extension.

Below is an example of an .ascx page and how it's referenced in a page with an .aspx extension.


SimpleCustomControl_vb.ascx
<%@ Control Language="VB" %>
<script runat="server">
Public Color As String
</script>
  <font color="<%=Color%>">This text will replace the custom 
  control tag on the .aspx page.</font>

SimpleCustomControl_vb.aspx
<%@ Page Language="vb" %>
<%@ Register TagPrefix="My" TagName="NewTag" Src="SimpleCustomControl_vb.ascx" %>
<html>
  <head>
  </head>
  <body>
    <form runat="server">
      <p>
        <My:NewTag color="red" runat="server" />
      </p>
    </form>
  </body>
</html>

Note how the Color attribute on the My:NewTag control in the .aspx can set the color of the text in the custom control.

While the example shown is quite basic, custom controls can be as advanced as you like. We can even use web controls and programmatically access and modify their attributes.

The important thing to bear in mind, though, is that, similar to the classic ASP INCLUDE file, you only have to make changes to the markup code in the .ascx file and not on every page that references the custom control. Page navigation elements are, thus, often defined as custom controls. For more details and an excellent and quick introduction to custom controls, see this asp101 lesson.

Thus far, we have talked about the structure of an ASP.NET page and how we can achieve separation of server side code from presentation markup details. We have seen that ASP.NET web controls can be powerfully effective in reducing the amount of HTML and JavaScript that we have to explicitly write. We have also seen how to define custom controls, which is similar to the classic the ASP server side includes. Moreover, ASP.NET has another way of pulling out common code to a separate page. The page with the pulled out code is called the "code-behind" page, which simply means the "server side code behind the ASP.NET page." Pulling code out and placing it in a separate file has the advantage of further separating presentation from code. Graphically, what we want to accomplish is shown below:

Code to pull out
Figure 1. Code to pull out.

Related Reading

ASP.NET in a Nutshell
By G. Andrew Duthie, Matthew MacDonald

While pulling the script side code into a separate code-behind file, let us make a slight change. We can certainly continue to use Visual Basic as our server side script language. Let us take this opportunity, however, to switch languages to C# (pronounced c-sharp).

The code-behind file takes the extension of the scripting language used. Since we are using C#, the extension of the code-behind file is .cs. If we were using Visual Basic, the extension of the code-behind file would be .vb.

In classic ASP, when moving code to an Include file, we literally "cut-and-pasted" from the "mother" .asp page to a separate INCLUDE file. In ASP.NET, the code that gets moved to the code-behind page is also pretty much the same as in the "mother" .aspx page but is structured a little differently.

When pulling the script-side code to a separate file, the Page directive on the original .aspx file does not migrate over--it stays on the .aspx file itself and forms the glue between the .aspx file and the code-behind .cs file. The src attribute on the Page directive specifies the name of the code-behind file.

Code-behind files always have a namespace and at least one class specification within it. Thus, the Page directive also has an attribute that specifies the namespace and class from the code-behind page that gets inherited on the .aspx page. These specifications make the code within the referenced class "available" to the .aspx page. Below is an example of a Page directive which references a code-behind file:

<%@ Page Language="C#" Src="DataGrid_Codebehind.aspx.cs" 
     Inherits="MyNamespace.MyClass" %>

The structure of the code-behind behind is as follows:

namespace MyNamespace {
using System;

  public class MyClass {

    // Script code goes here
  } 
}

Note how the Inherits attribute on the Page directive references the namespace and class on the code-behind page. Once a class has been defined, you can now place the code from the original .aspx page.

Since the code-behind file is a totally separate file from the original .aspx file, any web controls that were being referenced in the original script-side block cannot be accessed without explicitly importing the System.Web.UI.Controls class. (In C#, the import directive is replaced with the using namespace; statement.) The class that uses these controls must inherit the SystemWeb.UI.Page class. Finally, you must declare the controls that will be accessed in your code. While declaring the controls, you make them protected, which means that they are accessible only within the code-behind code and the presentation page that inherits from it. Class inheritance will then make these controls available in the code-behind code so that you can access the controls and associate records to them, etc., just as you would on the .aspx page itself.


using System;
using System.Web.UI.WebControls; // import web controls 
namespace MyNamespace {
  public class MyClass : System.Web.UI.Page { 
    protected DataGrid DataGrid1; // Declare controls
    void Page_Load() {
      // Script code goes here
    } // end of Page_Load function
  } // end of MyClass
} // end of MyNamespace

At this point, you can now "cut-and-paste" the code from the original .aspx page into the code-behind page. Below is the complete code-behind code for assigning records from a database table to a DataGrid. You can see the similarity between the original code in the .aspx file and how it's specified in the code-behind file.

DataGrid_Codebehind.aspx.cs
using System.Web.UI.WebControls; // import web controls
using System.Data; // import for DataSet class
using System.Data.SqlClient; // import for SQL Server classes

namespace MyNamespace {
  
  public class MyClass : System.Web.UI.Page {
    // Controls from the HTML page
    protected DataGrid DataGrid1;

    void Page_Load() {	
      // Set up the SQL Server database connection
      string ConnStr = "server='(local)'; trusted_connection=true; database='Demo'";
      DataSet RecordSet = new DataSet();
      // Now, pull the records from the database
      string SQL = "Select * from Books";
      SqlDataAdapter RecordSetAdpt = new SqlDataAdapter(SQL,ConnStr);
      RecordSetAdpt.Fill(RecordSet);

      // Set the data grid's source of data to this recordset and bind
      DataGrid1.DataSource = RecordSet.Tables[0].DefaultView;
      // Finally, bind this data to the control
      DataGrid1.DataBind();
	  
    } // end of Page_Load()
  } // end of MyClass
} // end of MyNamespace

The code in the .aspx file is:

<%@ Page Language="C#" Src="DataGrid_Codebehind.aspx.cs" 
     Inherits="MyNamespace.MyClass" %>
<html>
  <head>
  </head>
  <body>
    <form runat="server">
      <asp:DataGrid id="DataGrid1" runat="server"></asp:DataGrid>
    </form>
  </body>
</html>

As you can see from comparing the code above to the DataGrid code in Visual Basic described in Part 1, switching to C# is not a major undertaking. In fact, you should have no trouble following the C# code; in this case, the C# code is almost the same as the Visual Basic code. The reason for this close similarity is that we are essentially just using properties and methods of imported objects. In general, however, you will see greater differences. But, in a very loose sense, C# is a lot like JavaScript. Thus, instead of the if ( ) then ... endif construct in Visual Basic, you have if ( ) { ... } construct in C#. A few other salient points of C# that you will find useful as you transition from Visual Basic to C#:

  1. Every statement in C# must end with a semi-colon
  2. C# comments begin with //; multi-line comments are enclosed within /* ... */
  3. Use Session["YOUR_SESSION_VARIABLE"] with the square brackets [ ... ] instead of parenthesis ( ... )
  4. In C#, variables are defined with the type first as in string MY_STRING_VAR = "initial value" while in Visual Basic we use Dim MY_STRING_VAR as String = "initial value"
  5. String concatenation is done using "+" in C# ("&" in Visual Basic)
  6. Logical operators (AND, NOT, OR, etc.) are similar to JavaScript (&&, !, ||, etc.)
  7. To access individual fields of records extracted from the database, you can use Record["FIELD_NAME"] where Record is of type DataRow as in DataRow Record

(This is only a "cheat-sheet" overview of C# and does not do justice to the full range of programming constructs available, but it should get you started.)

Finally, a code-behind file can be referenced by several .aspx pages as the following graphic shows:

Multiple pages using code-behind
Figure 2. Multiple pages using code-behind.

Hence, the code-behind files serve a similar purpose, albeit implemented differently, as the Server Side Includes in classic ASP, in that common code is not duplicated.

If you have certain classes in your code-behind code which are being used on the majority of your web pages, then it may be more efficient to create what are known as assemblies and then import these assemblies like the other namespaces. Creating and importing your own custom assemblies will reduce the amount of code in your code-behind page. Building assemblies, though, is beyond the scope of this article. For more information on how to create and register assemblies, please refer to the book ASP.NET in a Nutshell.

Finally, with this introduction to code-behinds, I'd like to end this section by suggesting why the term "forms" is so prevalent in ASP.NET. "Forms" are reminiscent of programming in Visual Studio where you would build the graphical user interface (GUI) by dragging and dropping controls onto a "work-area" called a "Form." The code that drives the form is placed on a separate window which you access by right-clicking on the "Form" in the Visual Studio Project pane and selecting "View Code." Visual Studio managed the relevant associations internally, so you didn't need Page directives. Thus, the terminology from Visual Studio is carried over into ASP.NET. Hopefully, this explanation should help clear some of confusion between ASP.NET forms and standard HTML forms.

Pages: 1, 2

Next Pagearrow