Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Pro CSharp 2008 And The .NET 3.5 Platform [eng]

.pdf
Скачиваний:
78
Добавлен:
16.08.2013
Размер:
22.5 Mб
Скачать

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.

CHAPTER 31 BUILDING ASP.NET WEB PAGES

1205

Figure 31-21. Documentation details of a Web.config file

The ASP.NET Website Administration Utility

Although you are always free to modify the content of a Web.config file directly using Visual Studio 2008, ASP.NET web projects can make use of a handy web-based editor that will allow you to graphically edit numerous elements and attributes of your project’s Web.config file. To launch this tool, shown in Figure 31-22, simply activate the Web Site ASP.NET Configuration menu option.

Figure 31-22. The ASP.NET Web Site Administration tool

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.

C H A P T E R 3 2

ASP.NET Web Controls, Themes, and

Master Pages

The previous chapter concentrated on the composition and behavior of ASP.NET Page objects. This chapter will dive into the details of the web controls that make up a page’s user interface. After examining the overall nature of an ASP.NET web control, you will come to understand how to make use of several UI elements including the validation controls and data-centric controls.

The latter half of this chapter will examine the role of master pages and show how they provide a simplified manner to define a common UI skeleton that will be replicated across the pages in your website. I wrap up by showing you how to apply themes to your pages in order to define a consistent look and feel for your page’s controls. As you will see, the ASP.NET theme engine provides a serverside alternative to traditional client-side style sheets.

Understanding the Nature of Web Controls

A major benefit of ASP.NET is the ability to assemble the UI of your pages using the types defined in the System.Web.UI.WebControls namespace. As you have seen, these controls (which go by the names server controls, web controls, or Web Form controls) are extremely helpful in that they automatically generate the necessary HTML for the requesting browser and expose a set of events that may be processed on the web server. Furthermore, because each ASP.NET control has a corresponding class in the System.Web.UI.WebControls namespace, it can be manipulated in an objectoriented manner.

When you configure the properties of a web control using the Visual Studio 2008 Properties window, your edits are recorded in the opening control declaration of a given element in the *.aspx file as a series of name/value pairs. Thus, if you add a new TextBox to the designer of a given *.aspx file and change the ID, BorderStyle, BorderWidth, BackColor, and Text properties, the opening <asp:TextBox> tag is modified accordingly (note that the Text value becomes the inner text of the

TextBox scope):

<asp:TextBox ID="txtNameTextBox" runat="server" BackColor="#C0FFC0" BorderStyle="Dotted"BorderWidth="5px"> Enter Your Name

</asp:TextBox>

Given that the HTML declaration of a web control eventually becomes a member variable from the System.Web.UI.WebControls namespace (via the dynamic compilation cycle examined in Chapter 31), you are able to interact with the members of this type within a server-side <script> block or the page’s code-behind file. For example, if you handled the Click event for a given Button type, you could change the background color of the TextBox as follows:

1207

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

CHAPTER 32 ASP.NET WEB CONTROLS, THEMES, AND MASTER PAGES

1209

state of one widget automatically populate another value within another widget on the same page. To illustrate, assume you have a web page that contains a single TextBox (named txtAutoPostback) and a single ListBox control (named lstTextBoxData). Here is the relevant markup:

<form id="form1" runat="server">

<asp:TextBox ID="txtAutoPostback" runat="server"></asp:TextBox> <br/>

<asp:ListBox ID="lstTextBoxData" runat="server"></asp:ListBox> </form>

Now, handle the TextChanged event of the TextBox, and within the server-side event handler, populate the ListBox with the current value in the TextBox:

partial class _Default : System.Web.UI.Page

{

protected void txtAutoPostback_TextChanged(object sender, System.EventArgs e)

{

lstTextBoxData.Items.Add(txtAutoPostback.Text);

}

}

If you run the application as is, you will find that as you type in the TextBox, nothing happens. Furthermore, if you type in the TextBox and tab to the next control, nothing happens. The reason is that the AutoPostBack property of the TextBox is set to false by default. However, if you set this property to true:

<asp:TextBox ID="txtAutoPostback" runat="server" AutoPostBack="true">

</asp:TextBox>

you will find that when you tab away from the TextBox (or press the Enter key), the ListBox is automatically populated with the current value in the TextBox. To be sure, beyond the need to populate the items of one widget based on the value of another widget, you will typically not need to alter the state of a widget’s AutoPostBack property (and even then, sometimes this can be accomplished purely in client script, removing the need for server interaction at all).

The System.Web.UI.Control Type

The System.Web.UI.Control base class defines various properties, methods, and events that allow the ability to interact with core (typically non-GUI) aspects of a web control. Table 32-1 documents some, but not all, members of interest.

Table 32-1. Select Members of System.Web.UI.Control

Member

Meaning in Life

Controls

This property gets a ControlCollection object that represents the child controls

 

within the current control.

DataBind()

This method binds a data source to the invoked server control and all its child

 

controls.

EnableTheming

This property establishes whether the control supports theme functionality.

HasControls()

This method determines whether the server control contains any child controls.

ID

This property gets or sets the programmatic identifier assigned to the server

 

control.

Continued

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);

CHAPTER 32 ASP.NET WEB CONTROLS, THEMES, AND MASTER PAGES

1211

theInfo += string.Format("Control Visible? {0} <br/>", c.Visible); theInfo += string.Format("ViewState? {0} <br/>", c.EnableViewState);

}

}

lblControlInfo.Text = theInfo;

}

protected void Page_Load(object sender, System.EventArgs e)

{

ListControlsInPanel();

}

}

Here, you iterate over each WebControl maintained on the Panel and perform a check to see whether the current type is of type System.Web.UI.LiteralControl. This type is used to represent literal HTML tags and content (such as <br>, text literals, etc.). If you do not do this sanity check, you might be surprised to find a total of seven types in the scope of the Panel (given the *.aspx declaration seen previously). Assuming the type is not literal HTML content, you then print out some various statistics about the widget. Figure 32-1 shows the output.

Figure 32-1. Enumerating contained widgets