Home > Articles > Programming > ASP .NET

This chapter is from the book

This chapter is from the book

Understanding ASP.NET Pages

This section examines ASP.NET pages in more detail. You learn about dynamic compilation and code-behind files. We also discuss the events supported by the Page class.

Understanding Dynamic Compilation

Strangely enough, when you create an ASP.NET page, you are actually creating the source code for a .NET class. You are creating a new instance of the System.Web.UI.Page class. The entire contents of an ASP.NET page, including all script and HTML content, are compiled into a .NET class.

When you request an ASP.NET page, the ASP.NET Framework checks for a .NET class that corresponds to the page. If a corresponding class does not exist, the Framework automatically compiles the page into a new class and stores the compiled class (the assembly) in the Temporary ASP.NET Files folder located at the following path:

\WINDOWS\Microsoft.NET\Framework\v2.0.50727\Temporary ASP.NET Files

The next time anyone requests the same page in the future, the page is not compiled again. The previously compiled class is executed and the results are returned to the browser.

Even if you unplug your web server, move to Borneo for three years, and start up your web server again, the next time someone requests the same page, the page does not need to be re-compiled. The compiled class is preserved in the Temporary ASP.NET Files folder until the source code for your application is modified.

When the class is added to the Temporary ASP.NET Files folder, a file dependency is created between the class and the original ASP.NET page. If the ASP.NET page is modified in any way, the corresponding .NET class is automatically deleted. The next time someone requests the page, the Framework automatically compiles the modified page source into a new .NET class.

This process is called dynamic compilation. Dynamic compilation enables ASP.NET applications to support thousands of simultaneous users. Unlike an ASP Classic page, for example, an ASP.NET page does not need to be parsed and compiled each and every time it is requested. An ASP.NET page is compiled only when an application is modified.

In case you are curious, I've included the source code for the class that corresponds to the FirstPage.aspx page in Listing 1.12 (I've cleaned up the code and made it shorter to save space). I copied this file from the Temporary ASP.NET Files folder after enabling debugging for the application.

Listing 1.12. FirstPage.aspx Source

namespace ASP
{
    using System.Web.Profile;
    using System.Text.RegularExpressions;
    using System.Web.Caching;
    using System.Configuration;
    using System.Collections.Specialized;
    using System.Web.UI.WebControls.WebParts;
    using System.Web.UI.HtmlControls;
    using System.Web.UI.WebControls;
    using System.Web.UI;
    using System.Collections;
    using System;
    using System.Web.Security;
    using System.Web;
    using System.Web.SessionState;
    using System.Text;


    [System.Runtime.CompilerServices.CompilerGlobalScopeAttribute()]
    public class firstpage_aspx : global::System.Web.UI.Page,
    System.Web.SessionState.IRequiresSessionState, System.Web.IHttpHandler
    {
        protected global::System.Web.UI.WebControls.Label lblServerTime;
        protected global::System.Web.UI.HtmlControls.HtmlForm form1;
        private static bool @__initialized;
        private static object @__fileDependencies;

        void Page_Load()
        {
            lblServerTime.Text = DateTime.Now.ToString();
        }

        public firstpage_aspx()
        {
            string[] dependencies;
            ((global::System.Web.UI.Page)(this)).AppRelativeVirtualPath = "~/FirstPage.aspx";
            if ((global::ASP.firstpage_aspx.@__initialized == false))
            {
                dependencies = new string[1];
                dependencies[0] = "~/FirstPage.aspx";
                global::ASP.firstpage_aspx.@__fileDependencies = this.GetWrappedFileDependencies(dependencies);
                global::ASP.firstpage_aspx.@__initialized = true;
            }
            this.Server.ScriptTimeout = 30000000;
        }

        protected System.Web.Profile.DefaultProfile Profile
        {
            get
            {
                return ((System.Web.Profile.DefaultProfile)(this.Context.Profile));
            }
        }

        protected System.Web.HttpApplication ApplicationInstance
        {
            get
            {
                return ((System.Web.HttpApplication)(this.Context.ApplicationInstance));
            }
        }

        private global::System.Web.UI.WebControls.Label @__BuildControllblServerTime()
        {
        ...code...
        }
        private global::System.Web.UI.HtmlControls.HtmlForm @__BuildControlform1()
        {
        ...code...
        }

        private void @__BuildControlTree(firstpage_aspx @__ctrl)
        {
        ...code...
        }

        protected override void FrameworkInitialize()
        {
            base.FrameworkInitialize();
            this.@__BuildControlTree(this);
            this.AddWrappedFileDependencies(global::ASP.firstpage_aspx.@__fileDependencies);
            this.Request.ValidateInput();
        }

        public override int GetTypeHashCode()
        {
            return 579569163;
        }

        public override void ProcessRequest(System.Web.HttpContext context)
        {
            base.ProcessRequest(context);
        }
    }
}

The class in Listing 1.12 inherits from the System.Web.UI.Page class. The ProcessRequest() method is called by the ASP.NET Framework when the page is displayed. This method builds the page's control tree, which is the subject of the next section.

Understanding Control Trees

In the previous section, you learned that an ASP.NET page is really the source code for a .NET class. Alternatively, you can think of an ASP.NET page as a bag of controls. More accurately, because some controls might contain child controls, you can think of an ASP.NET page as a control tree.

For example, the page in Listing 1.13 contains a DropDownList control and a Button control. Furthermore, because the <%@ Page %> directive has the Trace="true" attribute, tracing is enabled for the page.

Listing 1.13. ShowControlTree.aspx

<%@ Page Language="C#" Trace="true" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head id="Head1" runat="server">
    <title>Show Control Tree</title>
</head>
<body>
    <form id="form1" runat="server">
    <div>

    <asp:DropDownList
        id="DropDownList1"
        Runat="server">
        <asp:ListItem Text="Oranges" />
        <asp:ListItem Text="Apples" />
    </asp:DropDownList>

    <asp:Button
        id="Button1"
        Text="Submit"
        Runat="server" />

    </div>
    </form>
</body>
</html>

When you open the page in Listing 1.12 in your browser, you can see the control tree for the page appended to the bottom of the page. It looks like this:

__Page ASP.showcontroltree_aspx
    ctl02 System.Web.UI.LiteralControl
    ctl00 System.Web.UI.HtmlControls.HtmlHead
        ctl01 System.Web.UI.HtmlControls.HtmlTitle
    ctl03 System.Web.UI.LiteralControl
    form1 System.Web.UI.HtmlControls.HtmlForm
        ctl04 System.Web.UI.LiteralControl
        DropDownList1 System.Web.UI.WebControls.DropDownList
        ctl05 System.Web.UI.LiteralControl
        Button1 System.Web.UI.WebControls.Button
        ctl06 System.Web.UI.LiteralControl
    ctl07

The root node in the control tree is the page itself. The page has an ID of __Page. The page class contains all the other controls in its child controls collection.

The control tree also contains an instance of the HtmlForm class named form1. This control is the server-side form tag contained in the page. It contains all the other form controls—the DropDownList and Button controls—as child controls.

Notice that there are several LiteralControl controls interspersed between the other controls in the control tree. What are these controls?

Remember that everything in an ASP.NET page is converted into a .NET class, including any HTML or plain text content in a page. The LiteralControl class represents the HTML content in the page (including any carriage returns between tags).

Using Code-Behind Pages

The ASP.NET Framework (and Visual Web Developer) enables you to create two different types of ASP.NET pages. You can create both single-file and two-file ASP.NET pages.

All the code samples in this book are written as single-file ASP.NET pages. In a single-file ASP.NET page, a single file contains both the page code and page controls. The page code is contained in a <script runat="server"> tag.

As an alternative to a single-file ASP.NET page, you can create a two-file ASP.NET page. A two-file ASP.NET page is normally referred to as a code-behind page. In a code-behind page, the page code is contained in a separate file.

For example, Listing 1.14 and Listing 1.15 contain the two halves of a code-behind page.

Listing 1.14. FirstPageCodeBehind.aspx

<%@ Page Language="C#" AutoEventWireup="true" CodeFile="FirstPageCodeBehind.aspx.cs" Inherits="FirstPageCodeBehind" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head id="Head1" runat="server">
    <title>First Page Code-Behind</title>
</head>
<body>
    <form id="form1" runat="server">
    <div>

    <asp:Button
        id="Button1"
        Text="Click Here"
        OnClick="Button1_Click"
        Runat="server" />

    <br /><br />

    <asp:Label
        id="Label1"
        Runat="server" />

    </div>
    </form>
</body>
</html>

Listing 1.15. FirstPageCodeBehind.aspx.cs

using System;
using System.Data;
using System.Configuration;
using System.Collections;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;

public partial class FirstPageCodeBehind : System.Web.UI.Page
{
    protected void Page_Load(object sender, EventArgs e)
    {
        Label1.Text = "Click the Button";
    }

    protected void Button1_Click(object sender, EventArgs e)
    {
        Label1.Text = "Thanks!";
    }
}

The page in Listing 1.14 is called the presentation page. It contains a Button control and a Label control. However, the page does not contain any code. All the code is contained in the code-behind file.

The code-behind file in Listing 1.15 contains the Page_Load() and Button1_Click() handlers. The code-behind file in Listing 1.15 does not contain any controls.

Notice that the page in Listing 1.14 includes both a CodeFile and Inherits attribute in its <%@ Page %> directive. These attributes link the page to its code-behind file.

How Code-Behind Works: The Ugly Details

In the previous version of the ASP.NET Framework (ASP.NET 1.x), two classes were generated by a code-behind page. One class corresponded to the presentation page and one class corresponded to the code-behind file. These classes were related to one another through class inheritance. The presentation page class inherited from the code-behind file class.

The problem with this method of associating presentation pages with their code-behind files was that it was very brittle. Inheritance is a one-way relationship. Anything that is true of the mother is true of the daughter, but not the other way around. Any control that you declared in the presentation page was required to be declared in the code-behind file. Furthermore, the control had to be declared with exactly the same ID. Otherwise, the inheritance relationship would be broken and events raised by a control could not be handled in the code-behind file.

In the beta version of ASP.NET 2.0, a completely different method of associating presentation pages with their code-behind files was used. This new method was far less brittle. The two halves of a code-behind page were no longer related through inheritance, but through a new technology supported by the .NET 2.0 Framework called partial classes.

Partial classes enable you to declare a class in more than one physical file. When the class gets compiled, one class is generated from all the partial classes. Any members of one partial class—including any private fields, methods, and properties—are accessible to any other partial classes of the same class. This makes sense because partial classes are combined eventually to create one final class.

The advantage of using partial classes is that you don't need to worry about declaring a control in both the presentation page and code-behind file. Anything that you declare in the presentation page is available automatically in the code-behind file, and anything you declare in the code-behind file is available automatically in the presentation page.

The beta version of the ASP.NET 2.0 Framework used partial classes to relate a presentation page with its code-behind file. However, certain advanced features of the ASP.NET 1.x Framework were not compatible with using partial classes. To support these advanced features, a more complex method of associating presentation pages with code-behind files is used in the final release of the ASP.NET 2.0 Framework.

The final release of the ASP.NET 2.0 Framework uses a combination of inheritance and partial classes to relate presentation pages and code-behind files. The ASP.NET 2.0 Framework generates three classes whenever you create a code-behind page.

The first two classes correspond to the presentation page. For example, when you create the FirstPageCodeBehind.aspx page, the following two classes are generated automatically in the Temporary ASP.NET Files folder:

public partial class FirstPageCodeBehind
{
    protected System.Web.UI.WebControls.Button Button1;
    protected System.Web.UI.WebControls.Label Label1;

    ... additional code ...
}

public class firstpagecodebehind_aspx : FirstPageCodeBehind
{
    ... additional code ...
}

A third class is generated that corresponds to the code-behind file. Corresponding to the FirstPageCodeBehind.aspx.cs file, the following class is generated:

public partial class FirstPageCodeBehind : System.Web.UI.Page
{
    protected void Page_Load(object sender, EventArgs e)
    {
        Label1.Text = "Click the Button";
    }

    protected void Button1_Click(object sender, EventArgs e)
    {
        Label1.Text = "Thanks!";
    }
}

The firstpagecodebehind_aspx class is executed when the FirstPageCodeBehind.aspx page is requested from a browser. This class inherits from the FirstPageCodeBehind class. The FirstPageCodeBehind class is a partial class. It gets generated twice: once by the presentation page and once by the code-behind file.

The final release of the ASP.NET 2.0 Framework uses a combination of partial classes and inheritance to relate presentation pages and code-behind files. Because the page and code-behind classes are partial classes, unlike the previous version of ASP.NET, you no longer need to declare controls in both the presentation and code-behind page. Any control declared in the presentation page is accessible in the code-behind file automatically. Because the page class inherits from the code-behind class, the ASP.NET 2.0 Framework continues to support advanced features of the ASP.NET 1.x Framework such as custom base Page classes.

Deciding Between Single-File and Code-Behind Pages

So, when should you use single-file ASP.NET pages and when should you use code-behind pages? This decision is a preference choice. There are intense arguments over this topic contained in blogs spread across the Internet.

I've heard it argued that code-behind pages are superior to single-file pages because code-behind pages enable you to more cleanly separate your user interface from your application logic. The problem with this argument is that the normal justification for separating your user interface from your application logic is code reuse. Building code-behind pages really doesn't promote code reuse. A better way to reuse application logic across multiple pages is to build separate component libraries. (Part IV of this book explores this topic.)

My personal preference is to build ASP.NET applications using single-file ASP.NET pages because this approach requires managing fewer files. However, I've built many applications using the code-behind model (such as some of the ASP.NET Starter Kits) without suffering dire consequences.

Handling Page Events

Whenever you request an ASP.NET page, a particular set of events is raised in a particular sequence. This sequence of events is called the page execution lifecycle.

For example, we have already used the Page Load event in previous code samples in this chapter. You normally use the Page Load event to initialize the properties of controls contained in a page. However, the Page Load event is only one event supported by the Page class.

Here is the sequence of events that are raised whenever you request a page:

  1. PreInit
  2. Init
  3. InitComplete
  4. PreLoad
  5. Load
  6. LoadComplete
  7. PreRender
  8. PreRenderComplete
  9. SaveStateComplete
  10. Unload

Why so many events? Different things happen and different information is available at different stages in the page execution lifecycle.

For example, View State is not loaded until after the InitComplete event. Data posted to the server from a form control, such as a TextBox control, is also not available until after this event.

Ninety-nine percent of the time, you won't handle any of these events except for the Load and the PreRender events. The difference between these two events is that the Load event happens before any control events and the PreRender event happens after any control events.

The page in Listing 1.16 illustrates the difference between the Load and PreRender events. The page contains three event handlers: one for the Load event, one for the Button Click event, and one for the PreRender event. Each handler adds a message to a Label control (see Figure 1.12).

Figure 1.12

Figure 1.12 Viewing the sequence of page events.

Listing 1.16. ShowPageEvents.aspx

<%@ Page Language="C#" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<script runat="server">

    void Page_Load(object sender, EventArgs e)
    {
        Label1.Text = "Page Load";
    }

    void Button1_Click(object sender, EventArgs e)
    {
        Label1.Text += "<br />Button Click";
    }

    void Page_PreRender()
    {
        Label1.Text += "<br />Page PreRender";
    }
</script>
<html xmlns="http://www.w3.org/1999/xhtml" >
<head id="Head1" runat="server">
    <title>Show Page Events</title>
</head>
<body>
    <form id="form1" runat="server">
    <div>

    <asp:Button
        id="Button1"
        Text="Click Here"
        OnClick="Button1_Click"
        Runat="server" />

    <br /><br />

    <asp:Label
        id="Label1"
        Runat="server" />

    </div>
    </form>
</body>
</html>

When you click the Button control, the Click event does not happen on the server until after the Load event and before the PreRender event.

The other thing you should notice about the page in Listing 1.16 is the way the event handlers are wired to the Page events. ASP.NET pages support a feature named AutoEventWireUp, which is enabled by default. If you name a subroutine Page_Load(), the subroutine automatically handles the Page Load event; if you name a subroutine Page_PreRender(), the subroutine automatically handles the Page PreRender event, and so on.

Using the Page.IsPostBack Property

The Page class includes a property called the IsPostBack property, which you can use to detect whether the page has already been posted back to the server.

Because of View State, when you initialize a control property, you do not want to initialize the property every time a page loads. Because View State saves the state of control properties across page posts, you typically initialize a control property only once, when the page first loads.

In fact, many controls don't work correctly if you re-initialize the properties of the control with each page load. In these cases, you must use the IsPostBack property to detect whether or not the page has been posted.

The page in Listing 1.17 illustrates how you can use the Page.IsPostBack property when adding items to a DropDownList control.

Listing 1.17. ShowIsPostBack.aspx

<%@ Page Language="C#" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<script runat="server">

    void Page_Load()
    {

        if (!Page.IsPostBack)
        {
            // Create collection of items
            ArrayList items = new ArrayList();
            items.Add("Apples");
            items.Add("Oranges");

            // Bind to DropDownList
            DropDownList1.DataSource = items;
            DropDownList1.DataBind();
        }
    }

    protected void Button1_Click(object sender, EventArgs e)
    {
        Label1.Text = DropDownList1.SelectedItem.Text;
    }
</script>
<html xmlns="http://www.w3.org/1999/xhtml" >
<head id="Head1" runat="server">
    <title>Show IsPostBack</title>
</head>
<body>
    <form id="form1" runat="server">
    <div>

    <asp:DropDownList
        id="DropDownList1"
        Runat="server" />

    <asp:Button
        id="Button1"
        Text="Select"
        OnClick="Button1_Click"
        Runat="server" />

    <br /><br />

    You selected:
    <asp:Label
        id="Label1"
        Runat="server" />

    </div>
    </form>
</body>
</html>

In Listing 1.17, the code in the Page_Load() event handler executes only once when the page first loads. When you post the page again, the IsPostBack property returns True and the code contained in the Page_Load() handler is skipped.

If you remove the IsPostBack check from the Page_Load() method, then you get a strange result. The DropDownList always displays its first item as the selected item. Binding the DropDownList to a collection of items re-initializes the DropDownList control. Therefore, you want to bind the DropDownList control only once, when the page first loads.

Debugging and Tracing ASP.NET Pages

The sad fact of life is that you spend the majority of your development time when building applications debugging the application.

In this section, you learn how to get detailed error messages when developing ASP.NET pages. You also learn how you can display custom trace messages that you can use when debugging a page.

Debugging ASP.NET Pages

If you need to view detailed error messages when you execute a page, you need to enable debugging for either the page or your entire application. You can enable debugging for a page by adding a Debug="true" attribute to the <%@ Page %> directive. For example, the page in Listing 1.18 has debugging enabled.

Listing 1.18. ShowError.aspx

<%@ Page Language="C#" Debug="true" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<script runat="server">

    void Page_Load()
    {
        int zero = 0;
        Label1.Text = (1 / zero).ToString();
    }

</script>
<html xmlns="http://www.w3.org/1999/xhtml" >
<head id="Head1" runat="server">
    <title>Show Error</title>
</head>
<body>
    <form id="form1" runat="server">
    <div>

    <asp:Label
        id="Label1"
        Runat="server" />

    </div>
    </form>
</body>
</html>

When you open the page in Listing 1.18 in your web browser, a detailed error message is displayed (see Figure 1.13).

Figure 1.13

Figure 1.13 Viewing a detailed error message.

Rather than enable debugging for a single page, you can enable debugging for an entire application by adding the web configuration file in Listing 1.19 to your application.

Listing 1.19. Web.Config

<configuration>
<system.web>
  <compilation debug="true" />
</system.web>
</configuration>

When debugging an ASP.NET application located on a remote web server, you need to disable custom errors. For security reasons, by default, the ASP.NET Framework doesn't display error messages when you request a page from a remote machine. When custom errors are enabled, you don't see errors on a remote machine. The modified web configuration file in Listing 1.20 disables custom errors.

Listing 1.20. Modified Web.Config

<configuration>
<system.web>
  <compilation debug="true" />
  <customErrors mode="Off" />
</system.web>
</configuration>

Debugging Pages with Visual Web Developer

If you are using Visual Web Developer, then you can display compilation error messages by performing a build on a page or an entire website. Select the menu option Build, Build Page or the menu option Build, Build Web Site. A list of compilation error messages and warnings appears in the Error List window (see Figure 1.14). You can double-click any of the errors to navigate directly to the code that caused the error.

Figure 1.14

Figure 1.14 Performing a build in Visual Web Developer.

If you need to perform more advanced debugging, you can use the Visual Web Developer's debugger. The debugger enables you to set breakpoints and step line by line through your code.

You set a breakpoint by double-clicking the left-most column in Source view. When you add a breakpoint, a red circle appears (see Figure 1.15).

Figure 1.15

Figure 1.15 Setting a breakpoint.

After you set a breakpoint, run your application by selecting the menu option Debug, Start Debugging. Execution stops when the breakpoint is hit. At that point, you can hover your mouse over any variable or control property to view the current value of the variable or control property.

After you hit a breakpoint, you can continue execution by selecting Step Into, Step Over, or Step Out from the Debug menu or the toolbar. Here's an explanation of each of these options:

  • Step Into—Executes the next line of code.
  • Step Over—Executes the next line of code without leaving the current method.
  • Step Out—Executes the next line of code and returns to the method that called the current method.

When you are finished debugging a page, you can continue, stop, or restart your application by selecting a particular option from the Debug menu or the toolbar.

Tracing Page Execution

If you want to output trace messages while a page executes, then you can enable tracing for a particular page or an entire application. The ASP.NET Framework supports both page-level tracing and application-level tracing.

The page in Listing 1.21 illustrates how you can take advantage of page-level tracing.

Listing 1.21. PageTrace.aspx

 <%@ Page Language="C#" Trace="true" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<script runat="server">

    void Page_Load()
    {
        for (int counter = 0; counter < 10; counter++)
        {
            ListBox1.Items.Add("item " + counter.ToString());
            Trace.Warn("counter=" + counter.ToString());
        }
    }

</script>
<html xmlns="http://www.w3.org/1999/xhtml" >
<head id="Head1" runat="server">
    <title>Page Trace</title>
</head>
<body>
    <form id="form1" runat="server">
    <div>

    <asp:ListBox
        id="ListBox1"
        Runat="server" />

    </div>
    </form>
</body>
</html>

Notice that the <%@ Page %> directive in Listing 1.21 includes a trace="true" attribute. This attribute enables tracing and causes a Trace Information section to be appended to the bottom of the page (see Figure 1.16).

Figure 1.16

Figure 1.16 Viewing page trace information.

Notice, furthermore, that the Page_Load() handler uses the Trace.Warn() method to write messages to the Trace Information section. You can output any string to the Trace Information section that you please. In Listing 1.21, the current value of a variable named counter is displayed.

You'll want to take advantage of page tracing when you need to determine exactly what is happening when a page executes. You can call the Trace.Warn() method wherever you need in your code. Because the Trace Information section appears even when there is an error in your page, you can use tracing to diagnose the causes of any page errors.

One disadvantage of page tracing is that everyone in the world gets to see your trace information. You can get around this problem by taking advantage of application-level tracing. When application-level tracing is enabled, trace information appears only when you request a special page named Trace.axd.

To enable application-level tracing, you need to add the web configuration file in Listing 1.22 to your application.

Listing 1.22. Web.Config

<configuration>
<system.web>
    <trace enabled="true" />
</system.web>
</configuration>

After you add the Web.Config file in Listing 1.22 to your application, you can request the Trace.axd page in your browser. The last 10 page requests made after application-level tracing is enabled are displayed (see Figure 1.17).

Figure 1.17

Figure 1.17 Viewing application trace information.

If you click the View Details link next to any of the listed page requests, you can view all the trace messages outputted by the page. Messages written with the Trace.Warn() method are displayed by the Trace.axd page even when page-level tracing is disabled.

InformIT Promotional Mailings & Special Offers

I would like to receive exclusive offers and hear about products from InformIT and its family of brands. I can unsubscribe at any time.

Overview


Pearson Education, Inc., 221 River Street, Hoboken, New Jersey 07030, (Pearson) presents this site to provide information about products and services that can be purchased through this site.

This privacy notice provides an overview of our commitment to privacy and describes how we collect, protect, use and share personal information collected through this site. Please note that other Pearson websites and online products and services have their own separate privacy policies.

Collection and Use of Information


To conduct business and deliver products and services, Pearson collects and uses personal information in several ways in connection with this site, including:

Questions and Inquiries

For inquiries and questions, we collect the inquiry or question, together with name, contact details (email address, phone number and mailing address) and any other additional information voluntarily submitted to us through a Contact Us form or an email. We use this information to address the inquiry and respond to the question.

Online Store

For orders and purchases placed through our online store on this site, we collect order details, name, institution name and address (if applicable), email address, phone number, shipping and billing addresses, credit/debit card information, shipping options and any instructions. We use this information to complete transactions, fulfill orders, communicate with individuals placing orders or visiting the online store, and for related purposes.

Surveys

Pearson may offer opportunities to provide feedback or participate in surveys, including surveys evaluating Pearson products, services or sites. Participation is voluntary. Pearson collects information requested in the survey questions and uses the information to evaluate, support, maintain and improve products, services or sites, develop new products and services, conduct educational research and for other purposes specified in the survey.

Contests and Drawings

Occasionally, we may sponsor a contest or drawing. Participation is optional. Pearson collects name, contact information and other information specified on the entry form for the contest or drawing to conduct the contest or drawing. Pearson may collect additional personal information from the winners of a contest or drawing in order to award the prize and for tax reporting purposes, as required by law.

Newsletters

If you have elected to receive email newsletters or promotional mailings and special offers but want to unsubscribe, simply email information@informit.com.

Service Announcements

On rare occasions it is necessary to send out a strictly service related announcement. For instance, if our service is temporarily suspended for maintenance we might send users an email. Generally, users may not opt-out of these communications, though they can deactivate their account information. However, these communications are not promotional in nature.

Customer Service

We communicate with users on a regular basis to provide requested services and in regard to issues relating to their account we reply via email or phone in accordance with the users' wishes when a user submits their information through our Contact Us form.

Other Collection and Use of Information


Application and System Logs

Pearson automatically collects log data to help ensure the delivery, availability and security of this site. Log data may include technical information about how a user or visitor connected to this site, such as browser type, type of computer/device, operating system, internet service provider and IP address. We use this information for support purposes and to monitor the health of the site, identify problems, improve service, detect unauthorized access and fraudulent activity, prevent and respond to security incidents and appropriately scale computing resources.

Web Analytics

Pearson may use third party web trend analytical services, including Google Analytics, to collect visitor information, such as IP addresses, browser types, referring pages, pages visited and time spent on a particular site. While these analytical services collect and report information on an anonymous basis, they may use cookies to gather web trend information. The information gathered may enable Pearson (but not the third party web trend services) to link information with application and system log data. Pearson uses this information for system administration and to identify problems, improve service, detect unauthorized access and fraudulent activity, prevent and respond to security incidents, appropriately scale computing resources and otherwise support and deliver this site and its services.

Cookies and Related Technologies

This site uses cookies and similar technologies to personalize content, measure traffic patterns, control security, track use and access of information on this site, and provide interest-based messages and advertising. Users can manage and block the use of cookies through their browser. Disabling or blocking certain cookies may limit the functionality of this site.

Do Not Track

This site currently does not respond to Do Not Track signals.

Security


Pearson uses appropriate physical, administrative and technical security measures to protect personal information from unauthorized access, use and disclosure.

Children


This site is not directed to children under the age of 13.

Marketing


Pearson may send or direct marketing communications to users, provided that

  • Pearson will not use personal information collected or processed as a K-12 school service provider for the purpose of directed or targeted advertising.
  • Such marketing is consistent with applicable law and Pearson's legal obligations.
  • Pearson will not knowingly direct or send marketing communications to an individual who has expressed a preference not to receive marketing.
  • Where required by applicable law, express or implied consent to marketing exists and has not been withdrawn.

Pearson may provide personal information to a third party service provider on a restricted basis to provide marketing solely on behalf of Pearson or an affiliate or customer for whom Pearson is a service provider. Marketing preferences may be changed at any time.

Correcting/Updating Personal Information


If a user's personally identifiable information changes (such as your postal address or email address), we provide a way to correct or update that user's personal data provided to us. This can be done on the Account page. If a user no longer desires our service and desires to delete his or her account, please contact us at customer-service@informit.com and we will process the deletion of a user's account.

Choice/Opt-out


Users can always make an informed choice as to whether they should proceed with certain services offered by InformIT. If you choose to remove yourself from our mailing list(s) simply visit the following page and uncheck any communication you no longer want to receive: www.informit.com/u.aspx.

Sale of Personal Information


Pearson does not rent or sell personal information in exchange for any payment of money.

While Pearson does not sell personal information, as defined in Nevada law, Nevada residents may email a request for no sale of their personal information to NevadaDesignatedRequest@pearson.com.

Supplemental Privacy Statement for California Residents


California residents should read our Supplemental privacy statement for California residents in conjunction with this Privacy Notice. The Supplemental privacy statement for California residents explains Pearson's commitment to comply with California law and applies to personal information of California residents collected in connection with this site and the Services.

Sharing and Disclosure


Pearson may disclose personal information, as follows:

  • As required by law.
  • With the consent of the individual (or their parent, if the individual is a minor)
  • In response to a subpoena, court order or legal process, to the extent permitted or required by law
  • To protect the security and safety of individuals, data, assets and systems, consistent with applicable law
  • In connection the sale, joint venture or other transfer of some or all of its company or assets, subject to the provisions of this Privacy Notice
  • To investigate or address actual or suspected fraud or other illegal activities
  • To exercise its legal rights, including enforcement of the Terms of Use for this site or another contract
  • To affiliated Pearson companies and other companies and organizations who perform work for Pearson and are obligated to protect the privacy of personal information consistent with this Privacy Notice
  • To a school, organization, company or government agency, where Pearson collects or processes the personal information in a school setting or on behalf of such organization, company or government agency.

Links


This web site contains links to other sites. Please be aware that we are not responsible for the privacy practices of such other sites. We encourage our users to be aware when they leave our site and to read the privacy statements of each and every web site that collects Personal Information. This privacy statement applies solely to information collected by this web site.

Requests and Contact


Please contact us about this Privacy Notice or if you have any requests or questions relating to the privacy of your personal information.

Changes to this Privacy Notice


We may revise this Privacy Notice through an updated posting. We will identify the effective date of the revision in the posting. Often, updates are made to provide greater clarity or to comply with changes in regulatory requirements. If the updates involve material changes to the collection, protection, use or disclosure of Personal Information, Pearson will provide notice of the change through a conspicuous notice on this site or other appropriate way. Continued use of the site after the effective date of a posted revision evidences acceptance. Please contact us if you have questions or concerns about the Privacy Notice or any objection to any revisions.

Last Update: November 17, 2020