ONDotNet.com    
 Published on ONDotNet.com (http://www.ondotnet.com/)
 See this if you're having trouble printing code examples


Writing ASP.NET Web Forms with C#

by Budi Kurniawan
06/21/2001

Web Forms are a programming model in ASP.NET, the next generation of Web programming technology from Microsoft.

This article discusses Web Forms by first comparing ASP.NET and the classic ASP. It then presents server controls and paints a big picture of how separation between business logic and presentation layer is achieved in Web Forms. In addition, this article presents the new session-management strategy and offers some programming experience in building Web Forms using the C# language. Web Forms are a Web development technology that allows you to build a robust and scalable Web application rapidly. Programming languages that you can use to build Web Forms are many; you can use C#, Visual Basic.Net and JScript.NET, to name a few. Like other server-side Web technologies, Web Forms output standard HTML that can be rendered by all browsers. However, the engine that runs Web Forms also detects user browsers, and can generate browser-specific HTML tags, if you so desire.

Web Forms are also object-oriented, even though they are still hosted in ASP-like pages. Web Forms also provides easy separation between presentation layer and business logic. The code can be written in the same page as the user interface or stored separately in a different file. Using a RAD tool like Visual Studio.NET, Web Forms programming is even easier and more rapid.

Among the benefits that the new technology brings, the most important is probably the session management strategy that allows user sessions to be maintained without depending on cookies and or sacrificing scalability. As you will see, the new session management can also be set to work in a Web farm. Better still, the programming part is still the same as in classic ASP.

To introduce Web Forms, first the comparison with ASP, something that you might already be familiar with.

Comparing ASP and ASP.NET

The first cosmetic difference between ASP and ASP.NET is the page extension. ASP pages have an .asp extension; ASP.NET has changed it to .aspx. For backward compatibility, however, ASP.NET still supports the programming model of ASP. Therefore, though your pages now have an .aspx extension, you can still use the old ASP style to build spaghetti-like code, interweaving code and HTML tags, like the following.

<%@ Page Language="C#" %>
<html>
<head>
<title>ASP.NET Using the old ASP style</title>
</head>
<body>
<IMG SRC="logo.jpg">
<BR>
<%
  for (int i=0; i<6; i++) {
    Response.Write(i + "<BR>");
  }
%>	
</body>
</html>

Comment on this articleWhat are your experiences with Web form development with C# or even other programming languages?
Post your comments

Note, though, that the default language in ASP.NET is Visual Basic.NET. So, if you are using C#, you need to include the Language attribute in the Page directive in the first line. With ASP.NET there is a new programming model: Web Forms. The most important difference from ASP is that in Web Forms you always separate the business layer and the presentation layer, the code from the user interface. If you are an ASP programmer and ASP is the only programming that you do, the new programming model is probably not familiar to you. In ASP, for one application you normally have multiple pages, where each page only handles a part of one particular task, and it is normal to make your user jump agilely from one page to another. Web forms, on the other hand, have only one page to process a particular task. Imagine something like a recursive page in classic ASP. Web Forms are like Windows forms, only on the Internet. If you have been programming with Visual Basic or Visual C++, you will find Web Forms very familiar. To illustrate this point, consider an ASP login page that checks the user name and password. In the old ASP, you would have two pages: Login.html and VerifyLogin.asp, as in Listings 1 and 2 respectively.

Listing 1: Login.html

<HTML>
<HEAD>
<TITLE>Login</TITLE>
</HEAD>
<BODY>
<FORM ACTION=VerifyLogin.asp METHOD=POST>
User Name: <INPUT TYPE=TEXT NAME=UserName>
<BR>
Password: <INPUT TYPE=PASSWORD Name=Password>
<BR>
<INPUT TYPE=SUBMIT>
</FORM>
</BODY>
</HTML>

Listing 2: VerifyLogin.asp

<%
  Option Explicit
  Dim UserName, Password

  UserName = Request.Form("UserName")
  Password = Request.Form("Password")
  If UserName = "kittyhawk" AND Password = "toronto" Then
    Response.Write "Welcome Kitty Hawk"
  Else
    Response.Redirect "Login.html"
  End If

%>

See how you end up with two pages? With Web Forms, you will only have one page, whose code is given in Listing 3.

Listing 3: A Web Forms application.

<html>
<head>
<title>Web Forms Login Application</title>
<script language="C#" runat="Server">

void Button1_Click(object Source, EventArgs e) {
  if (userName.Value.Equals("kittyhawk") &&
    password.Value.Equals("toronto"))
    message.InnerHtml="Welcome Kitty Hawk.";
  else
    message.InnerHtml="Login failed. Please try again.";
}
</script>
</head>

<body>
<form runat=server>
UserName: <input id="userName" runat=server>
<BR>
Password: <input id="password" type=password runat=server>
<BR>
<input type=submit OnServerClick="Button1_Click" runat=server>
</form>

<p><span id="message" runat=server/>
</body>
</html>

There are a few striking differences between the Web Forms code in Listing 3 and the ASP application in Listings 1 and 2. First, the form in Listing 3 does not have an action attribute; when the form is submitted, the HTTP request will go to the same page. A recursive page. Also, instead of the NAME attribute in every element, you have the id attribute. If your form does not have a method attribute, POST is used by default. This is in contrast to the old ASP, where the default method for forms is GET. Secondly, you may notice that there are the runat attributes in the form tag, the input tags, and the span tag. All the attributes have the =server values. For each element with runat=server, an attribute/value pair, the server processes it prior to sending it to the browser. The result of this server processing is shown in the HTML code that is sent when the page is requested for the first time.

<html>
<head>
<title>Web Forms Login Application</title>

</head>

<body>
<form name="ctrl2" method="post" action="mywebform.aspx"
  id="ctrl2">
<input type="hidden" name="__VIEWSTATE" 
  value="YTB6LTE2NTg0NDUzODRfX194845307e0" />

UserName: <input name="userName" id="userName" type="text" />
<BR>
Password: <input name="password" id="password" type="password" />
<BR>
<input name="ctrl7" type="submit" />
</form>

<p><span id="message"></span>
</body>
</html>

See how the server has supplied the action and method attributes for the form? Also, each HTML object has a name as well as an id. The exception to this is the hidden input element called __VIEWSTATE that is generated by the server. This hidden field is a container for a collection of information about the properties of a Web Forms page.

When the user submits the form, the HTTP request will be sent to the server, like in the old ASP. However, on the server the submit button has the following tag.

<input type=submit OnServerClick="Button1_Click" runat=server>

In the code above, the OnServerClick attribute tells the server what it has to do when the submit button is clicked: run the Button1_Click event procedure. For reading convenience, the Button1_Click event procedure is re-written below.

void Button1_Click(object Source, EventArgs e) {
  if (userName.Value.Equals("kittyhawk") &&
    password.Value.Equals("toronto"))
    message.InnerHtml="Welcome Kitty Hawk.";
  else
    message.InnerHtml="Login failed. Please try again.";
}

What it does is very simple; it compares the value of the text box called userName and the value of password. If the values are "kittyhawk" and "toronto" respectively, it sets the value of message.InnerHtml to "Welcome Kitty Hawk.". Otherwise, it will set it to "Login failed. Please try again.". This is shown in Figure 1.

Screen shot.
Figure 1: A Web Forms application

Open the HTML source page, and you'll see the following.

<html>
<head>
<title>Web Forms Login Application</title>

</head>

<body>
<form name="ctrl2" method="post" action="mywebform.aspx" id="ctrl2">
<input type="hidden" name="__VIEWSTATE" value="YTB6LTE2NTg0NDUzODRfYTB6X2h6NXoyeF9hMHpfaHo1ejd4X2Ewemh6aW5uZ
XJodG1sX0xvZ2luIGZhaWxlZC4gUGxlYXNlIHRyeSBhZ2Fpbi54X194eF94eF94X194d
3cc7eda" />

UserName: <input name="userName" id="userName" type="text" value="kittyhawk" />
<BR>Password: <input name="password" id="password" type="password" value="toronto" />
<BR><input name="ctrl7" type="submit" />
</form>

<p><span id="message">Login failed. Please try again.</span>
</body>
</html>

Web Forms Programming

Every ASP.NET page, by default, inherits the Page class from the System.Web.UI namespace. If you don't supply the Inherits part in the following page directive in your page, the compiler will assume it.

<%@ Page language="C#" Inherits="System.Web.UI.Page" %>

Your page is compiled as a new class when the Web Form is compiled. The page will be recompiled after you edit it. As a result, the first call to a page is always much slower. Subsequent calls to the same page will use the compiled version and will be much faster because there is no time spent on compilation.

Because the class is derived from the ASP.NET Page class, the new class inherits the properties, methods, and events of the Page class. The Page class has events that become the processing stages of a Web Form page. If you want to understand ASP.NET thoroughly, you should study the Page class.

The Page Class

The Page class extends the System.Web.UI.TemplateControl class and implements the System.Web.IHttpHandler interface. This interface defines the contract that developers must implement to synchronously process HTTP web requests. The Page class has a number of important properties and methods that you should understand.

The Page Class' Properties

Among the properties are the Request, Response, Server, Application and Session properties that allow you to retrieve, respectively, the Request, Response, Server, Application and Session objects from the HTTP Runtime. If you are an ASP programmer, you should be familiar with these five ASP built-in objects. For instance, the Response object allows you to output a string to the browser, as you have seen at the beginning of the article.

Also important is the IsPostBack property. This property returns false if the current request is the first request from the user. Otherwise, it returns true. You can query the value of this property and later do a one-time initialization if the property returns false.

If you are an ASP programmer, this use of the IsPostBack property is equivalent to writing code in the Session_OnStart event procedure in the global.asa file. Another property is the IsUplevel property, which returns true if the request comes from a fourth generation browser, i.e., Internet Explorer 4.0 or above and Netscape Navigator 4.0 or above. Utilizing this property, you can have two sets of HTML pages, the standard pages and browser-specific pages. If you know for sure that the user is using IE 5.0, for example, you might want to send dynamic HTML to make your sites more attractive.

The Page Class' Methods

The Page class provides useful methods to perform tasks that in classic ASP are done using methods of the built-in objects. For example, to redirect the user to a different URL, you can use the Redirect method of the Response object. However, in ASP.NET you have a choice; you can also use the Navigate method to do the same thing. For example, the following redirects you to the MSDN Web site.

Navigate("http://msdn.microsoft.com");

Note that you must write the "http" part if you are redirecting to an external Web site. Also, the MapPath method replaces the same method in the Server object. You can use this method to assign a virtual path, either relative or absolute, to a physical path.

Web Forms Processing Stages

There are a few stages that every Web Form page goes through. For each stage, the Page class provides one or more methods that you can use to work with the contents of the form.

The most frequently used stages are as follow.

The following example modifies the code in Listing 3 to greet the user when the user first comes to the page.

Listing 4: Writing code for the Page_Load event procedure

<html>
<head>
<title>Web Forms Login Application</title>
<script language="C#" runat="Server">

public void Page_Load() {
  if (!IsPostBack)
    message.InnerHtml="Welcome. " +
    "Please enter your user name and password in the boxes above";
}

void Button1_Click(object Source, EventArgs e) {
  if (userName.Value.Equals("kittyhawk") &&
password.Value.Equals("toronto"))
    message.InnerHtml="Welcome Kitty Hawk.";
  else
    message.InnerHtml="Login failed. Please try again.";
}
</script>
</head>

<body>
<form runat=server>
UserName: <input id="userName" runat=server>
<BR>Password: <input id="password" type=password runat=server>
<BR><input type=submit OnServerClick="Button1_Click" runat=server>
  
</form>
<p><span id="message" runat=server/>
</body>
</html>

Working with Server Controls

One of the benefits of ASP.NET is the availability of server controls that make Web Forms programming easy. These controls are specifically designed to work in the ASP.NET Framework and can be grouped into two general categories, HTML controls and Web controls. As you will see, each control has a base class representation of the .NET Framework type libraries. Every server control has the id attribute to allow you to refer to it programmatically. In a Web Form, this id must be unique.

HTML Controls

HTML controls have a one-to-one mapping with HTML tags. To use an HTML control in a Web Form, you declare it using the standard HTML tag that represents the control in HTML. However, the tag will have one attribute that must be present to indicate that this control is a server control: runat. The runat attribute will have the value server. As one example, the following is an input text control.

<input type="text" id="userName" runat="server">

In the .NET Framework type library, HTML controls reside in the System.Web.UI.HtmlControls namespace, and all controls derive directly and indirectly from the HtmlControl abstract class. HTML controls are grouped into three categories:

Web Controls

Web controls exist within the System.Web.UI.WebControls namespace and derive directly or indirectly from the WebControl base class. Some of the controls are very simple controls that are identical to HTML controls. Some others, however, provide higher-level abstractions.

Web controls are declared using the asp prefix. For example, the following is a TextBox Web control declaration.

<asp:TextBox id="userName" type="text" runat="server">

The above Web control is rendered as the following.

<input name="userName" type="text" id="userName" type="text" />

which is the same as the HTML tag sent by the following HTML input text control.

<input type=text id="userName" runat="server">

Note that a Web control must be written using the XML syntax, whereas an HTML control can use either the HTML or XML syntax.

However, you can't interchange a Web control with its HTML control equivalent without changing the code, because a Web control in an ASP.NET page will be translated into a different object. For example, to retrieve the value entered by the user to a TextBox Web control, you would use the Text property of the TextBox object, whereas to do the same task with an HtmlInputText control you use the Value property.

Even though HTML controls present similarity that makes code migration from ASP to ASP.NET easier, Web controls have some superior features that don't exist in the former. These features include the following:

Screen shot.
Figure 2: The Calendar control

Both types of server controls can raise events that will be run during the event handling stage of the Page class. For instance, the HtmlInputButton control has the ServerClick event that is raised when the control is clicked on the browser. Another example is the ImageButton control that has the Click event. This event occurs when the control is clicked by the user.

Page Directives

In Web Forms, directives are optional settings that the author of a Web Forms page uses to instruct the page compiler to follow some compilation commands. Page directives can be located anywhere within an .aspx file. Each directive can contain one or more attribute/value pairs specific to that directive.

The following is the list of directives in Web Forms.

The @ Page Directive

The @ Page directive defines page-specific attributes used by the ASP.NET page parser and compiler. You can only have one @ Page directive for every .aspx file. It has 17 attributes and the most important ones are listed below.

For example, the following is an @ Page directive that tells the compiler that the language used in the .aspx page is C#, and that the class should be compiled into a new class that inherits the MyCode class that can be found in the MyCode.cs file.

<%@ Page language="c#" Src="MyCode.cs" Inherits="MyCode" %>

The @ Control Directive

The @ Control directive defines user control-specific attributes used by the ASP.NET page parser and compiler. This directive can only be used with user controls.

The @ Import Directive

The @ Import directive explicitly imports a namespace into a page, making all classes and interfaces of the imported namespace available to the page. The imported namespace can be either part of the .NET Framework class library or a user-defined namespace. The @ Import directive cannot have more than one namespace attribute. To import multiple namespaces, you have to use multiple @ Import directives. Some most frequently used namespaces are imported automatically. These include System, System.Collections, System.IO, System.Web, System.Web.UI, System.Web.UI.HtmlControls and System.Web.UI.WebControls namespaces.

The @ Register Directive

The @ Register directive associates aliases with namespaces and class names for concise notation in custom server control syntax. For example, the following uses the @ Register directive to declare tagprefix and tagname aliases for a server control and a user control.

The first directive declares the MyTag alias as a tag prefix for all controls residing in the MyCompany:MyNameSpace namespace. The second directive declares Acme:AdRotator as a tagprefix:tagname pair for the user control in the file adrotator.ascx. The aliases are then used in custom server control syntax within the form to insert an instance of each server control.

<%@ Register Tagprefix="MyTag" Namespace="MyCompany:MyNameSpace" %>
<%@ Register Tagprefix="Acme" Tagname="AdRotator" Src="AdRotator.ascx" %>
<HTML>
...

The @ Assembly Directive

The @ Assembly directive declaratively links an assembly to the current page, making all of the assembly's classes and interfaces available for use on the page. You can also use this directive to register assemblies in the configuration file, to link assemblies across the entire application.

The @OutputCache Directive

The @ OutputCache directive declaratively controls the output-caching policies of a page.

<%@ OutputCache Error! Hyperlink reference not valid.="cachetime" Error! Hyperlink reference not valid.="headers" %>

Attributes

The following example would keep items in a page's output cache for 10 seconds.

<%@ OutputCache Duration="10" %>

Separating User Interface and Code

When your application gets more complex, it is recommended that you store your code in a separate file from the user interface. If you are using Visual Studio.NET to develop your Web Forms, the code part is always saved as a different file. If you do this, the class in the code file will extend the Page class. In turn, your aspx file, the page where you put your user interface controls, will extend the class in the code file.

Web Forms allow you to do this by providing the Codebehind and Src attribute of the Page directive. These two attributes act as the glue between your aspx file and your code file. You use Codebehind if your code has already been compiled, and Src if your code exists as source code.

To illustrate the separation of the user interface and code, consider the following example, the code for which is given in Listings 5 and 6.

Listing 5: Testing.aspx

<%@ Page language="c#" Codebehind="MyCode.cs" 
AutoEventWireup="false" Inherits="MyCode" %>
<html>
<head>
<title>Code separation</title>
</head>
<body>
<form runat="server">
<asp:Label id=Label1 runat="server" Width="186" 
Height="19">Label</asp:Label>
<br>
<asp:TextBox id=TextBox1 runat="server"></asp:TextBox>
<asp:Button id=Button1 runat="server" Text="Button"></asp:Button>
</form>
</body>
</html>

Listing 6: MyCode.cs

using System;
using System.Web.UI.WebControls;

public class MyCode : System.Web.UI.Page {
  protected Label Label1;
  protected Button Button1;
  protected TextBox TextBox1;
	
  public MyCode() {
    Page.Init += new System.EventHandler(Page_Init);
  }

  protected void Page_Init(object sender, EventArgs e) {
    Button1.Click += new System.EventHandler (this.Button1_Click);
  }

  public void Button1_Click (object sender, System.EventArgs e) {
    Label1.Text = TextBox1.Text;
  }
}

Listing 4 presents an aspx file that contains some user interface controls: a Label, a TextBox and a Button. No code is present; however, the first line of the page is the Page directive with the Codebehind attribute and the Inherits attribute. The Inherits attribute has the value of "MyCode", telling the compiler that the aspx page is to be compiled as a new class that extends a class named MyCode. This class is to be found in the file given by the Codebehind attribute.

Listing 5 is the code itself. It contains the class MyCode. Note that the class MyCode extends System.Web.UI.Page. This class contains all the needed code to run the application.

If you pre-compile the source code, it has to be compiled into a .dll file and this .dll file should be deployed to the bin subdirectory of the virtual directory.

Session Management

An important feature of Web Forms is the new session-management strategy, the mechanism to retain state between same-user requests. In ASP and other programming technologies, session management using the Session object is not a recommended solution because Session objects are stored in the memory. Therefore, using session management makes your application not scalable. Apart from that, session management relies on cookies to carry session identifiers for each user. This has two serious implications. The user browser has to accept cookies and, in a Web farm environment, there must be a mechanism to redirect subsequent request from the same user to the original server that issues the session identifier.

ASP.NET brings with it a new system of session management that overcomes the disadvantages of Session object-based session management in classic ASP. What is new is that the new feature lets you decide where the user session information will be stored.

You have three options: storing the session information in the memory like in old ASP, in a shared computer's memory, or in a database. These options are known as the session management mode. The three modes are in-process, state server and SQL Server.

The In-Process Mode

You only use this mode if your application won't attract many audiences. Why? Because this mode is basically the same as the old session management in ASP. It consumes computer memory and cannot work in a Web farm without the help of other products that make sure the user always gets directed to the server that issues the session identifier. However, this mode has the fastest response time because Session objects are stored in the same process as the worker process.

The State Server Mode

This is an out-of-process mode. You use this mode if your ASP.NET application is to be hosted in a Web farm. In this mode, ASP.NET saves Session objects in the memory of a shared computer that can be accessed by all servers in a Web farm. As a result, you don't need to redirect subsequent requests from the same user to the server that originates the session identifier. However, because the session information is still stored in the memory, scalability is compromised.

The SQL Server Mode

Like the state server mode, this mode also works out-of-process. In this mode, session information is stored in a SQL Server database accessible to all Web servers in a Web farm. All the Web servers must know the address of the SQL server, as well as the user name and password, to access the database. You don't need to have a Web farm to use this mode, however. You can have the SQL Server in the same machine as the Web server. This mode is to be used in a large Web application to ensure scalability.

To use this mode, you must first create a database in the SQL Server using the script file named state.sql found in the [system drive]\winnt\Microsoft.NET\Framework\[version]\ directory to create a database called ASPState and two tables and several stored procedures inside the ASPState database. These two tables are used to persist session information.

Session Management Configuration

The good thing about the new session-management feature is you can still use the familiar code that you used to use in ASP to manage session information. Nothing has changed. For example, you can use the following code to store the value of text1 to a session variable called aSession.

Session["aSession"] = text1.Value;

Later on, you can retrieve the value from the same Session["aSession"]. All you need to do to use the session management is some configuration in the config.web file. There are two of these files, the global config.web that applies to all applications in a machine, and the application-specific config.web file. The latter is an optional file and applies only to that application. If the same settings are present in both files, the application config.web will overwrite the global one. In .NET SDK Beta 1, the machine config.web file is located in the following directory.

WinNT\Microsoft.NET\Framework\v1.0.2204

The application config.web file, on the other hand, resides in the application's directory.

The setting that you need to modify to use session management is the <sessionstate> node. The syntax is as follows.

<sessionstate
  mode = "inproc" | "sqlserver" | "stateserver"
  cookieless = "true" | "false"
  timeout = <session timeout in minutes>
  sqlconnectionstring = <connection string>
  server = <server name>
  port = <port number>
/>

The six settings above (mode, cookieless, timeout, sqlconnectionstring, server and port) are used to configure the ASP.NET session state. Each setting is explained below.

The following are the session state default settings in the machine config.web file.

<sessionstate 
  mode="inproc"
  cookieless="false" 
  timeout="20" 
  sqlconnectionstring="data source=127.0.0.1;user id=sa;password="
  server="127.0.0.1" 
  port="42424" 
/>

For example, to use the SQL Server mode, you should configure the <sessionstate> node of your config.web file as the following.

<configuration> 
  <sessionstate 
    mode="sqlserver"
    cookieless="true" 
    timeout="20" 
    sqlconnectionstring="data source=202.46.33.33;
user id=tukijan;password=jumiyo44"
    server="" 
    port="" 
  />
</configuration>

Note that if you set the cookieless setting to true, your session management will work without using cookies. In this case, rather than using an automatically-generated cookie that holds a unique 120-bit session identifier string containing URL-legal ASCII characters to identify and track each session, the ASP.NET session management system modifies the URL to include the information about the session identifier.

Summary

In this article, you have seen the new programming model in ASP.NET: Web Forms. Web Forms are new technology that is event-driven, and should be familiar to you if you have been programming using Visual Basic or Visual C++. You have also seen how to use the two sets of server controls: HTML controls and Web controls. You also learned how to separate user interface and code in different files and the new feature of session management that can be made scalable, cookie independent and work in a Web farm.

Copyright © 2009 O'Reilly Media, Inc.