Home > Articles > Programming > Windows Programming

The Web Forms Programming Model

Calc.aspx demonstrates three important principles of the Web Forms programming model:

  • A Web form's user interface is "declared" using a combination of HTML and server controls. Controls can be customized by using control properties as attributes in the tags that declare the controls. Controls are also bona fide objects that are instantiated and executed each time the page that hosts them is requested.

  • Server controls fire events that can be handled by server-side scripts. In effect, ASP.NET abstracts the divide between client and server by creating the illusion that events are fired and handled on the same machine. In reality, events fire on the server when an external stimulus (such as the click of a button) causes the form to post back to the server.

  • Server-side scripts aren't scripts in the conventional sense of the word. Unlike ASP scripts, which are interpreted rather than compiled and therefore run rather slowly, server-side scripts in ASP.NET are compiled to common intermediate language (CIL) and executed by the common language runtime. Although ASP.NET pages incur more processing overhead than static HTML pages, they tend to execute much faster than ASP pages.

You probably noticed the RunAt="server" attributes sprinkled throughout Calc.aspx. RunAt="server" is the key that unlocks the door to the magic of Web forms; it signals ASP.NET to "execute" the tag rather than treat it as static HTML. RunAt="server" is not optional. It must be used in every tag that ASP.NET is to process, including the <form> tag that marks the beginning of a form containing server controls.

Web Controls

TextBox, Button, and Label are server controls. They're also examples of Web controls—server controls defined in the FCL's System.Web.UI.WebControls namespace. The Web controls family includes almost 30 different control types that you can use in ASP.NET Web forms. Table 1 lists the Web controls provided in version 1.0 of the .NET Framework class library.

Table 1: Web Controls

Class Name

Description

AdRotator

Displays rotating banners in Web forms

Button

Generates submit buttons

Calendar

Displays calendars with selectable dates

CheckBox

Displays a check box in a Web form

CheckBoxList

Displays a group of check boxes

CompareValidator

Validates user input by comparing it to another value

CustomValidator

Validates user input using the algorithm of your choice

DataGrid

Displays data in tabular format

DataList

Displays items using single-column or multicolumn lists

DropDownList

Generates HTML drop-down lists

HyperLink

Generates hyperlinks

Image

Displays images in Web forms

ImageButton

Displays graphical push buttons

Label

Generates programmable text fields

LinkButton

Generates hyperlinks that post back to the server

ListBox

Generates HTML list boxes

Literal

Generates literal text in a Web form

Panel

Groups other controls

RadioButton

Displays a radio button in a Web form

RadioButtonList

Displays a group of check boxes

RangeValidator

Verifies that user input falls within a specified range

RegularExpressionValidator

Validates user input using regular expressions

Repeater

Displays items in simple lists

RequiredFieldValidator

Verifies that an input field isn't empty

Table

Generates HTML tables

TextBox

Generates text input fields

ValidationSummary

Displays a summary of validation errors

Xml

Displays XML documents and documents generated from XML using XSLT


Some Web controls are simple devices that produce equally simple HTML. Others produce more complex HTML, and some even return client-side script. Calendar controls, for example, emit a rich mixture of HTML and JavaScript. It's not easy to add a calendar to a Web page by hand (especially if you want dates in the calendar to be clickable), but calendars are no big deal in Web forms: You simply include an <asp:Calendar> tag in an ASPX file. DataGrid is another example of a sophisticated control type. One DataGrid control can replace reams of old ASP code that queries a database and returns the results in a richly formatted HTML table.

HTML Controls

Most Web forms are built from Web controls, but ASP.NET supports a second type of server control called HTML controls. HTML controls are instances of classes defined in the FCL's System.Web.UI.HtmlControls namespace. They're declared by adding RunAt="server" (or, if you'd prefer, runat="server"; capitalization doesn't matter in HTML) attributes to ordinary HTML tags. For example, the statement

<input type="text" />

declares a standard HTML text input field. However, the statement

<input type="text" runat="server" />

declares an HTML control—specifically, an instance of System.Web.UI.HtmlControls.HtmlInputText. At run time, ASP.NET sees the runat="server" attribute and creates an HtmlInputText object. The HtmlInputText object, in turn, emits an <input type="text"> tag that's ultimately returned to the browser.

Without realizing it, you used an HTML control in Calc.aspx. The line

<form runat="server">

caused an instance of System.Web.UI.HtmlControls.HtmlForm to be created on the server. HtmlForm returned the <form> tag that you saw when you viewed the page's HTML source code with the View/Source command:

<form name="_ctrl0" method="post" action="calc.aspx" id="_ctrl0">

HtmlInputText and HtmlForm are but two of many controls defined in the System.Web.UI.HtmlControls namespace. Table 2 lists all the HTML controls that the FCL supports and the tags that produce them.

Table 2: HTML Controls

Tag

Corresponding HTML Control

<a runat="server">

HtmlAnchor

<button runat="server">

HtmlButton

<form runat="server">

HtmlForm

<img runat="server">

HtmlImage

<input type="button" runat="server">

HtmlInputButton

<input type="reset" runat="server">

HtmlInputButton

<input type="submit" runat="server">

HtmlInputButton

<input type="checkbox" runat="server">

HtmlInputCheckBox

<input type="file" runat="server">

HtmlInputFile

<input type="hidden" runat="server">

HtmlInputHidden

<input type="image" runat="server">

HtmlInputImage

<input type="radio" runat="server">

HtmlInputRadioButton

<input type="password" runat="server">

HtmlInputText

<input type="text" runat="server">

HtmlInputText

<select runat="server">

HtmlSelect

<table runat="server">

HtmlTable

<td runat="server">

HtmlTableCell

<th runat="server">

HtmlTableCell

<tr runat="server">

HtmlTableRow

<textarea runat="server">

HtmlTextArea

Any other tag with runat="server"

HtmlGenericControl


It's important to know which HtmlControls class corresponds to a given HTML tag because only by knowing the class name can you consult the documentation to determine which properties you can use with that tag and which events the resulting control fires. For example, here's the HTML controls version of Calc.aspx:

<html>
 <body>
  <form runat="server">
   <input type="text" id="op1" runat="server" />
   +
   <input type="text" id="op2" runat="server" />
   <input type="submit" value=" = " OnServerClick="OnAdd"
    runat="server" />
   <span id="Sum" runat="server" />
  </form>
 </body>
</html>

<script language="C#" runat="server">
 void OnAdd (Object sender, EventArgs e)
 {
   int a = Convert.ToInt32 (op1.Value);
   int b = Convert.ToInt32 (op2.Value);
   Sum.InnerText = (a + b).ToString ();
 }
</script>

Besides the different way in which the form's controls are declared, the HTML controls version of this Web form differs from the Web controls version in three important respects:

  • The attribute that wires the button control to the event handler is named OnServerClick rather than OnClick. Why? Because an <input type="button" runat="server" /> tag translates into an instance of HtmlInputButton, and HtmlInputButton controls, unlike Button controls, don't fire Click events. They fire ServerClick events.

  • OnAdd reads input from the textboxes using the property name Value rather than Text. HtmlInputText controls don't have Text properties as Labels and TextBoxes do; instead, they expose their contents using Value properties.

  • OnAdd writes its output by initializing Sum's InnerText property instead of its Text property. The <span runat="server"> tag creates an instance of HtmlGenericControl. HtmlGenericControl doesn't have a Text property, but it does have an InnerText property.

Once you know which class ASP.NET instantiates as a result of applying a runat="server" tag to an otherwise ordinary HTML tag, you can figure out from the documentation what the tag's programmatic interface looks like.

Why does ASP.NET support HTML controls when Web controls do everything that HTML controls do and then some? HTML controls simplify the task of turning existing HTML forms into Web forms. It takes a while to convert a couple of hundred <input> tags and <select> tags and other HTML tags into Web controls. It doesn't take long to add runat="server" to each of them.

Page-Level Events

Server controls that render HTML and fire events are a cornerstone of the Web Forms programming model, but controls aren't the only entities that fire events. Pages do, too. To understand page-level events, it helps to understand what goes on behind the scenes when ASP.NET processes the first HTTP request for an ASPX file:

  1. ASP.NET creates a temporary file containing a class derived from System.Web.UI.Page. The Page class is one of the most important classes in ASP.NET; it represents ASP.NET Web pages.

  2. ASP.NET copies the code in the ASPX file, as well as some code of its own, to the Page-derived class. A method named OnAdd in a <script> block in an ASPX file becomes a member method of the derived class.

  3. ASP.NET compiles the derived class and places the resulting DLL in a system folder. The DLL is cached so that steps 1 and 2 won't have to be repeated unless the contents of the ASPX file change.

  4. ASP.NET instantiates the derived class and "executes" it by calling a series of methods on it. It is during this execution phase that the Page object instantiates any controls declared inside it and solicits their output.

As a Page object executes, it fires a series of events that can be processed by server-side scripts. The most important are Init, which is fired when the page is first instantiated, and Load, which is fired after the page's controls are created but before the page renders any output. The Load event is particularly important to ASP.NET developers because a Load handler is the perfect place to initialize any controls that require dynamic (that is, runtime) initialization. The next section offers an example.

If you want to see the DLLs that ASP.NET generates from your ASPX files, you'll find them in subdirectories under the Windows (or Winnt) directory's Microsoft.NET\Framework\vn.n.nnnn\Temporary ASP.NET Files subdirectory, where n.n.nnnn is the version number of the .NET Framework installed on your PC. Drill down to the bottom of the directory tree under Temporary ASP.NET Files\root, for example, and you'll find a DLL containing the class that ASP.NET derived from Page to serve Calc.aspx (assuming that you ran Calc.aspx from \Inetpub\wwwroot). If the subdirectory contains several DLLs, open them with ILDASM, and you'll find one containing a Page-derived class named Calc_aspx. (See Figure 4.) That's the class ASP.NET instantiates each time a request arrives for Calc.aspx. If Calc.aspx changes, ASP.NET recompiles the DLL on the next request. Otherwise, the DLL remains on your hard disk so that ASP.NET can reuse it as needed.

Figure 4 DLL generated from Calc.aspx.

The Page.Load Event and the Page.IsPostBack Property

Suppose you want to build a Web form that displays today's date and the four days following it in a drop-down list. If today is January 1, 2002, one solution is to statically initialize a DropDownList control:

<asp:DropDownList ID="MyList" RunAt="server">
 <asp:ListItem Text="January 1, 2002" RunAt="server" />
 <asp:ListItem Text="January 2, 2002" RunAt="server" />
 <asp:ListItem Text="January 3, 2002" RunAt="server" />
 <asp:ListItem Text="January 4, 2002" RunAt="server" />
 <asp:ListItem Text="January 5, 2002" RunAt="server" />
</asp:DropDownList>

The problem with this approach is obvious: Every day you'll have to modify the form to update the dates. A smarter approach is to write a handler for the page's Load event that initializes the DropDownList at run time:

<asp:DropDownList ID="MyList" RunAt="server" />
 .
 .
 .
<script language="C#" runat="server">
 void Page_Load (Object sender, EventArgs e)
 {
   if (!IsPostBack) {
     for (int i=0; i<5; i++) {
       DateTime date =
         DateTime.Today + new TimeSpan (i, 0, 0, 0);
       MyList.Items.Add (date.ToString ("MMMM dd, yyyy"));
     }
   }
 }
</script>

A Page_Load method prototyped this way is automatically called by ASP.NET when the page fires a Load event. You don't have to manually wire the event to the handler as you do for controls. The same is true for all page-level events. You can respond to any event fired by Page by writing a method named Page_EventName, where EventName is the name of the event you want to handle.

The Page_Load handler in the previous example adds items to the DropDownList by calling Add on the control's Items collection. Items represents the items in the DropDownList. Significantly, this implementation of Page_Load initializes the control only if a value named IsPostBack is false. IsPostBack is one of several properties defined in the Page class. Because all code in an ASPX file executes in the context of a class derived from Page, your code enjoys intrinsic access to Page properties and methods. IsPostBack is a particularly important property because it reveals whether your code is executing because the page was requested from the Web server with an HTTP GET (IsPostBack==false) or because the page was posted back to the server (IsPostBack==true). In general, you don't want to initialize a Web control during a postback because ASP.NET maintains the control's state for you. If you call Add on the control's Items collection the first time the page is fetched and then call it again when the page is posted back, the control will have twice as many items in it following the first postback.

The Page.Init Event

Page_Load methods are handy for performing runtime control initializations. You can also write Page_Init methods that fire in response to Init events. One use for Init events is to create controls and add them to the page at run time. Another is to programmatically wire events to event handlers. For example, instead of connecting Click events to an event handler with an OnClick attribute, like this:

<asp:Button Text=" = " OnClick="OnAdd" RunAt="server" />
 .
 .
 .
<script language="C#" runat="server">
 void OnAdd (Object sender, EventArgs e)
 {
   int a = Convert.ToInt32 (op1.Text);
   int b = Convert.ToInt32 (op2.Text);
   Sum.Text = (a + b).ToString ();
 }
</script>

you could connect them programmatically in this manner:

<asp:Button Text=" = " ID="EqualsButton" RunAt="server" />
 .
 .
 .
<script language="C#" runat="server">
 void Page_Init (Object sender, EventArgs e)
 {
   EqualsButton.Click += new EventHandler (OnAdd);
 }

 void OnAdd (Object sender, EventArgs e)
 {
   int a = Convert.ToInt32 (op1.Text);
   int b = Convert.ToInt32 (op2.Text);
   Sum.Text = (a + b).ToString ();
 }
</script>

This is the technique that Visual Studio .NET uses to wire events to event handlers. You'll see an example at the end of this article when you build a Web Forms application with Visual Studio .NET.

Page-Level Directives

ASP.NET supports a number of commands called page-level directives that you can put in ASPX files. They're sometimes called @ directives because all directive names begin with an @ sign: @ Page, @ Import, and so on. Page-level directives appear between <% and %> symbols and must be positioned at the top of an ASPX file. In practice, @ directives appear in all but the simplest of ASPX files. Table 3 lists the directives that ASP.NET supports. Succeeding sections document the most commonly used directives. Other directives are discussed as circumstances warrant.

Table 3: ASP.NET @ Directives

Directive

Description

@ Page

Defines general attributes and compilation settings for ASPX files

@ Control

Defines general attributes and compilation settings for ASCX files

@ Import

Imports a namespace

@ Assembly

Enables linkage to assemblies not linked to by default

@ Register

Registers user controls and custom controls for use in a Web form

@ OutputCache

Exerts declarative control over page caching and fragment caching

@ Reference

Adds a reference to an external ASPX or ASCX file

@ Implements

Identifies an interface implemented by a Web page


The @ Page Directive

Of the various page-level directives that ASP.NET supports, @ Page is the one used most often. The following @ Page directive changes the default language for all scripts that don't specify otherwise from Visual Basic .NET to C#. It's especially useful when you "inline" code in an ASPX file by placing it between <% and %> tags:

<%@ Page Language="C#" %>

And here's an ASPX file that uses it:

<%@ Page Language="C#" %>

<html>
 <body>
  <%
   Response.Write ("Hello, world");
  %>
 </body>
</html>

As this example demonstrates, ASP.NET pages can use Response and other intrinsic objects in the same way ASP pages can. Because you can't include Language="C#" attributes in <% %> blocks, you need either an @ Page directive telling ASP.NET which compiler to pass your code to or a Web.config file that changes the default language on a directory-wide basis.

Another common use for @ Page directives is to enable debugging support. By default, ASP.NET builds release-build DLLs from your ASPX files. If you encounter a runtime error and need to debug it, you need DLLs with debugging symbols. The statement

<%@ Page Debug="true" %>

commands ASP.NET to create debug DLLs rather than release DLLs and enriches the information available to you when you debug a malfunctioning Web form.

As you can see, @ Page is overloaded to support a variety of uses. In all, it supports some 28 different attributes, such as Language and Debug. A page can have only one @ Page directive, but that directive can contain any number of attributes. For example, the statement

<%@ Page Language="C#" Debug="true" %>

enables debugging and sets the page's default language to C#.

The @ Import Directive

Next to @ Page, the directive that ASP.NET programmers use the most is @ Import. The @ Import directive is ASP.NET's equivalent of C#'s using statement. Its purpose is to import a namespace so that the types in that namespace are known to the compiler. You need @ Import anytime you use an FCL data type that's defined in a namespace that ASP.NET doesn't import by default. For example, the statement

<%@ Import Namespace="System.Data" %>

makes all the data types defined in System.Data available to a Web form.

What namespaces does ASP.NET import by default? Here's a complete list:

  • System
  • System.Collections
  • System.Collections.Specialized
  • System.Configuration
  • System.IO
  • System.Text
  • System.Text.RegularExpressions
  • System.Web
  • System.Web.Caching
  • System.Web.Security
  • System.Web.SessionState
  • System.Web.UI
  • System.Web.UI.HtmlControls
  • System.Web.UI.WebControls

Because System.Data isn't imported automatically, you must import it yourself if you want to use System.Data types (for example, DataSet) in a Web form. Otherwise, you'll receive an error message the first time ASP.NET attempts to compile the page. System.Web.Mail is another example of a commonly used namespace that isn't imported automatically.

Unlike @ Page, @ Import can appear multiple times in a Web page. The following statements import three namespaces and are often used together in ASPX files that access SQL Server databases:

<%@ Import Namespace="System.Data" %>
<%@ Import Namespace="System.Data.SqlClient" %>
<%@ Import Namespace="System.Data.SqlTypes" %>

The @ Assembly Directive

The @ Import directive identifies namespaces containing an application's data types; @ Assembly identifies assemblies. The .NET Framework class library is implemented in a series of single-file assemblies: Mscorlib.dll, System.dll, and others. If ASP.NET is to compile your page, it must know which assemblies the page references so that it can provide that information to the compiler. The following assembly names are provided to the compiler by default and therefore require no @ Assembly directive:

  • Mscorlib.dll
  • System.dll
  • System.Data.dll
  • System.Drawing.dll
  • System.EnterpriseServices.dll
  • System.Web.dll
  • System.Web.Services.dll
  • System.Xml.dll

These assemblies include the data types that Web forms are most likely to use. But suppose that you want to use the FCL's System.DirectoryServices.DirectorySearcher class in a <script> block to perform a query against Active Directory. Because DirectorySearcher lives in an assembly (System.DirectoryServices.dll) that ASP.NET doesn't reference by default, its use requires an @ Assembly directive. In the following example, @ Import is required also because DirectorySearcher is defined in a nondefault namespace:

<%@ Import Namespace="System.DirectoryServices" %>
<%@ Assembly Name="System.DirectoryServices" %>

It's coincidental that the namespace name and the assembly name are one and the same; that's not always the case. Note that an assembly name passed to @ Assembly must not include the filename extension (.dll). In addition, the list of "default" assemblies can be changed by editing a machine-wide configuration file named Machine.config or can be augmented by dropping a Web.config file containing an <assemblies> section into an application root. Like @ Import, @ Assembly can appear multiple times in a Web page.

The @ OutputCache Directive

One of the best ways to optimize the performance of ASP.NET applications is to cache Web pages generated from ASPX files so that they can be delivered straight from the cache if they're requested again. ASP.NET supports two forms of caching: page caching, which caches entire pages, and fragment (or subpage) caching, which caches portions of pages. The @ OutputCache directive enables an application to exert declarative control over page and fragment caching.

Because examples have a way of lending clarity to a subject (funny how that works, isn't it?), here's a simple one that demonstrates @ OutputCache:

<%@ Page Language="C#" %>
<%@ OutputCache Duration="60" VaryByParam="None" %>

<html>
 <body>
  Today is <%= DateTime.Now.ToLongDateString () %>
 </body>
</html>

This ASPX file displays today's date in a Web page. (The <%= ... %> syntax is an alternative to using Response.Write. It's an easy way to inject text into the page's output.) Because today's date changes only every 24 hours, it's wasteful to re-execute this page every time it's requested. Therefore, the page includes an @ OutputCache directive that caches the output for 60 seconds at a time. Subsequent requests for the page come straight from the cache. When the cache expires and ASP.NET receives another request for the page, ASP.NET re-executes (and recaches) the page. The Duration attribute controls the length of time that the cached page output is valid.

In real life, Web pages are rarely this simple. The output from an ASPX file often varies based on input provided by users. The designers of ASP.NET anticipated this and gave the page cache the ability to hold multiple versions of a page, qualified by the user input that produced each version. Imagine, for example, that you wrote a Web form that takes a city name and state name as input and returns a satellite image of that city from a database. If the city and state names accompanying each request are transmitted in variables called city and state, the following directive caches a different version of the page for each city and state requested for up to one hour:

<%@ OutputCache Duration="3600" VaryByParam="city;state" %>

It's that simple. You can even use a shortened form of the VaryByParam attribute to cache a separate version of the page for every different input:

<%@ OutputCache Duration="3600" VaryByParam="*" %>

Now if two users request a satellite image of Knoxville, Tennessee, 30 minutes apart, the second of the two requests will be fulfilled very quickly.

A Web Forms Currency Converter

Figure 5 shows a Web form that performs currency conversions using exchange rates stored in an XML file. To see it in action, copy Converter.aspx and Rates.xml, which are listed in Listings 5 and 6, to \Inetpub\wwwroot and type http://localhost/converter.aspx in your browser's address bar. Then pick a currency, enter an amount in U.S. dollars, and click the Convert button to convert dollars to the currency of your choice.

Here are some points of interest regarding the source code:

  • Because it uses the DataSet class defined in the System.Data namespace, Converter.aspx begins with an @ Import directive importing System.Data.

  • Rather than show a hard-coded list of currency types in the list box, Converter.aspx reads them from Rates.xml. Page_Load reads the XML file and initializes the list box. To add new currency types to the application, simply add new <Rate> elements to Rates.xml. They'll automatically appear in the list box the next time the page is fetched.

  • For good measure, Converter.aspx wires the Convert button to the Click handler named OnConvert programmatically rather than declaratively. The wiring is done in Page_Init.

Notice how easily Converter.aspx reads XML from Rates.xml. It doesn't parse any XML; it simply calls ReadXml on a DataSet and provides an XML filename. ReadXml parses the file and initializes the DataSet with the file's contents. Each <Rate> element in the XML file becomes a row in the DataSet, and each row, in turn, contains fields named Currency and Exchange. Enumerating all the currency types is a simple matter of enumerating the DataSet's rows and reading each row's Currency field. Retrieving the exchange rate for a given currency is almost as easy. OnConvert uses DataTable.Select to query the DataSet for all rows matching the currency type. Then it reads the Exchange field from the row returned and converts it to a decimal value with Convert.ToDecimal.

One reason I decided to use a DataSet to read the XML file is that a simple change would enable the Web form to read currencies and exchange rates from a database. Were Converter.aspx to open the XML file and parse it using the FCL's XML classes, more substantial changes would be required to incorporate database input.

A word of caution regarding this Web form: Don't use it to perform real currency conversions! The exchange rates in Rates.xml were accurate when I wrote them, but they'll be outdated by the time you read this. Unless you devise an external mechanism for updating Rates.xml in real time, consider the output from Converter.aspx to be for educational purposes only.

Figure 5 Web form currency converter.

Listing 5: Converter.aspx: Currency Converter Source Code

<%@ Import Namespace=System.Data %>

<form>
 <body>
  <h1>Currency Converter</h1>
  <hr>
  <form runat="server">
   Target Currency<br>
   <asp:ListBox ID="Currencies" Width="256" RunAt="server" /><br>
   <br>
   Amount in U.S. Dollars<br>
   <asp:TextBox ID="USD" Width="256" RunAt="server" /><br>
   <br>
   <asp:Button Text="Convert" ID="ConvertButton" Width="256"
    RunAt="server" /><br>
   <br>
   <asp:Label ID="Output" RunAt="server" />
  </form>
 </body>
</form>

<script language="C#" runat="server">
 void Page_Init (Object sender, EventArgs e)
 {
   // Wire the Convert button to OnConvert
   ConvertButton.Click += new EventHandler (OnConvert);
 }

 void Page_Load (Object sender, EventArgs e)
 {
   // If this isn't a postback, initialize the ListBox
   if (!IsPostBack) {
     DataSet ds = new DataSet ();
     ds.ReadXml (Server.MapPath ("Rates.xml"));
     foreach (DataRow row in ds.Tables[0].Rows)
       Currencies.Items.Add (row["Currency"].ToString ());
     Currencies.SelectedIndex = 0;
   }
 }

 void OnConvert (Object sender, EventArgs e)
 {
   // Perform the conversion and display the results
   try {
     decimal dollars = Convert.ToDecimal (USD.Text);
     DataSet ds = new DataSet ();
     ds.ReadXml (Server.MapPath ("Rates.xml"));
     DataRow[] rows = ds.Tables[0].Select ("Currency = '" +
       Currencies.SelectedItem.Text + "'");
     decimal rate = Convert.ToDecimal (rows[0]["Exchange"]);
     decimal amount = dollars * rate;
     Output.Text = amount.ToString ("f2");
   }
   catch (FormatException) {
     Output.Text = "Error";
   }
 }
</script>

Listing 6: Rates.xml: XML File Used by Converter.aspx

<?xml version="1.0" encoding="UTF-8"?>
<Rates>
 <Rate>
  <Currency>British Pound</Currency>
  <Exchange>0.698544</Exchange>
 </Rate>
 <Rate>
  <Currency>Canadian Dollar</Currency>
  <Exchange>1.57315</Exchange>
 </Rate>
 <Rate>
  <Currency>French Franc</Currency>
  <Exchange>7.32593</Exchange>
 </Rate>
 <Rate>
  <Currency>German Mark</Currency>
  <Exchange>2.18433</Exchange>
 </Rate>
 <Rate>
  <Currency>Italian Lira</Currency>
  <Exchange>2162.67</Exchange>
 </Rate>
 <Rate>
  <Currency>Japanese Yen</Currency>
  <Exchange>122.742</Exchange>
 </Rate>
 <Rate>
  <Currency>Mexican Peso</Currency>
  <Exchange>9.22841</Exchange>
 </Rate>
 <Rate>
  <Currency>Swiss Franc</Currency>
  <Exchange>1.64716</Exchange>
 </Rate>
</Rates>

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