Microsoft.NET

……………………………………………….Expertise in .NET Technologies

The Code Model

Posted by Ravi Varma Thumati on February 11, 2015

So far, you’ve learned how to design simple web pages, and you’ve taken a tour of the Visual Studio interface. But before you get to serious coding, it’s important to understand a little more about the underpinnings of the ASP.NET code model. In this section, you’ll learn about your options for using code to program a web page and how ASP.NET events wire up to your code.

Visual Studio supports two models for coding web pages:

Inline code: This model is the closest to traditional ASP. All the code and HTML markup is stored in a single .aspx file. The code is embedded in one or more script blocks. However, even though the code is in a script block, it doesn’t lose IntelliSense or debugging support, and it doesn’t need to be executed linearly from top to bottom (like classic ASP code). Instead, you’ll still react to control events and use subroutines. This model is handy because it keeps everything in one neat package, and it’s popular for coding simple web pages.

Code-behind: This model separates each ASP.NET web page into two files: an .aspx markup file with the HTML and control tags, and a .cs code file with the source code for the page. This model provides better organization, and separating the user interface from programmatic logic is keenly important when building complex pages.

In Visual Studio, you have the freedom to use both approaches. When you add a new web page to your website (using Website ➤ Add New Item), the Place Code in a Separate File check box lets you choose whether you want to use the code-behind model (see Figure below). Visual Studio remembers your previous setting for the next time you add a new page, but it’s completely valid to mix both styles of pages in the same application.

This flexibility only applies to projectless development. If you’ve created a web project, you must use the code-behind model—there’s no other choice. Furthermore, the code-behind model is subtly different for the code-behind model that’s used in a projectless website, as you’ll see shortly.

vscm1

Figure. Choosing the code model

To better understand the difference between the inline code and code-behind models, it helps to consider a simple page. The following example shows the mark-up for a page named TestFormInline.aspx, which displays the current time in a label and refreshes it whenever a button is clicked. Here’s how the page looks with inline code:

<%@ Page Language=”C#” %>

<!DOCTYPE html PUBLIC “-//W3C//DTD XHTML 1.1//EN”

http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd”&gt;

<script runat=”server”>

protected void Button1_Click(object sender, EventArgs e)

{

Label1.Text = “Current time: ” + DateTime.Now.ToLongTimeString();

}

</script>

<html xmlns=”http://www.w3.org/1999/xhtml&#8221; >

<head runat=”server”>

<title>Test Page</title>

</head>

<body>

<form id=”form1″ runat=”server”>

<div>

<asp:Label ID=”Label1″ runat=”server” Text=”Click Me!” />

<br /><br /><br />

<asp:Button ID=”Button1″ runat=”server” OnClick=”Button1_Click” Text=”Button” />

</div>

</form>

</body>

</html>

The following listings, TestFormCodeBehind.aspx and TestFormCodeBehind.aspx.cs, show how the page is broken up into two pieces using the code-behind model. This is TestFormCodeBehind.aspx:

<%@ Page Language=”C#” AutoEventWireup=”true” CodeFile=”TestFormCodeBehind.aspx.cs”

Inherits=”TestFormCodeBehind”%>

<!DOCTYPE html PUBLIC “-//W3C//DTD XHTML 1.1//EN”

http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd”&gt;

<html xmlns=”http://www.w3.org/1999/xhtml&#8221; >

<head runat=”server”>

<title>Test Page</title>

</head>

<body>

<form id=”form1″ runat=”server”>

<div>

<asp:Label ID=”Label1″ runat=”server” Text=”Click Me!”></asp:Label><br />

<br />

<br />

<asp:Button ID=”Button1″ runat=”server” OnClick=”Button1_Click”

Text=”Button” /></div>

</form>

</body>

</html>

This is TestFormCodeBehind.aspx.cs:

using System;

using System.Data;

using System.Configuration;

using System.Linq;

using System.Web;

using System.Web.Security;

using System.Web.UI;

using System.Web.UI.WebControls;

using System.Web.UI.WebControls.WebParts;

using System.Web.UI.HtmlControls;

public partial class TestFormCodeBehind : System.Web.UI.Page

{

protected void Button1_Click(object sender, EventArgs e)

{

Label1.Text = “Current time: ” + DateTime.Now.ToLongTimeString();

}

}

The only real difference between the inline code example and the code-behind example is that the page class is no longer implicit in the latter—instead it’s declared to contain all the page methods. Overall, the code-behind model is preferred for complex pages. Although the inline code model is slightly more compact for small pages, as your code and HTML grows it becomes much easier to deal with both portions separately. The code-behind model is also conceptually cleaner, as it explicitly indicates the class you’ve created and the namespaces you’ve imported. Finally, the code-behind model introduces the possibility that a web designer may refine the mark-up in your pages without touching your code. This book uses the code-behind model for all examples.

How Code-Behind Files Are Connected to Pages

Every .aspx page starts with a Page directive. This Page directive specifies the language for the page, and it also tells ASP.NET where to find the associated code (unless you’re using inline code, in which case the code is contained in the same file).

You can specify where to find the associated code in several ways. In older versions of ASP.NET, it was common to use the Src attribute to point to the source code file or the Inherits attribute to indicate a compiled class name. However, both of these options have their idiosyncrasies. For example, with the Inherits attribute, you’re forced to always precompile your code, which is tedious (and can cause problems in development teams, because the standard option is to compile every page into a single DLL assembly). But the real problem is that both approaches force you to declare every web control you want to use with a member variable. This adds a lot of boilerplate code.

You can solve the problem using a language feature called partial classes, which lets you split a single class into multiple source code files. Essentially, the model is the same as before, but the control declarations are shuffled into a separate file. You, the developer, never need to be distracted by this file—instead you can just access your web-page controls by name. Keen eyes will have spotted the word partial in the class declaration for your web-page code:

public partial class TestFormCodeBehind : System.Web.UI.Page

{ … }

With this bit of infrastructure in place, the rest is easy. Your .aspx page uses the Inherits attribute to indicate the class you’re using, and the CodeFile attribute to indicate the file that contains your code-behind, as shown here:

How Control Tags Are Connected to Page Variables

When you request your web page in a browser, ASP.NET starts by finding the associated code file. Then, it generates a variable declaration for each server control (each element that has the runat=”server” attribute).

For example, imagine you have a text box named txtInput:

<asp:TextBox id=”txtInput” runat=”server”/>

ASP.NET generates the following member variable declaration and merges it with your page class using the magic of partial classes:

protected System.Web.UI.TextBox txtInput;

Of course, you won’t see this declaration, because it’s part of the automatically generated code that the .NET compiler creates. But you rely on it every time you write a line of code that refers to the txtInput object (either to read or to write a property):

txtInput.Text = “Hello.”;

Inherits=”TestFormCodeBehind”%>

Notice that Visual Studio uses a slightly unusual naming syntax for the source code file. It has the full name of the corresponding web page, complete with the .aspx extension, followed by the .cs extension at the end. This is just a matter of convention, and it avoids a problem if you happen to create two different code-behind file types (for example, a web page and a web service) with the same name.

To make sure this system works, you must keep both the .aspx markup file (with the control tags) and the .cs file (with the source code) synchronized. If you edit control names in one piece using another tool (such as a text editor), you’ll break the link, and your code won’t compile.

Incidentally, you’ll notice that control variables are always declared with the protected accessibility keyword. That’s because of the way ASP.NET uses inheritance in the web-page model. The following layers are at work:

  1. The Page class from the .NET class library defines the basic functionality that allows a web page to host other controls, render itself to HTML, and provide access to the traditional ASPstyle objects such as Request, Response, and Session.
  2. Your code-behind class (for example, TestFormCodeBehind) inherits from the Page class to acquire the basic set of ASP.NET web-page functionality.
  3. When you compile your class, ASP.NET merges some extra code into your class (using the magic of partial classes). This automatically generated code defines all the controls on your page as protected variables so that you can access them in your code.
  4. The ASP.NET compiler creates one more class to represents the actual .aspx page. This class inherits from your custom code-behind class (with the extra bit of merged code). To name this class, ASP.NET adds _aspx to the name of the code-behind class (for example, TestFormCodeBehind_aspx). This class contains the code needed to initialize the page and its controls and spits out the final rendered HTML. It’s also the class that ASP.NET instantiates when it receives the page request.

vscm2

Figure. How a page class is constructed

So, why are all the control variables and methods declared as protected? It’s because of the way inheritance is used in this series of layers. Protected variables act like private variables, with a key difference—they are accessible to derived classes. In other words, using protected variables in your code-behind class (for example, TestFormCodeBehind) ensures that the variables are accessible in the derived page class (TestFormCodeBehind_aspx). This allows ASP.NET to match your control variables to the control tags and attach event handlers at runtime.

How Events Are Connected to Event Handlers

Most of the code in an ASP.NET web page is placed inside event handlers that react to web control events. Using Visual Studio, you can add an event handler to your code in three ways:

Type it in by hand: In this case, you add the method directly to the page class. You must specify the appropriate parameters so that the signature of the event handler exactly matches the signature of the event you want to handle. You’ll also need to edit the control tag so that it links the control to the appropriate event handler, by adding an OnEventName attribute. (Alternatively, you can use delegates to wire this up programmatically.)

Double-click a control in design view: In this case, Visual Studio will create an event handler for that control’s default event (and adjust the control tag accordingly). For example, if you double-click the page, it will create a Page.Load event handler. If you double-click a Button control, Visual Studio will create an event handler for the Click event.

Choose the event from the Properties window: Just select the control, and click the lightning bolt in the Properties window. You’ll see a list of all the events provided by that control. Double-click in the box next to the event you want to handle, and Visual Studio will automatically generate the event handler in your page class and adjust the control tag.

The second and third options are the most convenient. The third option is the most flexible, because it allows you to select a method in the page class that you’ve already created. Just select the event in the Properties window, and click the drop-down arrow at the right. You’ll see a list that includes all the methods in your class that match the signature this event requires. You can then choose a method from the list to connect it. Figure 2-21 shows an example where the Button.Click event is connected to the Button_Click() method in your page class. The only limitation of this technique is that it works exclusively with web controls, not server-side HTML controls.

vscm3

Figure 2-21. Attaching an event handler

Visual Studio 2008 uses automatic event wire-up, as indicated in the Page directive. Automatic event wire-up has two basic principles:

  • All page event handlers are connected automatically based on the name of the event handler. In other words, the Page_Load() method is automatically called when the page loads.
  • All control event handlers are connected using attributes in the control tag. The attribute has the same name as the event, prefixed by the word On.

For example, if you want to handle the Click event of the Button control, you simply need to set the OnClick attribute in the control tag with the name of the event handler you want to use.

Here’s the change you need:

<asp:Button id=”cmdOK” OnClick=”cmdOK_Click” runat=”server”>

ASP.NET controls always use this syntax. Remember, because ASP.NET must connect the event handlers, the derived page class must be able to access the code-behind class. This means your event handlers must be declared with the protected or public keyword. (Protected is preferred, because it prevents other classes from seeing this method.)

Of course, if you’re familiar with .NET events, you know there’s another approach to connect an event handler. You can do it dynamically through code using delegates. Here’s an example:

cmdOK.Click += cmdOK_Click;

Leave a comment