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

Pro CSharp And The .NET 2.0 Platform (2005) [eng]

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

854CHAPTER 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

CHAPTER 23 ASP. NET 2 . 0 WEB PAGES AND WEB CONTROLS

855

web controls as well as the code within InitializeComponent(), such as event handling logic. Under ASP.NET 2.0, these details are accounted for by a third “file” generated in memory. In reality, of course, this is not a literal file, but an in-memory representation of the partial class. Consider Figure 23-17.

Figure 23-17. The compilation model for multifile pages

In this model, the web controls declared in the *.aspx file are used to build the additional partial class that defines each UI member variable and the configuration logic that used to be found within the InitializeComponent() method of ASP.NET 1.x (we just never directly see it). This partial class is combined at compile time with the code-behind file to result in the base class of the generated _aspx class type (in the single-file page compilation model, the generated _aspx file derived directly from System.Web.UI.Page).

In either case, once the assembly has been created upon the initial HTTP request, it will be reused for all subsequent requests, and thus will not have to be recompiled. Understanding this factoid should help explain why the first request of an *.aspx page takes the longest, and subsequent hits to the same page are extremely efficient.

Note Under ASP.NET 2.0, it is now possible to precompile all pages (or a subset of pages) of a website using a command-line tool named aspnet_compiler.exe. Check out the .NET Framework 2.0 SDK documentation for details.

The Inheritance Chain of the Page Type

As you have just seen, the final generated class that represents your *.aspx file eventually derives from System.Web.UI.Page. Like any base class, this type provides a polymorphic interface to all derived types. However, the Page type is not the only member in your inheritance hierarchy. If you

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.

CHAPTER 23 ASP. NET 2 . 0 WEB PAGES AND WEB CONTROLS

859

While you could most certainly make use of the HttpRequest.Form and HttpRequest.QueryString properties to access client-supplied form data on the web server, these old-school techniques are (for the most part) unnecessary. Given that ASP.NET supplies you with server-side web controls, you are able to treat HTML UI elements as true objects. Therefore, rather than obtaining the value within a text box as follows:

protected void btnGetFormData_Click(object sender, EventArgs e)

{

// Get value for a widget with ID txtFirstName. string firstName = Request.Form["txtFirstName"];

}

you can simply ask the server-side widget directly via the Text property:

protected void btnGetFormData_Click(object sender, EventArgs e)

{

// Get value for a widget with ID txtFirstName. string firstName = txtFirstName.Text;

}

Not only does this approach lend itself to solid OO principles, but also you do not need to concern yourself with how the form data was submitted (GET or POST) before obtaining the values. Furthermore, working with the widget directly is much more type-safe, given that typing errors are discovered at compile time rather than runtime. Of course, this is not to say that you will never need to make use of the Form or QueryString property in ASP.NET; rather, the need to do so has greatly diminished.

The IsPostBack Property

Another very important member of HttpRequest is the IsPostBack property. Recall that “postback” refers to the act of returning to a particular web page while still in session with the server. Given this definition, understand that the IsPostBack property will return true if the current HTTP request has been sent by a currently logged on user and false if this is the user’s first interaction with the page.

Typically, the need to determine whether the current HTTP request is indeed a postback is most helpful when you wish to perform a block of code only the first time the user accesses a given page. For example, you may wish to populate an ADO.NET DataSet when the user first accesses an *.aspx file and cache the object for later use. When the caller returns to the page, you can avoid the need to hit the database unnecessarily (of course, some pages may require that the DataSet is always updated upon each request, but that is another issue):

protected void Page_Load(object sender, EventArgs e)

{

//Only fill DataSet the very first time

//the user comes to this page. if(!IsPostBack)

{

//Populate DataSet and cache it!

}

//Use cached DataSet.

}

Interacting with the Outgoing HTTP Response

Now that you have a better understanding how the Page type allows you to interact with the incoming HTTP request, the next step is to see how to interact with the outgoing HTTP response. In ASP.NET, the Response property of the Page class provides access to an instance of the HttpResponse type. This

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

{

...