Pro CSharp And The .NET 2.0 Platform (2005) [eng]
.pdf854CHAPTER 23 ■ ASP. NET 2 . 0 WEB PAGES AND WEB CONTROLS
This name of this class is based on the name of the *.aspx file and takes an _aspx suffix (e.g., a page named MyPage.aspx becomes a class type named MyPage_aspx). Figure 23-15 illustrates the basic process.
Figure 23-15. The compilation model for single-file pages
This dynamically compiled assembly is deployed to a runtime-defined subdirectory under the <%windir%>Microsoft.NET\Framework\v2.0.50215\Temporary ASP.NET Files\root directory. The path beneath \root will differ based on a number of factors (hash codes, etc.), but eventually you will find the *.dll (and supporting files) in question. Figure 23-16 shows one such assembly.
Figure 23-16. The ASP.NET autogenerated assembly
Compilation Cycle for Multifile Pages
The compilation process of a page making use of the code-behind model is similar to that of the single-file model. However, the type deriving from System.Web.UI.Page is composed from three (yes, three) files rather than the expected two.
Looking back at the previous CodeBehindPageModel example, recall that the Default.aspx file was connected to a partial class named _Default within the code-behind file. If you have a background in ASP.NET 1.x, you may wonder what happened to the member variable declarations for the various
856CHAPTER 23 ■ ASP. NET 2 . 0 WEB PAGES AND WEB CONTROLS
were to locate the Page type (within the System.Web.dll assembly) using the Visual Studio 2005 object browser, you would find that Page “is-a” TemplateControl, which “is-a” Control, which “is-a” Object (see Figure 23-18).
Figure 23-18. The derivation of an ASP.NET page
As you would guess, each of these base classes brings a good deal of functionality to each and every *.aspx file. For the majority of your projects, you will make use of the members defined within the Page and Control parent classes. By and large, the functionality gained from the System. Web.UI.TemplateControl class is only of interest to you if you are building custom Web Form controls or interacting with the rendering process. This being said, let’s get to know the role of the Page type.
The System.Web.UI.Page Type
The first parent class of interest is Page itself. Here you will find numerous properties that enable you to interact with various web primitives such as application and session variables, the HTTP request/response, theme support, and so forth. Table 23-4 describes some (but by no means all) of the core properties.
Table 23-4. Properties of the Page Type
Property |
Meaning in Life |
Application |
Allows you to interact with application variables for the current website |
Cache |
Allows you to interact with the cache object for the current website |
ClientTarget |
Allows you to specify how this page should render itself based on the |
|
requesting browser |
IsPostBack |
Gets a value indicating if the page is being loaded in response to |
|
a client postback or if it is being loaded and accessed for the first time |
MasterPageFile |
Establishes the master page for the current page |
Request |
Provides access to the current HTTP request |
Response |
Allows you to interact with the outgoing HTTP response |
CHAPTER 23 ■ ASP. NET 2 . 0 WEB PAGES AND WEB CONTROLS |
857 |
Property |
Meaning in Life |
Server |
Provides access to the HttpServerUtility object, which contains |
|
various server-side helper functions |
Session |
Allows you to interact with the session data for the current caller |
Theme |
Gets or sets the name of the theme used for the current page |
Trace |
Provides access to a TraceContext object, which allows you to log |
|
custom messages during debugging sessions |
|
|
Interacting with the Incoming HTTP Request
As you saw earlier in this chapter, the basic flow of a web session begins with a client logging on to a site, filling in user information, and clicking a Submit button to post back the HTML form data to a given web page for processing. In most cases, the opening tag of the form statement specifies an action attribute and a method attribute that indicates the file on the web server that will be sent the data in the various HTML widgets, as well as the method of sending this data (GET or POST):
<form name="defaultPage" id="defaultPage" action="http://localhost/Cars/ClassicAspPage.asp" method = "GET">
...
</form>
Unlike classic ASP, ASP.NET does not support an object named Request. However, all ASP.NET pages do inherit the System.Web.UI.Page.Request property, which provides access to an instance of the HttpRequest class type. Table 23-5 lists some core members that, not surprisingly, mimic the same members found within the legacy classic ASP Request object.
Table 23-5. Members of the HttpRequest Type
Member |
Meaning in Life |
ApplicationPath |
Gets the ASP.NET application’s virtual application root path on the |
|
server |
Browser |
Provides information about the capabilities of the client browser |
Cookies |
Gets a collection of cookies sent by the client browser |
FilePath |
Indicates the virtual path of the current request |
Form |
Gets a collection of Form variables |
Headers |
Gets a collection of HTTP headers |
HttpMethod |
Indicates the HTTP data transfer method used by the client (GET, POST) |
IsSecureConnection |
Indicates whether the HTTP connection is secure (i.e., HTTPS) |
QueryString |
Gets the collection of HTTP query string variables |
RawUrl |
Gets the current request’s raw URL |
RequestType |
Indicates the HTTP data transfer method used by the client (GET, POST) |
ServerVariables |
Gets a collection of web server variables |
UserHostAddress |
Gets the IP host address of the remote client |
UserHostName |
Gets the DNS name of the remote client |
|
|
In addition to these properties, the HttpRequest type has a number of useful methods, including the following:
858CHAPTER 23 ■ ASP. NET 2 . 0 WEB PAGES AND WEB CONTROLS
•MapPath(): Maps the virtual path in the requested URL to a physical path on the server for the current request.
•SaveAs(): Saves details of the current HTTP request to a file on the web server (which can prove helpful for debugging purposes).
•ValidateInput(): If the validation feature is enabled via the Validate attribute of the page directive, this method can be called to check all user input data (including cookie data) against a predefined list of potentially dangerous input data.
Obtaining Brower Statistics
The first interesting aspect of the HttpRequest type is the Browser property, which provides access to an underlying HttpBrowserCapabilities object. HttpBrowserCapabilities in turn exposes numerous members that allow you to programmatically investigate statistics regarding the browser that sent the incoming HTTP request.
Create a new ASP.NET website named FunWithPageMembers. Your first task is to build a UI that allows users to click a Button web control to view various statistics about the calling browser. These statistics will be generated dynamically and attached to a Label type (named lblOutput). The Button Click event handler is as follows:
protected void btnGetBrowserStats_Click(object sender, System.EventArgs e)
{
string theInfo = "";
theInfo += String.Format("<li>Is the client AOL? {0}", Request.Browser.AOL);
theInfo +=
String.Format("<li>Does the client support ActiveX? {0}", Request.Browser.ActiveXControls);
theInfo += String.Format("<li>Is the client a Beta? {0}", Request.Browser.Beta);
theInfo +=
String.Format("<li>Dose the client support Java Applets? {0}", Request.Browser.JavaApplets);
theInfo +=
String.Format("<li>Does the client support Cookies? {0}", Request.Browser.Cookies);
theInfo +=
String.Format("<li>Does the client support VBScript? {0}", Request.Browser.VBScript);
lblOutput.Text = theInfo;
}
Here you are testing for a number of browser capabilities. As you would guess, it is (very) helpful to discover a browser’s support for ActiveX controls, Java applets, and client-side VBScript code. If the calling browser does not support a given web technology, your *.aspx page would be able to take an alternative course of action.
Access to Incoming Form Data
Other aspects of the HttpResponse type are the Form and QueryString properties. These two properties allow you to examine the incoming form data using name/value pairs, and they function identically to classic ASP. Recall from our earlier discussion of classic ASP that if the data is submitted using HTTP GET, the form data is accessed using the QueryString property, whereas data submitted via HTTP POST is obtained using the Form property.
860CHAPTER 23 ■ ASP. NET 2 . 0 WEB PAGES AND WEB CONTROLS
type defines a number of properties that allow you to format the HTTP response sent back to the client browser. Table 23-6 lists some core properties.
Table 23-6. Properties of the HttpResponse Type
Property |
Meaning in Life |
Cache |
Returns the caching semantics of the web page (e.g., expiration time, |
|
privacy, vary clauses) |
ContentEncoding |
Gets or sets the HTTP character set of the output stream |
ContentType |
Gets or sets the HTTP MIME type of the output stream |
Cookies |
Gets the HttpCookie collection sent by the current request |
IsClientConnected |
Gets a value indicating whether the client is still connected to the server |
Output |
Enables custom output to the outgoing HTTP content body |
OutputStream |
Enables binary output to the outgoing HTTP content body |
StatusCode |
Gets or sets the HTTP status code of output returned to the client |
StatusDescription |
Gets or sets the HTTP status string of output returned to the client |
SuppressContent |
Gets or sets a value indicating that HTTP content will not be sent to the |
|
client |
|
|
Also, consider the partial list of methods supported by the HttpResponse type described in Table 23-7.
Table 23-7. Methods of the HttpResponse Type
Method |
Meaning in Life |
AddCacheDependency() |
Adds an object to the application catch (see Chapter 24) |
Clear() |
Clears all headers and content output from the buffer stream |
End() |
Sends all currently buffered output to the client, and then closes the |
|
socket connection |
Flush() |
Sends all currently buffered output to the client |
Redirect() |
Redirects a client to a new URL |
Write() |
Writes values to an HTTP output content stream |
WriteFile() |
Writes a file directly to an HTTP content output stream |
|
|
Emitting HTML Content
Perhaps the most well-known aspect of the HttpResponse type is the ability to write content directly to the HTTP output stream. The HttpResponse.Write() method allows you to pass in any HTML tags and/or text literals. The HttpResponse.WriteFile() method takes this functionality one step further, in that you can specify the name of a physical file on the web server whose contents should be rendered to the output stream (this is quite helpful to quickly emit the contents of an existing *.htm file).
To illustrate, assume you have added another Button type to your current *.aspx file that implements the server-side Click event handler as so:
protected void btnHttpResponse_Click(object sender, EventArgs e)
{
Response.Write("<b>My name is:</b><br>"); Response.Write(this.ToString());
CHAPTER 23 ■ ASP. NET 2 . 0 WEB PAGES AND WEB CONTROLS |
861 |
Response.Write("<br><br><b>Here was your last request:</b><br>"); Response.WriteFile("MyHTMLPage.htm");
}
The role of this helper function (which you can assume is called by some server-side event handler) is quite simple. The only point of interest is the fact that the HttpResponse.WriteFile() method is now emitting the contents of a server-side *.htm file within the root directory of the website.
Again, while you can always take this old-school approach and render HTML tags and content using the Write() method, this approach is far less common under ASP.NET than with classic ASP. The reason is (once again) due to the advent of server-side web controls. Thus, if you wish to render a block of textual data to the browser, your task is as simple as assigning a string to the Text property of a Label widget.
Redirecting Users
Another aspect of the HttpResponse type is the ability to redirect the user to a new URL:
protected void btnSomeTraining_Click(object sender, EventArgs e)
{
Response.Redirect("http://www.IntertechTraining.com");
}
If this event handler was invoked via a client-side postback, the user will automatically be redirected to the specified URL.
■Note The HttpResponse.Redirect() method will always entail a trip back to the client browser. If you simply wish to transfer control to a *.aspx file in the same virtual directory, the HttpServerUtility.Transfer() method (accessed via the inherited Server property) will be more efficient.
So much for investigating the functionality of System.Web.UI.Page. We will examine the role of the System.Web.UI.Control base class in just a bit; however, the next task is to examine the life and times of a Page-derived object.
■Source Code The FunWithPageMembers files are included under the Chapter 23 subdirectory.
The Life Cycle of an ASP.NET Web Page
Every ASP.NET web page has a fixed life cycle. When the ASP.NET runtime receives an incoming request for a given *.aspx file, the associated System.Web.UI.Page-derived type is allocated into memory using the type’s default constructor. After this point, the framework will automatically fire a series of events.
By default, a Visual Studio 2005–generated code-behind page defines an event handler for the page’s Load event:
public partial class _Default : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
}
}
Beyond the Load event, a given Page is able to intercept any of the core events in Table 23-8, which are listed in the order in which they are encountered.
862 CHAPTER 23 ■ ASP. NET 2 . 0 WEB PAGES AND WEB CONTROLS
Table 23-8. Events of the Page Type
Event |
Meaning in Life |
PreInit |
The framework uses this event to allocate any web controls, |
|
apply themes, establish the master page, and set user profiles. |
|
You may intercept this event to customize the process. |
Init |
The framework uses this event to set the properties of web |
|
controls to their previous values via postback or view state |
|
data (more details on this in Chapter 24). |
Load |
When this event fires, the page and its controls are fully |
|
initialized, and their previous values are restored. At this |
|
point, it is safe to interact with each web widget. |
“Event that triggered the postback” |
There is of course, no event of this name. This “event” simply |
|
refers to whichever event caused the browser to perform the |
|
postback to the web server (such as a Button click). |
PreRender |
All control data binding and UI configuration has occurred |
|
and the controls are ready to render their data into the |
|
outbound HTTP response. |
Unload |
The page and its controls have finished the rendering process, |
|
and the page object is about to be destroyed. At this point, it is |
|
a runtime error to interact with the outgoing HTTP response. |
|
You may, however, capture this event to perform any page- |
|
level cleanup (close file or database connections, perform any |
|
form of logging activity, dispose of objects, etc.). |
|
|
|
|
■Note Each event of the Page type works in conjunction with the System.EventHandler delegate.
The Role of the AutoEventWireUp Attribute
When you wish to handle events for your page, you will need to update your <script> block or codebehind file with an appropriate event handler. Unlike in ASP.NET 1.x, you are not required to rig up the event logic by hand. All you need to do is define a method using the following pattern:
protected Page_nameOfTheEvent(object sender, EventArgs e)
{
}
For example, the Unload event can be handle this event simply by writing the following:
public partial class _Default : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
}
protected void Page_Unload(object sender, EventArgs e)
{
}
}
The reason this method is magically called when the page unloads (despite the fact that you have not applied the expected C# event syntax) is due to the AutoEventWireUp attribute set to true by default in the <%@Page%> directive of your *.aspx file:
<%@ Page Language="C#" AutoEventWireup="true"
CodeFile="Default.aspx.cs" Inherits="_Default" %>
CHAPTER 23 ■ ASP. NET 2 . 0 WEB PAGES AND WEB CONTROLS |
863 |
As its name suggests, this attribute (when enabled) will generate the necessary event riggings within the autogenerated partial class described in earlier in this chapter. If you were to set this attribute to false, neither the Load nor Unload event handlers of the _Default page will be called by the framework (you can verify this for yourself by setting breakpoints within the Page_Load() and Page_Unload() event handlers).
However, if you were to make use of the standard C# event syntax to hook into the Load and Unload events as shown here:
public partial class _Default : System.Web.UI.Page
{
public _Default()
{
// Explicitly hook into the Load and Unload events. this.Load +=new EventHandler(Page_Load); this.Unload += new EventHandler(Page_Unload);
}
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!");
}
protected void btnPostback_Click(object sender, EventArgs e)
{
//Nothing happens here; this is just to ensure a
//postback to the page.
}
}
these events will be captured in your page regardless of the value assigned to AutoEventWireup. As a final note, remember that once the Unload event fires, you are no longer able to interact
with the outbound HTTP response (if you attempt to call members of the HttpResponse object, you will receive a runtime exception). Given this, your Unload event handler is simply emitting a line of text to a file on the local C drive.
The Error Event
Another event that may occur during your page’s life cycle is Error, which also works in conjunction with the System.EventHandler delegate. 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, you have one final chance to deal with the problem before the end user finds an ugly error. Ponder the following code:
public partial class _Default : System.Web.UI.Page
{
public _Default()
{
...