Tải bản đầy đủ (.pdf) (90 trang)

Beginning ASP.NET 1.1 with Visual C# .NET 2003 phần 9 pdf

Bạn đang xem bản rút gọn của tài liệu. Xem và tải ngay bản đầy đủ của tài liệu tại đây (2.33 MB, 90 trang )


string connectionString =
ConfigurationSettings.AppSettings["ConnectionString"];
System.Data.IDbConnection dbConnection =
new System.Data.OleDb.OleDbConnection(connectionString);
string queryString = "SELECT
[Players].[PlayerName],[Positions].[PositionName],[Teams].[TeamName]
FROM [Players], [Positions], [PlayerTeam], [Teams]
WHERE (([PlayerTeam].[PlayerID] = [Players].[PlayerID])
AND ([PlayerTeam].[Position] = [Positions].[PositionID])
AND ([PlayerTeam].[TeamID] = [Teams].[TeamID])
AND ([Players].[PlayerID] = @PlayerID))";
System.Data.IDbCommand dbCommand = new System.Data.OleDb.OleDbCommand();
dbCommand.CommandText = queryString;
dbCommand.Connection = dbConnection;
System.Data.IDataParameter dbParam_teamID =
new System.Data.OleDb.OleDbParameter();
dbParam_teamID.ParameterName = "@PlayerID";
dbParam_teamID.Value = playerID;
dbParam_teamID.DbType = System.Data.DbType.Int32;
dbCommand.Parameters.Add(dbParam_teamID);
dbConnection.Open();
System.Data.IDataReader dataReader =
dbCommand.ExecuteReader(System.Data.CommandBehavior.CloseConnection);
return dataReader;
}
The GetTeamsByPlayer() method is a very simple alteration of GetPlayersByTeam() from the Teams
page. The really tricky part on this page is that we need to obtain the ID of the player that the user
selects. In the
Team page, that was easy – we packaged up each team's ID as the CommandArgument for
the


LinkButton in the teams DataList. But a DataGrid won't let us do that, so we need to find
another solution. Remember the fields we set up on the players
DataGrid? At the left hand side there
was an invisible column that contained the player ID. This is how we get it:
TableCell cell = (TableCell)e.Item.Controls[0];
int SelectedPlayerID = int.Parse(cell.Text);
Chapter 11
This chapter deals with tracking users across pages and looks at the ASP.NET objects that are used to
enable this feature.
Exercise 1
Add some text, Current Topic, and a Label control to the Chat.aspx page above the main chat box,
which contains the text of the current topic (stored in the
Application object). Add some default topic
693
Exercise Solutions
text to the Global.asax file and also another box and button to the page, allowing you to change the
current topic.
Solution
You should start this exercise by adding the text and Label control to the top of the page. This is a
simple addition that you can do either in the
Design view, HTML view, or the All view.
❑ In
Design view, type some text directly below the sub-heading that says Current topic:.
❑ Drag a
Label control onto the page and set its ID to lblCurrentTopic.
Alternatively, enter the following code below the sub-heading:
<h2>Online Chat</h2>
Current topic: &nbsp;
<asp:Label id="lblCurrentTopic" runat="server">
</asp:Label>

<br />

In Global.asax, you need to enter code that will store the details of the default topic when the
application is first started:
public void Application_Start(Object sender, EventArgs e)
{
Application["ChatLog"] = "Hello, and welcome to the Wrox United Chat page!";
Application["CurrentTopic"] = "General free-for-all chat!";
}
Back in Chat.aspx, add the following line to the Page_Load event handler:
void Page_Load()
{
txtChatBox.Text = (string)Application["ChatLog"];
lblCurrentTopic.Text = (string)Application["CurrentTopic"];
}
You can run the page at this stage and the default topic, 'General free-for-all chat!', will be displayed at the
top of the page.
To make this exercise interactive, you need to add a couple of controls and another event handler. Below
the two buttons, you need to add another row to your table.
❑ In the first cell, enter some text to tell the user what to do (for example,
Enter a new topic).
❑ In the next cell, drag a
TextBox control into the cell and name it txtTopic.
❑ Add another row and in the first cell, enter a non-breaking space. In the second, add a button
control with its
ID set to btnUpdateTopic. Double-click this button to wire up an event handler
for the click event.
694
Appendix A
Alternatively, enter the following code:

<asp:Button id="btnPost" onclick="btnPost_Click" runat="server"
Text="Post message"></asp:Button>
<asp:Button id="btnClearLog" onclick="btnClearLog_Click" runat="server"
Text="Clear log"></asp:Button>
<hr />
</td>
</tr>
<tr>
<td width="150">
Enter a new topic:
</td>
<td>
<asp:TextBox id="txtTopic" runat="server" MaxLength="100" width="402px">
</asp:TextBox>
</td>
</tr>
<tr>
<td>
&nbsp;
</td>
<td>
<asp:Button id="btnUpdateTopic"
onclick="btnUpdateTopic_Click" runat="server" text="Update Topic">
</asp:Button>
</td>
</tr>
Finally, you need to add some code to update the contents of the Application object when the button is
clicked:
void btnUpdateTopic_Click(object sender, EventArgs e)
{

Application["CurrentTopic"] = txtTopic.Text;
lblCurrentTopic.Text = (string)Application["CurrentTopic"];
txtTopic.Text = "";
}
Exercise 2
Add the session initialization code from the stylesheet example to your Global.asax file.
Solution
You'll recall that, during the CSS example, the following code was included in the Page_Load() method
of
Default.aspx:
if (Session["SelectedCss"] == null)
{
if (Request.Cookies["PreferredCss"] == null)
{
695
Exercise Solutions
Session["SelectedCss"] = "WroxUnited.css";
}
else
{
Session["SelectedCss"] = Request.Cookies["PreferredCss"].Value;
}
}
This code can be shortened considerably by adding the following statement to the Global.asax file:
public void Session_Start(Object sender, EventArgs e)
{
System.Collections.Hashtable basketTable =
new System.Collections.Hashtable();
Session["Basket"] = basketTable;
Session["SelectedCss"] = "WroxUnited.css";

}
The code in Page_Load() method can now be changed to the following:
if (Request.Cookies["PreferredCss"] != null)
{
Session["SelectedCss"] = Request.Cookies["PreferredCss"].Value;
}
Exercise 3
Add a link to the Merchandise.aspx page from the front page of the site, and then apply the stylesheet
used in the
Default.aspx page to all the other pages in the site. You will need to add the <link >
tag to the <head > section of each page and you will need to ensure that the session initialization
code is correctly configured in the
Global.asax file from the previous exercise.
Solution
Adding the link to the Default.aspx page is quite simple – just add the following code to the list of
links:
<p>
<asp:HyperLink id="lnkMerchandise" runat="server"
NavigateUrl="Merchandise.aspx">
Merchandise
</asp:HyperLink>
</p>
Now you can add the css link to each of the other pages in the site:
<head>
<link id="css" href='<%= (string)Session["SelectedCss"] %>'
type="text/css" rel="stylesheet" />
</head>
696
Appendix A
Having said this, it's not always quite as simple as it looks – take a look at the output of Teams.aspx

when using the Away scheme and you'll notice that the red links remain red, because the color was hard-
coded when the page was created. You need to remove the color information from the tag:
<asp:linkbutton
text='<%# DataBinder.Eval(Container.DataItem, "TeamName") %>'
CommandArgument='<%# DataBinder.Eval(Container.DataItem, "TeamID") %>'
id="TeamNameLink"
style="color:darkred"
runat="server"
CommandName="ShowTeam" />
Once you delete the style="color.darkred" attribute, the links will inherit the styling defined for all
hyperlinks.
Players.aspx has some additional styling that will need to be amended. The font color and header bar
are blue and since the theme for the site is red, white, and black, these colors need altering. First, delete
all the hard-coded styles from the control – you may find that the
Properties pane is the most useful tool
for this.
Next, you can add some custom styling. Here is some CSS code you can add to
WroxUnited.css:
.datatablebody {
background-color:"#ffffff";
color:black;
font-size:smaller;
}
.datatablebody td{
padding:3;
}
.datatablehead {
background-color:"#c0c0c0";
color:black;
font-weight:bold;

}
.datatablehead td{
padding:3;
}
Once these styles are added, you can apply them to the control:
<ItemStyle cssclass="datatablebody"></ItemStyle>
<HeaderStyle font-bold="True" cssclass="datatablehead"></HeaderStyle>
Chapter 12
This chapter covers the concepts of user controls and code-behind. The first three exercises for this
chapter don't really have any new type code to them; it's only practicing adding user controls to pages
697
Exercise Solutions
and switching to using code-behind. The completed code for these pages is available for download from
the Wrox website.
Exercise 1
Add the header control and navigation bar control to each page in the site. Remember to add the
following code at the top of each page:
<%@ Register TagPrefix="WroxUnited" TagName="Header" Src="Header.ascx" %>
<%@ Register TagPrefix="WroxUnited" TagName="NavBar" Src="NavBar.ascx" %>
Solution
Refer 57084_Ch12_Ans01.aspx for the code for this question.
Exercise 2
Move the C# code for each page (visible in the Code view in Web Matrix) into an associated code-behind
file, making sure each control has a corresponding declaration in the code-behind file.
Solution
See 57084_Ch12_Ans02.aspx for the solution.
Exercise 3
Move the C# code from the navbar.ascx control (containing an event-handler) into an associated .cs
code-behind file, following the same technique as you used for the other pages on the site.
Exercise 4

Create a user control for the Merchandise.aspx page that enables you to easily add new items to the
list. You will need to copy a row of the table from
Merchandise.aspx into a new ASCX user control file.
Make the properties on the image and button controls generic and add some public properties to
programmatically set the values on each Web control in the user control.
Firstly, here's some code (currently in
Merchandise.aspx) that could be placed in the control:
<tr>
<td>
<asp:Image id="imgCap" runat="server" Height="100px"
ImageUrl="images/shirt.gif" Width="100px"></asp:Image>
</td>
<td>
The Wrox United shirt, available in one size only</td>
<td>
<asp:Button id="btnBuyShirt" onclick="AddItemToBasket" runat="server"
Width="100px" CommandArgument="Shirt" Text="Buy a shirt!"></asp:Button>
698
Appendix A
</td>
</tr>
If you change the ImageUrl of the image, the Text of the button, and the CommandArgument to empty
strings
"", then you can set those in the Page_Load() event. Consider the earlier example – the word
"Shirt" features in all three of these attributes, so you could add a property like the following to store
the name of the item (in this case, shirt), then use this value to construct the appropriate values for these
attributes:
private string _itemName = "";
public string ItemName
{

get{ return _itemName; }
set{ _itemName = value; }
}
Here's an example of using this property to update another private variable. This could be used, for
example, to provide a default image name:
:
if (_imageName == "")
{
_imageName = _itemName + ".jpg";
}
You would also need to move the AddItemToBasket() function to the control because the buttons now
reside within this control. Since the name of the session is globally available, it's possible to set or update
session values from the control just as easily as from a page.
You will need three properties in all. The first,
ItemName is shown above. You can include an optional
ImageName property to override the default value (in case you want to use a .gif, for example). Finally,
you need to store the text that describes the item in a
Text property and include the value stored in this
property in the page using the following syntax:
<td><%=Text%></td>
All that remains then is to add the item to the page:
<WroxUnited:Product id="Shirt" runat="server"
ItemName="Shirt"
ImageName="shirt.gif"
Text="The Wrox United shirt, available in one size only"/>
Solution
Firstly, the HTML of the Product.ascx user control:
<tr>
<td>
699

Exercise Solutions
<asp:Image id="image1" Width="120px" ImageUrl="<%=imageLink%>"
Height="120px" runat="server"></asp:Image>
</td>
<td>
<%=Text%></td>
<td>
<asp:Button id="button1" onclick="AddItemToBasket" Width="100px"
runat="server"
Text="<%=buttonText%>"
CommandArgument="<%=ItemName%>"></asp:Button>
</td>
</tr>
Next, the code for the Product.ascx user control:
using System;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.Caching;
using System.Collections;
using System.Configuration;
namespace WroxUnited
{
public class Product : UserControl
{
public Image image1;
public Button button1;
private string _itemName = "";
public string ItemName
{

get{ return _itemName; }
set{ _itemName = value; }
}
private string _imageName = "";
public string ImageName
{
get { return _imageName; }
set { _imageName = value; }
}
private string _text = "";
public string Text
{
get { return _text; }
set { _text = value; }
}
public void Page_Load()
{
700
Appendix A
if (_imageName == "")
{
_imageName = _itemName + ".jpg";
}
string imageLink = "images/" + _imageName;
string buttonText = "Buy the " + _itemName + "!";
image1.ImageUrl = imageLink;
button1.Text = buttonText;
}
public void AddItemToBasket(object sender, EventArgs e)
{

System.Collections.Hashtable basketTable = (Hashtable)Session["Basket"];
if (basketTable[_itemName] == null)
{
basketTable[_itemName] = 0;
}
int itemCount = (int)basketTable[_itemName];
basketTable[_itemName] = itemCount + 1;
}
}
}
In Merchandise.aspx add the following:
<%@ Register TagPrefix="WroxUnited" TagName="Product" Src="Product.ascx" %>

<table width="600">
<WroxUnited:Product id="Shirt" runat="server"
ItemName="Shirt"
ImageName="shirt.gif"
Text="The Wrox United shirt, available in one size only"/>
<WroxUnited:Product id="Hat" runat="Server"
ItemName="Hat"
ImageName="hat.jpg"
Text="The official Wrox United hat!"/>
<WroxUnited:Product id="Mascot" runat="Server"
ItemName="Mascot"
ImageName="mascot1.jpg"
Text="The Wrox United cuddly mascot - a must-have for the younger
supporters!"/>
<WroxUnited:Product id="Plate" runat="server"
ItemName="Plate"
ImageName="team_s_b.gif"

Text="This is a strange square collector's plate of the team!"/>
</table>
701
Exercise Solutions
Exercise 5
Move the new code in Product.ascx into a code-behind file.
Chapter 13
This chapter covered how to compile a .NET assembly and use it from within our ASP.NET page. It also
discussed the encapsulation of business logic into a reusable component.
Exercise 1
Build a data access component that connects to the Travel.mdb access database and retrieves data
about the weather at that location (filtered by location). You may find the following SQL useful:
SELECT [Locations].[LocationName], [Locations].[CurrentTemperature],
[WeatherTypes].[WeatherType]
FROM [Locations], [WeatherTypes]
WHERE (([WeatherTypes].[WeatherTypeID] = [Locations].[CurrentWeather])
AND ([Locations].[LocationName] = @LocationName))
If you use the Web Matrix SELECT Data Wizard, you can create a method called GetWeatherByCity()
that takes the LocationName as a parameter, and returns a DataReader.
Exercise 2
Add another method called GetCities() to this data access component, which selects all the
LocationNames from the database and returns a DataReader.
Solution (1 and 2)
Once you have created the two methods using the data wizards in Web Matrix, all that remains is to
ensure that everything is in place for compilation. Note that we've used the
BegASPNET namespace and
a Class named
TravelData – these will come handy for the rest of the exercise solutions. The following
code is available in the file called
DataAccessCode.cs in the code download.

// DataAccessCode.cs
//
using System;
namespace BegASPNET
{
public class TravelData
{
public TravelData()
{
}
public System.Data.IDataReader GetWeatherByCity(string locationName)
702
Appendix A
{
string connectionString =
"Provider=Microsoft.Jet.OLEDB.4.0; Ole DB Services=-4;
Data Source=C:\\BegASPNET11\\Chapter13Code\\Exercises\\travel.mdb";
System.Data.IDbConnection dbConnection =
new System.Data.OleDb.OleDbConnection(connectionString);
string queryString =
"SELECT [Locations].[LocationName], [Locations].[CurrentTemperature],"+
"[WeatherTypes].[WeatherType] "+
"FROM [Locations], [WeatherTypes] "+
"WHERE (([WeatherTypes].[WeatherTypeID] = " +
"[Locations].[CurrentWeather])" +
"AND ([Locations].[LocationName] = @LocationName))";
System.Data.IDbCommand dbCommand = new System.Data.OleDb.OleDbCommand();
dbCommand.CommandText = queryString;
dbCommand.Connection = dbConnection;
System.Data.IDataParameter dbParam_locationName =

new System.Data.OleDb.OleDbParameter();
dbParam_locationName.ParameterName = "@LocationName";
dbParam_locationName.Value = locationName;
dbParam_locationName.DbType = System.Data.DbType.String;
dbCommand.Parameters.Add(dbParam_locationName);
dbConnection.Open();
System.Data.IDataReader dataReader =
dbCommand.ExecuteReader(System.Data.CommandBehavior.CloseConnection);
return dataReader;
}
public System.Data.IDataReader GetCities() {
string connectionString =
"Provider=Microsoft.Jet.OLEDB.4.0; Ole DB Services=-4;
Data Source=C:\\BegASPNET11\\Chapter13Code\\Exercises\\travel.mdb";
System.Data.IDbConnection dbConnection =
new System.Data.OleDb.OleDbConnection(connectionString);
string queryString = "SELECT [Locations].[LocationName] FROM " +
"[Locations]";
System.Data.IDbCommand dbCommand = new System.Data.OleDb.OleDbCommand();
dbCommand.CommandText = queryString;
dbCommand.Connection = dbConnection;
dbConnection.Open();
System.Data.IDataReader dataReader =
dbCommand.ExecuteReader(System.Data.CommandBehavior.CloseConnection);
return dataReader;
}
}
}
703
Exercise Solutions

We'll see how to compile this file along with the two server controls once after we have seen the
solutions for the next two exercises.
Exercise 3
Create a simple custom control that has a temperature property, which takes the temperature in Celcius
and renders a string of text that displays the temperature in both Celcius and Fahrenheit:
Fahrenheit temperature = Celsius temperature * (9/5) + 32
The control should render a <span> tag that has a style=color:<color> attribute that can be used to
change the color of the text for different temperature ranges. If the temperature is below 0 degrees
Celcius, you should make the text blue, above 30 degrees it should be red, and all others should be
orange.
Solution
The code for this control isn't too different from the code we used in the chapter. In the following code,
you'll see that there are two properties in this control, one for Celcius and one to convert that value into
Fahrenheit. The
Render() method then creates a <span > control when the control is rendered.
Notice that we've used a string formatter to render the control exactly as we intended (adding a degrees
symbol after each temperature value. This file is called
57084_Ch13_Ans03.cs in the code download:
using System;
using System.Web;
using System.Web.UI;
namespace BegASPNET
{
public class TemperatureControl : Control
{
private double _tempInCelcius;
public double TempInCelcius
{
get{return _tempInCelcius;}
set{_tempInCelcius = value;}

}
public double TempInFahrenheit
{
get {return _tempInCelcius * (9.0 / 5.0) + 32.0;}
set {_tempInCelcius = (value - 32.0) * (5.0 / 9.0);}
}
protected override void Render(System.Web.UI.HtmlTextWriter writer)
{
string color;
if (_tempInCelcius <= 0.0)
{
704
Appendix A
color = "blue";
}
else if (_tempInCelcius >= 30.0)
{
color = "red";
}
else
{
color = "orange";
}
writer.Write("<span style='color:");
writer.Write(color);
writer.Write("'>");
writer.Write("{0:##0.#}&deg;C ({1:##0.#}&deg;F)", TempInCelcius,
TempInFahrenheit);
writer.Write("</span>");
}

}
}
Exercise 4
Create another control that takes the code built in the first two examples to produce a composite control
that displays temperature data stored in the database for a specific city. Your control should render the
following output:
❑ The name of the city
❑ The temperature at the specified city (use an instance of the control created in the previous
example)
❑ An image control
<ASP:Image > that displays one of a series of images (available in the
code download for this chapter) that represents the style of weather currently being experienced
at the specified city – for example, an image of a cloud if the weather is overcast
Solution
This control only has one property, the name of the city to display. The tricky bit is to get it to render the
output we're after. In the following code, you'll see that the output will be rendered in an HTML table.
Also, notice also that it's very simple to nest the first control within this control. This file is called
57084_Ch13_Ans04.cs in the code download:
using System;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.HtmlControls;
using System.Data;
namespace BegASPNET
{
705
Exercise Solutions
public class CityWeatherControl : Control
{

private Label _cityNameLabel = new Label();
private TemperatureControl _temperatureControl = new TemperatureControl();
private Image _weatherImage = new Image();
private TravelData _travelData = new TravelData();
private string _city;
public string City
{
get{return _city;}
set{_city = value;}
}
protected override void CreateChildControls()
{
Controls.Clear();
IDataReader cityData = _travelData.GetWeatherByCity(City);
try
{
if (cityData.Read())
{
double currentTemperature = (int)(cityData["CurrentTemperature"]);
string weatherType = (string)(cityData["WeatherType"]);
_cityNameLabel.Text = City;
_temperatureControl.TempInCelcius = currentTemperature;
_weatherImage.AlternateText = weatherType;
_weatherImage.ImageUrl = weatherType + ".gif";
Table layoutTable = new Table();
TableRow topRow = new TableRow();
TableRow bottomRow = new TableRow();
TableCell cell1 = new TableCell();
cell1.Controls.Add(_cityNameLabel);
TableCell cell2 = new TableCell();

cell2.Controls.Add(_weatherImage);
cell2.RowSpan = 2;
topRow.Cells.Add(cell1);
topRow.Cells.Add(cell2);
TableCell cell3 = new TableCell();
cell3.Controls.Add(_temperatureControl);
bottomRow.Cells.Add(cell3);
layoutTable.Rows.Add(topRow);
706
Appendix A
layoutTable.Rows.Add(bottomRow);
Controls.Add(layoutTable);
}
else
{
Literal errorLiteral = new Literal();
errorLiteral.Text = "No data available for city " + City;
Controls.Add(errorLiteral);
}
}
finally
{
cityData.Close();
cityData.Dispose();
}
ChildControlsCreated = true;
}
}
}
These three components now need to be compiled. In the download for these solutions, you'll find that

there's a file called
Compile.bat that contains the following code:
CD C:\BegASPNET11\Chapter13Code\Exercises
md bin
csc /t:library /r:System.dll,System.Data.dll,System.Web.dll
/out:bin/TravelSite.dll DataAccessCode.cs TemperatureControl.cs
CityWeatherControl.cs
pause
This code will compile all three components into an assembly called TravelSite.dll. They are all
based in the same namespace, so this is a fairly logical thing to do in real life applications.
Exercise 5
Finally, add the following to an ASP.NET page:
❑ Add a drop-down
ListBox and bind it to the DataReader returned by the GetCities()
method in the data access component. Enable auto-postback for this control so that a postback
occurs whenever the selection changes.
❑ Add a copy of the weather control created in the previous exercise to the page, and pass the
name of the currently selected city to the control for displaying the weather for that city.
Solution
All that remains is to add the CityWeatherControl to a web page. In this page, we've used a drop
down
ListBox for selecting a city, which automatically posts back to the server to refresh the page. This
page is called
travel.aspx:
707
Exercise Solutions
<%@ Page Language="C#" %>
<%@ Register TagPrefix="TravelControl" Namespace="BegASPNET"
Assembly="TravelSite" %>
<%@ import Namespace="BegASPNET" %>

<script runat="server">
void Page_Load()
{
if (!Page.IsPostBack)
{
TravelData data = new TravelData();
System.Data.IDataReader reader = data.GetCities();
ddlLocations.DataSource = reader;
ddlLocations.DataValueField = "LocationName";
ddlLocations.DataTextField = "LocationName";
ddlLocations.DataBind();
}
CityWeather.City = ddlLocations.SelectedItem.ToString();
}
</script>
<html>
<head>
</head>
<body>
<form runat="server">
<asp:DropDownList id="ddlLocations" runat="server" AutoPostBack="True">
</asp:DropDownList>
<br />
<TRAVELCONTROL:CITYWEATHERCONTROL id="CityWeather" runat="server" />
</form>
</body>
</html>
As long as you have the images in the same directory as the ASPX page, you should be able to see the
results of your efforts.
Chapter 14

This chapter explains the steps you can take to debug your code, minimize errors, handling errors as
well as how to recover when things go wrong.
Exercise 1
How are parser errors different from compilation errors? Is there any difference between the ways they
are displayed by ASP.NET?
708
Appendix A
Solution
When a page has errors that are caught during compilation by a .NET Framework compiler (remember
that ASP.NET pages are compiled), ASP.NET generates a syntax error report with information about the
error and sends this information to the browser. When an error occurs while a page is being executed, it
gives rise to a parser error. The difference is that ASP.NET sends a Stack Trace to the browser; it that
contains information about what was going on when the error occurred.
Exercise 2
Here are three sections of code – what is wrong with each section and what type of error does it contain?
How would you fix it?
❑ Section A:
<html>
<head>
<title>Syntax Error Example </title>
</head>
<body>
<form method="post" action="syntaxerror.aspx" runat="server">
<asp:TextBox id="txtQuantity" runat="Server />
</form>
</body>
</html>
❑ Section B:
void Page_Load()
{

int intCounter, intLoop;
intCounter=0;
intLoop=0;
while (intCounter<10)
{
intLoop = intLoop +1;
}
}
❑ Section C:
<script language="C#" runat="server">
void Page_Load()
{
string a;
int b;
string c;
a = "Hello";
b = "World";
c = a + b;
}
</script>
709
Exercise Solutions
Solution
The sections, the errors they would generate, and a possible solution have been provided as follows:
❑ In section A, see the following line:
<asp:TextBox id="txtQuantity" runat="Server />
It is missing a closing quotation mark after Server.
❑ Section B is an infinite loop. We check the contents of
intCounter to see if it has reached 10,
but increment the variable called

intLoop:
while (intCounter<10)
{
intLoop = intLoop +1;
}
To correct this, change intLoop to intCounter (or vice versa).
❑ In section C,
b is declared as an integer, yet a string value is read into it:
int b;

b = "World";
b
should be declared as a string.
Exercise 3
Create a form with four textboxes and a submit button. Each of the textboxes accepts a user name, an
email address, a phone number, and the user's gender. Use validation controls to make sure that there
are no blank entries, that you can only enter numbers into the phone field, and that you can only enter a
number between 1 and 140 in the age field. Also, but not necessarily with validation controls, make sure
that the gender textbox only accepts male or female and that the email address contains the '
@' character.
In what ways could this form be improved further?
Solution
The code should read as follows (available in the code download as 57084_Ch14_Ans03.aspx:
<form method="post" action="usingvalidationcontrol.aspx" runat="server">
<asp:Label text="Name" runat="server" />
<asp:TextBox id="txtUserName" runat="server" />
<asp:RequiredFieldValidator ControlToValidate="txtUserName" runat="server"
ErrorMessage="Please enter a value in the Name Field">
</asp:RequiredFieldValidator>
<asp:Label text="Email" runat="server" />

<asp:TextBox id="txtEmail" runat="server" />
<asp:RequiredFieldValidator ControlToValidate="txtEmail" runat="server"
710
Appendix A
ErrorMessage="Please enter a value in the Email Field">
</asp:RequiredFieldValidator>
<asp:RegularExpressionValidator ControlToValidate="txtEmail"
ValidationExpression="^\w+[\w-\.]*\@"
ErrorMessage="This isn't a valid email address!"
runat="server" />
<asp:Label text="Age" runat="server" />
<asp:TextBox id="txtPhone" runat="server" />
<asp:RequiredFieldValidator ControlToValidate="txtPhone" runat="server"
ErrorMessage="Please enter a value in the Phone Field">
</asp:RequiredFieldValidator>
<asp:CompareValidator id="numbervalidatior"
ControlToValidate="txtPhone"
Type="Integer"
Operator="DataTypeCheck"
ErrorMessage="You must enter a number!"
runat="server" />
<asp:Label text="Age" runat="server" />
<asp:TextBox id="txtAge" runat="server" />
<asp:RequiredFieldValidator ControlToValidate="txtAge" runat="server"
ErrorMessage="Please enter a value in the Age Field">
</asp:RequiredFieldValidator>
<asp:RangeValidator id="Range1"
ControlToValidate="txtAge"
MinimumValue="1"
MaximumValue="140"

Type="Integer"
EnableClientScript="false"
Text="The value must be between 1 and 140!"
runat="server"/>
<br />
<asp:Button id="btnComplete_Order" Text="Submit Form"
onclick="Submit Form" runat="server"/><br>
<asp:Label id="lblOrderConfirm" runat="server"/>
</form>
There are many ways that this could be improved; here are a few:
❑ The email address could be checked to see that it took a format
, or you could
even check to see if it was a valid email. There are plenty of pre-written regular expressions for
email validation. You can download some from
/>❑ You could use an authentication tool such as Passport to check these details and not worry about
the user having to input them! You should be aware that there isn't a set of hard and fast rules
when creating forms, just that some ways of doing things will be more sensible than others.
Exercise 4
Write a try…catch error handler that will handle errors specifically for a divide-by-zero handler (as we
did for invalid casts).
711
Exercise Solutions
Hint: We haven't mentioned the specific class involved, you can find a list of classes using the class
browser.
Solution
There are many ways of doing this, as long as you include a DivideByZeroException. Here is a
suggested method, complete with an example divide-by-zero error (available in the code download as
57084_Ch14_Ans04.aspx:
<script language="C#" runat="server" >
void StructuredErrorHandling()

{
try
{
int a;
int b
int c;
a=1;
b=0;
c=a/b;
}
//Handler for DivideByZero Exception
catch (DivideByZeroException excep)
{
Response.Write ("Error Occurred"+ "<br>" + excep.ToString + "<br>");
}
finally
{
Response.Write ("The Page Execution is completed" & "<br>")
}
}
}
</script>
Exercise 5
Create a custom error page for an HTTP 403 error Access is forbidden error and get it working for this
chapter's code folder.
Solution
The following section should go in web.config in the ch14 folder:
<configuration>
<system.web>
<customErrors defaultRedirect="userError.aspx" mode="On">

<error statusCode="403" redirect="PageForbidden.aspx" />
</customErrors>
</system.web>
</configuration>
The page Forbidden.aspx can just say something like:
712
Appendix A
<html>
<head>
</head>
<body>
<h1> You are not allowed access to this page.</h1>
</body>
</html>
Chapter 15
This chapter explains how ASP.NET applications can be managed from a series of XML configuration
files.
Exercise 1
If you didn't know how to specify a particular setting of an element in the config file, where would you
look to find them?
Solution
In the machine.config file itself, which has examples of how to use many of the commonly used
settings.
Example 2
Create a friendly custom error page for a file not found error and set the relevant config file so that it
appears whenever a 404 error message is generated.
Solution
The following section should go in web.config in the ch14 folder:
<configuration>
<system.web>

<customErrors defaultRedirect="userError.aspx" mode="On">
<error statusCode="404" redirect="PageNotFound.aspx" />
</customErrors>
</system.web>
</configuration>
The page PageNotFound.aspx can just say something like:
<html>
<head>
</head>
<body>
<h1> Sorry but this page cannot be found on our web server.</h1>
</body>
</html>
713
Exercise Solutions
Example 3
Create a page with two Label controls that both display the time, and create an output cache that lasts
for 30 minutes and caches just one of the controls.
Solution
When using fragment caching, you cache only in the ASCX file; so create an ASPX page that isn't cached
containing two user controls:
<%@ Page Language="C#" %>
<%@ Register TagPrefix="l1" TagName="mylabel1" Src="label1.ascx" %>
<%@ Register TagPrefix="l2" TagName="mylabel2" Src="label2.ascx" %>
<script runat = "server">
string ServerTime()
{
return ServerTime = System.DateTime.Now.ToLongTimeString();
}
</script>

<l1:mylabel1 text="ServerTime()" runat="server"/>
<l2:mylabel1 text="ServerTime()" runat="server"/>
Then create two ASCX files, and cache only one of them. Consider Label1.ascx:
<%@ OutputCache Duration="1800" VaryByParam="none" %>
<asp:label id="mylabel1" text="ServerTime()" runat="server"/>
Label2.ascx
:
<asp:label id="mylabel2" text="ServerTime()" runat="server"/>
Exercise 4
Create a cache that stores the following information "MyFavouriteColour = Orange", and expires it if
it hasn't been updated for three minutes.
Solution
The following lines of code serves this purpose:
Cache.Insert("MyFavoriteColor", "orange", null, DateTime.Now.AddMinutes(3),
NoSlidingExpiration);
Exercise 5
Create a cache that will expire whenever the contents of one of three files – XMLDoc1.xml,
XMLDoc2.xml, and XMLDoc3.xml – change. They all contain the following code:
<?xml version="1.0"?>
<address>
<name>Rheingold Cabriole</name>
<address>673 Chellingworth Place, Morningtown </address>
714
Appendix A
<phone>333-444-555</phone>
<email> </email>
</address>
Solution
DataSet XMLFileDataSet = New DataSet();
XMLFileDataSet.ReadXML("C:\\BegASPNet11\\ch15\\address.xml");

CacheDependency filedependency1 = New
CacheDependency("C:\\BegASPNet11\\ch15\\xmldoc1.xml");
CacheDependency filedependency2 = New
CacheDependency("C:\\BegASPNet11\\ch15\\xmldoc2.xml");
CacheDependency filedependency3 = New
CacheDependency("C:\\BegASPNet11\\ch15\\xmldoc3.xml");
Cache.Insert("address",XMLFileDataSet, filedependency1);
Cache.Insert("address",XMLFileDataSet, filedependency2);
Cache.Insert("address",XMLFileDataSet, filedependency3);
Chapter 16
This chapter teaches you how to expose functionality from your Web site to others as a Web service.
Exercise 1
Explain the role of the Simple Object Access Protocol (SOAP) in Web services.
Solution
SOAP is the protocol with which functions are called remotely in Web services.
Exercise 2
What is the purpose of the WSDL file?
Solution
The WSDL file is an XML file that specifies the parameters that are used in the Web services. With this
file, consumers know what parameters to send to the Web service and the values they will receive.
Exercise 3
How would you locate a Web service that provides the functions you require?
Solution
To locate a Web service, you can use the UDDI service. Businesses register their Web services on the
UDDI database, which can then be searched for a service that suits your needs.
715
Exercise Solutions
Exercise 4
Create a Web service with a class name of circles that calculates the area and circumference of a circle
and the volume of a sphere.

*
Area = (Pi)r2
* Circumference = 2(Pi)r
* Volume of a sphere = 4/3(Pi)r3.
Solution
See 57084_Ch16_Ans04.asmx available in the code download:
<%@ WebService Language="C#" Class="Circles"%>
using System.Web.Services;
public class Circles
{
[WebMethod] _
public decimal Areaofcircle(Decimal radius)
{
return radius*radius*3.142;
}
[WebMethod] _
public decimal CircumferenceofCircle(Decimal radius)
{
return 2 * 3.142 * radius;
}
[WebMethod] _
public decimal VolumeofSphere(Decimal radius)
{
return (4 / 3) * 3.142 * radius * radius * radius;
}
}
We create a WebMethod to calculate each of these values. Each method takes one parameter –the circle
radius – and returns one value. They are all encapsulated within the
public class Circles.
Exercise 5

Create a Web service that connects to the Northwind database and returns employees' addresses based
on their last names.
Solution
See 57084_Ch16_Ans05.aspx:
<%@ WebService Language="C#" Class="Addresses" %>
using System.Web.Services;
716
Appendix A

×