
Pro CSharp 2008 And The .NET 3.5 Platform [eng]
.pdf
1202 CHAPTER 31 ■ BUILDING ASP.NET WEB PAGES
<%@ Page Language="C#" AutoEventWireup="true"
CodeFile="Default.aspx.cs" Inherits="_Default" %>
With this default behavior, each page-level event handler will automatically be handled if you enter the appropriately named method. However, if you disable AutoPageWireUp by setting this attribute to false:
<%@ Page Language="C#" AutoEventWireup="false"
CodeFile="Default.aspx.cs" Inherits="_Default" %>
the page-level events will no longer be captured. As its name suggests, this attribute (when enabled) will generate the necessary event riggings within the autogenerated partial class described earlier in this chapter. Even if you disable AutoEventWireup, you can still process page-level events by making use of C# event-handling logic, for example:
public _Default()
{
// Explicitly hook into the Load and Unload events. this.Load += new EventHandler(Page_Load); this.Unload += new EventHandler(Page_Unload);
}
As you might suspect, by and large you will simply leave AutoEventWireup enabled.
The Error Event
Another event that may occur during your page’s life cycle is Error. This event will be fired if a method on the Page-derived type triggered an exception that was not explicitly handled. Assume that you have handled the Click event for a given Button on your page, and within the event handler (which I named btnGetFile_Click), you attempt to write out the contents of a local file to the HTTP response.
Also assume you have failed to test for the presence of this file via standard structured exception handling. If you have rigged up the page’s Error event in the default constructor, you have one final chance to deal with the problem on this page before the end user finds an ugly error. Consider the following code:
public partial class _Default : System.Web.UI.Page
{
void Page_Error(object sender, EventArgs e)
{
Response.Clear();
Response.Write("I am sorry...I can't find a required file.<br>"); Response.Write(string.Format("The error was: <b>{0}</b>",
Server.GetLastError().Message)); Server.ClearError();
}
protected void Page_Load(object sender, EventArgs e)
{
Response.Write("Load event fired!");
}
protected void Page_Unload(object sender, EventArgs e)
{
//No longer possible to emit data to the HTTP
//response at this point, so we will write to a local file.
System.IO.File.WriteAllText(@"C:\MyLog.txt", "Page unloading!");
}

CHAPTER 31 ■ BUILDING ASP.NET WEB PAGES |
1203 |
protected void btnPostback_Click(object sender, EventArgs e)
{
//Nothing happens here, this is just to ensure a
//postback to the page.
}
protected void btnTriggerError_Click(object sender, EventArgs e)
{
System.IO.File.ReadAllText(@"C:\IDontExist.txt");
}
}
Notice that your Error event handler begins by clearing out any content currently within the HTTP response and emits a generic error message. If you wish to gain access to the specific System. Exception object, you may do so using the HttpServerUtility.GetLastError() method exposed by the inherited Server property.
Finally, note that before exiting this generic error handler, you are explicitly calling the HttpServerUtility.ClearError() method via the Server property. This is required, as it informs the runtime that you have dealt with the issue at hand and require no further processing. If you forget to do so, the end user will be presented with the runtime’s error page. Figure 31-20 shows the result of this error-trapping logic.
Figure 31-20. Page-level error handling
At this point, you should feel confident with the composition of an ASP.NET Page type. Now that you have such a foundation, you can turn your attention to the role of ASP.NET web controls, themes, and master pages, all of which are the subject of the next chapter. To wrap up this chapter, however, let’s examine the role of the Web.config file.
■Source Code The PageLifeCycle files are included under the Chapter 31 subdirectory.
The Role of the Web.config File
By default, all C# ASP.NET web applications created with Visual Studio 2008 are automatically provided with a Web.config file. However, if you ever need to manually insert a Web.config file into your site (e.g., when you are working with the single-page model and have not created a web solution), you may do so using the using the Web Site Add New Item menu option. In either case, within this scope of a Web.config file you are able to add settings that control how your web application will function at runtime.

1204 CHAPTER 31 ■ BUILDING ASP.NET WEB PAGES
■Note It is not mandatory for your web applications to include a Web.config file. If you do not have such a file, your website will be granted the default web-centric settings recorded in the machine.config file for your .NET installation.
Recall during your examination of .NET assemblies (in Chapter 15) that you learned client applications can leverage an XML-based configuration file to instruct the CLR how it should handle binding requests, assembly probing, and other runtime details. The same holds true for ASP.NET web applications, with the notable exception that web-centric configuration files are always named Web.config (unlike *.exe configuration files, which are named based on the related client executable).
The default structure of a Web.config file is rather verbose with the release of .NET 3.5, but the essentials settings break down as follows. Table 31-9 outlines some of the more interesting subelements that can be found within a Web.config file.
Table 31-9. Select Elements of a Web.config File
Element |
Meaning in Life |
<appSettings> |
This element is used to establish custom name/value pairs that can be |
|
programmatically read in memory for use by your pages using the |
|
ConfigurationManager type. |
<authentication> |
This security-related element is used to define the authentication mode for |
|
this web application. |
<authorization> |
This is another security-centric element used to define which users can |
|
access which resources on the web server. |
<connectionStrings> |
This element is used to hold external connection strings used within this |
|
website. |
<customErrors> |
This element is used to tell the runtime exactly how to display errors that |
|
occur during the functioning of the web application. |
<globalization> |
This element is used to configure the globalization settings for this web |
|
application. |
<namespaces> |
This element documents all of the namespaces to include if your web |
|
application has been precompiled using the new aspnet_compiler.exe |
|
command-line tool. |
<sessionState> |
This element is used to control how and where session state data will be |
|
stored by the .NET runtime. |
<trace> |
This element is used to enable (or disable) tracing support for this web |
|
application. |
|
|
A Web.config file may contain additional subelements above and beyond the set presented in Table 31-9. The vast majority of these items are security related, while the remaining items are useful only during advanced ASP.NET scenarios such as creating with custom HTTP headers or custom HTTP modules (topics that are not covered here).
If you wish to see the complete set of elements (and the related attributes) that can appear in a Web.config file, you may do so using the .NET Framework 3.5 SDK documentation. Simply search for the topic “ASP.NET Configuration Settings” as shown in Figure 31-21, and dive in.
You will come to know various aspects of the Web.config file over the remainder of this text.


1206 CHAPTER 31 ■ BUILDING ASP.NET WEB PAGES
If you were to click the tabs located on the top of the page, you would quickly notice that most of this tool’s functionality is used to establish security settings for your website. However, this tool also makes it possible to add settings to your <appSettings> element, define debugging and tracing settings, and establish a default error page.
You’ll see more of this tool in action where necessary; however, do be aware that this utility will not allow you to add all possible settings to a Web.config file. There will most certainly be times when you will need to manually update this file using your text editor of choice.
Summary
Building web applications requires a different frame of mind than is used to assemble traditional desktop applications. In this chapter, you began with a quick and painless review of some core web topics, including HTML, HTTP, the role of client-side scripting, and server-side scripts using classic ASP. The bulk of this chapter was spent examining the architecture of an ASP.NET page. As you have seen, each *.aspx file in your project has an associated System.Web.UI.Page-derived class. Using this OO approach, ASP.NET allows you to build more reusable and OO-aware systems.
After examining some of the core functionality of a page’s inheritance chain, this chapter then discussed how your pages are ultimately compiled into a valid .NET assembly. We wrapped up by exploring the role of the Web.config file and overviewed the ASP.NET Web Site Administration tool.


1208 CHAPTER 32 ■ ASP.NET WEB CONTROLS, THEMES, AND MASTER PAGES
partial class _Default : System.Web.UI.Page
{
protected void btnChangeTextBoxColor_Click(object sender, System.EventArgs e)
{
// Change color of text box object in code. this.txtNameTextBox.BackColor = Drawing.Color.DarkBlue;
}
}
All ASP.NET web controls ultimately derive from a common base class named System.Web.UI. WebControls.WebControl. WebControl in turn derives from System.Web.UI.Control (which derives from System.Object). Control and WebControl each define a number of properties common to all server-side controls. Before we examine the inherited functionality, let’s formalize what it means to handle a server-side event.
Understanding Server-Side Event Handling
Given the current state of the World Wide Web, it is impossible to avoid the fundamental nature of browser/web server interaction. Whenever these two entities communicate, there is always an underlying, stateless, HTTP request-and-response cycle. While ASP.NET server controls do a great deal to shield you from the details of the raw HTTP protocol, always remember that treating the Web as an event-driven entity is just a magnificent smoke-and-mirrors show provided by the CLR, and it is not identical to the event-driven model of a Windows-based UI.
For example, although the System.Windows.Forms, System.Windows.Controls, and System.Web. UI.WebControls namespaces define types with the same simple names (Button, TextBox, Label, and so on), they do not expose an identical set of events. For example, there is no way to handle a server-side MouseMove event when the user moves the cursor over a Web Form Button type. Obviously, this is a good thing. (Who wants to post back to the server each time the user mouse moves in the browser?)
The bottom line is that a given ASP.NET web control will expose a limited set of events, all of which ultimately result in a postback to the web server. Any necessary client-side event processing will require you to author blurbs of client-side JavaScript/VBScript script code to be processed by the requesting browser’s scripting engine. Given that ASP.NET is primarily a server-side technology, I will not be addressing the topic of authoring client-side scripts in this text.
■Note Handling an event for a given web control using Visual Studio 2008 can be done in an identical manner to doing so for a Windows Forms control. Simply select the widget from the designer and click the “lightning bolt” icon on the Properties window.
The AutoPostBack Property
It is also worth pointing out that many of the ASP.NET web controls support a property named AutoPostBack (most notably, the CheckBox, RadioButton, and TextBox controls, as well as any widget that derives from the abstract ListControl type). By default, this property is set to false, which disables the automatic processing of server-side events (even if you have indeed rigged up the event in the code-behind file). In most cases, this is the exact behavior you require, given that UI elements such as check boxes typically don’t require postback functionality (as the page object can obtain the state of the widget within a more natural Button Click event handler).
However, if you wish to cause any of these widgets to post back to a server-side event handler, simply set the value of AutoPostBack to true. This technique can be helpful if you wish to have the


1210 CHAPTER 32 ■ ASP.NET WEB CONTROLS, THEMES, AND MASTER PAGES
Table 32-1. Continued
Member |
Meaning in Life |
Page |
This property gets a reference to the Page instance that contains the server |
|
control. |
Parent |
This property gets a reference to the server control’s parent control in the page |
|
control hierarchy. |
SkinID |
This property gets or sets the “skin” to apply to the control. Under ASP.NET, it is |
|
now possible to establish a control’s overall look and feel on the fly via skins. |
Visible |
This property gets or sets a value that indicates whether a server control is |
|
rendered as a UI element on the page. |
|
|
Enumerating Contained Controls
The first aspect of System.Web.UI.Control we will examine is the fact that all web controls (including Page itself) inherit a custom controls collection (accessed via the Controls property). Much like in a Windows Forms application, the Controls property provides access to a strongly typed collection of WebControl-derived types. Like any .NET collection, you have the ability to add, insert, and remove items dynamically at runtime.
While it is technically possible to add web controls directly to a Page-derived type, it is easier (and more robust) to make use of a Panel widget. The Panel class represents a container of widgets that may or may not be visible to the end user (based on the value of its Visible and BorderStyle properties).
To illustrate, create a new website named DynamicCtrls. Using the Visual Studio 2008 page designer, add a Panel type (named myPanel) that contains a TextBox, Button, and HyperLink widget named whatever you choose (be aware that the designer requires that you drag internal items within the UI of the Panel type). Once you have done so, the <form> element of your *.aspx file will have been updated as follows:
<asp:Panel ID="myPanel" runat="server" Height="50px" Width="125px"> <asp:TextBox ID="TextBox1" runat="server"></asp:TextBox><br/> <asp:Button ID="Button1" runat="server" Text="Button"/><br/> <asp:HyperLink ID="HyperLink1" runat="server">HyperLink </asp:HyperLink>
</asp:Panel>
Next, place a Label widget outside the scope of the Panel (named lblControlInfo) to hold the rendered output. Assume in the Page_Load() event you wish to obtain a list of all the controls contained within the Panel and assign the results to the Label type (named lblControlInfo):
public partial class _Default : System.Web.UI.Page
{
private void ListControlsInPanel()
{
string theInfo = "";
theInfo = string.Format("Has controls? {0} <br/>", myPanel.HasControls()); foreach (Control c in myPanel.Controls)
{
if (!object.ReferenceEquals(c.GetType(), typeof(System.Web.UI.LiteralControl)))
{
theInfo += "***************************<br/>";
theInfo += string.Format("Control Name? {0} <br/>", c.ToString()); theInfo += string.Format("ID? {0} <br>", c.ID);
