Structure of Flights Table Name Data Type Length AllowNull Description aircraft_type varchar 50 Yes Type of the air craft... Structure of Travel_Class Table Name Data Type Length AllowNu
Trang 2Building an Air line Reser vation System Using ASP.NET 2.0
and SQL Ser ver 2005
So far in this book, you have learned about XML DOM, XML support in ADO.NET, XSLT features
in NET, XML data display, and XML support in SQL Server 2005 This chapter focuses on rating these features in a real-world Web site This case study not only discusses the application
incorpo-of these features in a Web site but also demonstrates the best practices incorpo-of using these features.Toward this end, this chapter discusses and showcases the following features:
❑ How to design and develop an N-tier Web site using the XML features of ASP.NET 2.0and SQL Server 2005 To support this design, this chapter discusses how to encapsulatethe data access logic in the form of reusable components
❑ How to work with an XML data type column by persisting data in it using ADO.NET
❑ How to utilize the XSD schemas support provided by SQL Server 2005 to validateXML data
❑ How to transform the XML data into HTML using the XSLT features of NET 2.0
❑ How to display the XML data using an XmlDataSourcecontrol with a GridViewcontrol
❑ How to read and write XML data using XmlReaderand XmlWriterclasses
❑ How to validate XML data using XSD schemas
Trang 3Over view of the Case Study
For this case study, consider an airline reservations system This airline system provides the basic tures of an online reservation system Some of the features include searching for flights based on specificsearch criteria and booking tickets for a particular flight It also provides for the users to have member-ship in the site by registering themselves with the site
fea-Architecture of System
Figure 11-1 illustrates the proposed architecture of the online reservation system
Figure 11-1
As shown in Figure 11-1, the Web site primarily depends on the middle tier NET component
(AirlineReservationsLib) for all of its functionalities When the user comes to the site and performs ations such as searching for flights, the Web site invokes the methods of the NET component to carryout those tasks Before looking at the implementation of the architecture, it is important to examine thebusiness processes supported by the ShoppingAssistant
Data AccessLayerInternet
SQL Server2005Database
Trang 4choosing the best approach The business processes that the online reservation system is going to have toenable are as follows:
❑ Login process — The login system allows the users to identify themselves to the system Theuser must provide a valid user id and a valid password to be able to log onto the system Afterlogged in, the user can carry out tasks such as searching for flights and booking tickets
❑ New user registration process — If you are a new user, you have the opportunity to become amember of the site by filling out the online forms and selecting the desired preferences In thisstep, the user is asked to create a unique user id, which is used to identify the user in the sys-tem The user is also required to choose a password of his choice to protect their membershipand prevent someone else from using their account And the user also can fill out relevantdetails like name, address, and so on After the user enters all the details, the user’s profile isstored in the database for later retrieval
❑ Search flights process — As the name suggests, this process allows the user to search for flights
❑ Book tickets process — In this process, the user can book the tickets for a specified flight
❑ Logout process — Allows the user to log out of the site, thereby terminating the session
Limitations
This case study is not aimed at demonstrating how to build and deploy a real-world online reservationsystem The intended purpose is to show how to tie different XML features of ASP.NET together For thatreason, many issues are not addressed in this example, including:
❑ Security — No regard is taken to security in the implementation of the Web services in thisexample
❑ Payment — Obviously in this example no real bookings are made and none of the issues cerned with payment are handled
con-ImplementationNow that you have understood the business processes involved, examine the individual building blocksthat are required for implementing this solution For the purposes of this example, the discussion of theremaining part of the case study will be split into the following sections
❑ Database design
❑ Implementation of NET component (AirlineReservationsLib)
❑ Implementation of Web site
To start with, consider the database design that is required to support the Web site
Database Design
The database, called AirlineReservation, used in this case study has minimum number of tables required
to implement this solution The AirlineReservation database consists of six tables The entity relationshipdiagram for the database is as follows:
Trang 5Figure 11-2
The structure of these tables is shown in Table 11-1, starting with Flights table
Table 11-1 Structure of Flights Table
Name Data Type Length AllowNull Description
aircraft_type varchar 50 Yes Type of the air craft
Trang 6The Travel_Class table is defined in Table 11-2.
Table 11-2 Structure of Travel_Class Table
Name Data Type Length AllowNull Description
travel_class_id int 4 No Represents the travel class idtravel_class_code char 1 No Represents the different travel class
codestravel_class_ varchar 50 No Provides a description of the travel
The stored procedure named SearchFlightis used to search for flights based on the following ters: starting location, destination, arrival date, departure date, and the type of travel class
parame-CREATE Procedure dbo.SearchFlight
@startingFrom varchar(50), @destination varchar(50),
@arrivalDate datetime, @departureDate datetime,
@travelClassID intAs
Beginset nocount on select F.*,TC.travel_class_id from flights F inner join travel_class_seat_capacity TCSC
on TCSC.flight_id = F.flight_id inner join travel_class TC
on TC.travel_class_id = TCSC.travel_class_idwhere F.starting_from = @startingFrom and F.destination = @destinationand F.arrival_date = @arrivalDate and F.departure_date = @departureDateand TC.travel_class_id = @travelClassID and TCSC.number_of_seats > 0End
Table 11-3 describes the structure of the Travel_Class_Capacity table
Table 11-3 Structure of Travel_Class_Capacity Table
Name Data Type Length AllowNull Description
travel_class_id int 4 No Represents the travel class idnumber_of_seats Int 4 No Number of seats available in a
particular flightThe Bookings table is defined as follows in Table 11-4
Trang 7Table 11-4 Structure of Bookings Table
Name Data Type Length AllowNull Description
passenger_id int 4 No Specifies the passenger id
travel_class_id int 4 No Specifies the travel class id
date_booking_made datetime 8 No Specifies the date of booking
To create a new booking in the bookings table, a stored procedure named InsertBookingis utilized.CREATE procedure dbo.InsertBooking
@flightID int, @passengerID varchar(20),
@travelClassID int, @bookingID int output
The definition of Stocks table is shown in Table 11-5
Table 11-5 Structure of Stocks Table
Name Data Type Length AllowNull Description
price Varchar 10 No Represents the stock price
The stored procedure GetStockQuoteretrieves the stock quote based on the supplied symbol Create procedure GetStockQuote
Trang 8Table 11-6 Structure of Users Table
Name Data Type Length AllowNull Description
UserID varchar 20 No Represents the User IDPassword varchar 10 No Represents the password assigned to a userName varchar 128 No Represents the name of the logged on userAddress varchar 128 Yes Represents the address of the userPhone xml N/A Yes Typed XML column that represents the phone
numbers XML format
As you can see from Table 11-6, the Phone column is a typed column that has an XML schema associatedwith it The DDL for creating the schema used by this column is as follows:
CREATE XML Schema collection PhoneSchema as N’<xs:schema attributeFormDefault=”unqualified”
elementFormDefault=”qualified” xmlns:xs=”http://www.w3.org/2001/XMLSchema”>
<xs:element name=”phone”>
<xs:complexType>
<xs:sequence>
<xs:element name=”homePhone” type=”xs:string” />
<xs:element name=”cellPhone” type=”xs:string” />
<xs:element name=”officePhone” type=”xs:string” />
Alter table Users Alter Column Phone XML(PhoneSchema)
To insert rows into the Users table, the InsertUserstored procedure is utilized
CREATE Procedure InsertUser(@UserID char(20), @Password char(10), @Name varchar(128),
@Address varchar(128), @Phone xml, @City varchar(50),
@State char(2), @Zip char(5))As
BeginInsert into Users(UserID,Password,Name,Address,Phone, City,State,Zip)Values(@UserID,@Password,@Name,@Address,@Phone,@City,@State,@Zip)End
Trang 9In addition to storing the user details, you also need a way to be able to verify the credentials of a userthat is trying to log onto the site To this end, the CheckUserLoginis used.
CREATE Procedure CheckUserLogin
SELECT @RetValue = 1End
Now that you have implemented the stored procedures, the next step is to implement the middle tiercomponent that will consume the stored procedures
Implementation of AirlineReservationsLib Component
In this section, you learn the implementation of the C# class library AirlineReservationsLib This nent contains all the necessary classes and methods that provide the core functionalities for the onlinereservations system To start, create a new Visual C# Class library project named AirlineReservationsLibusing Visual Studio 2005 After the project is created, change the name of the default class from Class1 toUserInfo The UserInfoclass simply acts as a container for holding user-related data, and its imple-mentation is shown in Listing 11-1
compo-Listing 11-1: Declaration of the UserInfo Class
protected string userID;
protected string passWord;
protected string name;
protected string address;
protected string phone;
protected string city;
protected string state;
protected string zip;
public string UserID{
get{return userID;}
set{userID = value;}
}public string PassWord{
Trang 10get{return passWord;}
set{passWord = value;}
}public string Name{
get{return name;}
set{name = value;}
}public string Address{
get{return address;}
set{address = value;}
}public string Phone{
get{return phone;}
set{phone = value;}
}public string City{
get{return city;}
set{city = value;}
}public string State{
get{return state;}
set{state = value;}
}public string Zip{
get{return zip;}
set{zip = value;}
}}}
As you can see from this code, the UserInfoclass simply exposes a bunch of properties that act as thecontainer for user-related data
Implementation of Data Access Layer Methods
So far, you have seen the container class for holding user-related data That is only part of the story, andyou need a data access layer class for persisting that data and retrieving that data from the Users table.This is where the UserDBclass comes into play Implementation of the UserDBclass is illustrated inListing 11-2
Listing 11-2: Implementation of UserDB Class
Trang 11string connString = System.Web.Configuration.WebConfigurationManager.ConnectionStrings[“airlines”].ConnectionString;
throw new InValidLoginException(“Invalid Login”);
}else{return true;
}}}catch (Exception ex){
throw ex;
}}public bool InsertUserInfo(UserInfo userInfo){
try{using (SqlConnection conn = new SqlConnection())
Trang 12{string connString = System.Web.Configuration.WebConfigurationManager.ConnectionStrings[“airlines”].ConnectionString;
SqlParameter paramPhone = new SqlParameter(“@Phone”, SqlDbType.Xml);
paramPhone.Value = new SqlXml(new XmlTextReader(userInfo.Phone, XmlNodeType.Document, null));
throw ex;
}}}}The UserDBclass contains two methods: CheckUserLogIn()and InsertUserInfo().TheCheckUserLogIn()method authenticates a customer’s user name and password against theAirlineReservation database Under the hood, CheckUserLogIn()method invokes the stored procedureCheckUserLogIn The CheckUserLogInstored procedure returns 1, if a record with the specified user
Trang 13name and password is found, else returns –1 Depending on the value returned by the stored procedure,the CheckUserLogInmethod either returns true or raises an exception of type InValidLoginException.The declaration of the InvalidLoginExceptionis as follows:
public class InValidLoginException : Exception
{
public InValidLoginException(string exceptionMessage) : base(exceptionMessage)
{}}
The InsertUserInfo()method persists the details of the user in the Users table It takes the UserInfoobject as an argument, parses its contents, executes a stored procedure, and returns true or false, depend-ing on the result of its execution Note how the phone column (which is of type XML) is added to theParameters collection of the SqlCommandobject
SqlParameter paramPhone = new SqlParameter(“@Phone”, SqlDbType.Xml);
paramPhone.Value = new SqlXml(new XmlTextReader(userInfo.Phone,
XmlNodeType.Document, null));
command.Parameters.Add(paramPhone);
You specify the type of the column as XML by passing in the enumeration SqlDbType.Xmlto the second parameter of the SqlParameter’sconstructor You then assign an object of type System.Data.SqlTypes.SqlXmlobject to the Value property of the SqlParameterobject Now that you have had alook at the UserDBclass, focus on the FlightDBclass that is specifically focused on searching of flightsand booking of flights
Implementation of FlightDB Class
One of the methods exposed by the FlightDBclass is SearchFlight()that allows you to search forflights based on a specific set of search criteria Listing 11-3 shows the code of the FlightDBclass
Listing 11-3: Implementation of FlightDB Class
User-defined exceptions allow you to notify the clients when a particular business
logic violation occurs or when a specific condition is reached They also allow you to
implement custom exception processing mechanisms such as logging the errors to
event log, and sending emails to an administrator and so on.
Trang 14try{using (SqlConnection conn = new SqlConnection()){
string connString = System.Web.Configuration.WebConfigurationManager.ConnectionStrings[“airlines”].ConnectionString;
conn.ConnectionString = connString;
DataSet flight = new DataSet(“Flights”);
SqlDataAdapter adapter = new SqlDataAdapter(“SearchFlight”, conn);
throw ex;
}}public int InsertBooking(int flightID, string passengerID, int travelClassID)
{try{using (SqlConnection conn = new SqlConnection()){
string connString = System.Web.Configuration.WebConfigurationManager.ConnectionStrings[“airlines”].ConnectionString;
Trang 15throw ex;
}}}
}
In addition to the SearchFlight()method, the FlightDBclass also contains a method namedInsertBooking()that persists the details of the booking onto the database For reasons of brevity, theimplementation of these methods will not be discussed in detail; however, you can download the com-plete code of the case study from the Wrox Web site
Implementation of StockDB Class
As the name suggests, the StockDBclass provides methods specifically for working with the Stockstable It exposes a method named GetStockQuote()that returns the stock quote based on the suppliedsymbol Listing 11-4 illustrates the code of the StockDBclass
Listing 11-4: Implementation of StockDB Class
Trang 16try{using (SqlConnection conn = new SqlConnection()){
//Retrieve the connection string from the configuration filestring connString = System.Web.Configuration.WebConfigurationManager.ConnectionStrings[“airlines”].ConnectionString;
XmlReader reader = command.ExecuteXmlReader();
XmlDocument doc = new XmlDocument();
//Load the XmlReader to an XmlDocument objectdoc.Load(reader);
return doc;
}}catch (Exception ex){
throw ex;
}}}}The GetStockQuote()method simply retrieves the stock quote by executing a stored procedure namedGetStockQuotethat accepts the stock ticker company as an argument and returns the XML output inthe form of an XmlReaderobject This XmlReaderobject is then loaded into an XmlDocumentobject and
is finally returned back to the caller
Implementation of Web Site
This section focuses on the implementation of the ASP.NET Web site The code of the Web site is cussed by considering the different processes involved Before getting into that discussion, go over thecode of the master page that is used throughout the Web site
dis-A Look at Master Pages
A professional Web site has a standardized look across all pages For example, one of the commonlyused layouts has its navigation menu on the left side of the page, a copyright on the bottom, and content
in the middle It can be difficult to maintain a standard look if you start duplicating the common logicand look and feel in every Web page you build In ASP.NET 2.0, Master Pages will make the job easier.You will need to write the common pieces only once in the Master Page A Master Page can serve as atemplate for one or more Web pages Each ASPX Web page only needs to define the content unique toitself, and this content will plug into specified areas of the Master Page layout
Trang 17A Master Page looks similar to an ASPX file, except a Master Page will have a master file extension instead of an aspx extension, and uses an @ Master directive instead of an @ Page directive at the top Master Pages will define the <html>, <head>, <body >, and <form>tags A new control, the ContentPlaceHoldercontrol, also appears in the Master Page You can have one or more
ContentPlaceHoldercontrols in a Master Page ContentPlaceHoldercontrols are where you want the ASPX Web pages to place their content A Web page associated with a Master Page is called a content page A content page may only contain markup inside of content controls If you try to place any markup or controls outside of the content controls, you will receive a compiler error Each Content control
in a content page maps to exactly one of theContentPlaceHoldercontrols in the Master Page
Listing 11-5 shows the code of the Master Page that will be used in the online reservations Web site
Listing 11-5: Master Page That Provides Consistent Look and Feel
//Create the XML file for the first timeCreateXmlFile(path);
}else{//Check to make sure that the file is not more than 20 minutes oldTimeSpan elapsedTimespan =
DateTime.Now.Subtract(File.GetLastWriteTime(path));
if (elapsedTimespan.Minutes > 20)//Refresh the contents of the XML fileCreateXmlFile(path);
} }
void CreateXmlFile(string path)
{
StockDB stock = new StockDB();
XmlDocument doc = stock.GetStockQuote(“WOTS”);
Trang 18<asp:Table id=”tblTop” BackColor=”Red” runat=”server” Width=”819px”
<asp:TableRow runat=”server” HorizontalAlign=”Center”>
<asp:TableCell runat=”server” ColumnSpan=”2”>
<asp:Label id=”Label1” runat=”server” ForeColor=”White”
Font-Size=”medium”>Online Reservation System
</asp:Label>
</asp:TableCell>
</asp:TableRow>
<asp:TableRow runat=”server” HorizontalAlign=”Center”>
<asp:TableCell runat=”server” ColumnSpan=”2” ForeColor=”White”>
<asp:XmlDataSource runat=”server” DataFile=”~/App_Data/Stocks.xml”
ID=”XmlDataSource1” XPath=”Stocks” />
<asp:GridView BorderWidth=0 BorderStyle=Ridge Font-Bold=”true”
Font-Size=Small ShowHeader=false runat=”server” ID=”stockoutput”
<asp:TableRow runat=”server” HorizontalAlign=”Right”>
<asp:TableCell runat=”server” ColumnSpan=”2”>
<asp:HyperLink runat=”server” ForeColor=”White” Text=”Logout”
<asp:XmlDataSource runat=”server” DataFile=”~/App_Data/Stocks.xml”
ID=”XmlDataSource1” XPath=”Stocks” />
Trang 19The XmlDataSourcecontrol utilizes a local XML file Stocks.xmlas the source of XML data TheStocks.xmlfile is very simple, and it just contains only one line of code.
<?xml version=”1.0” ?>
<Stocks name=”WOTS” price=”96”/>
The contents of the Stocks.xmlare updated periodically (specifically only in 20 minutes) through thelogic contained in the Page_Loadevent Let us focus on the Page_Loadevent
In the Page_Load, you first check to see if an XML file named Stocks.xmlfile is available
StockDB stock = new StockDB();
XmlDocument doc = stock.GetStockQuote(“WOTS”);
doc.Save(path);
}
The XmlDocument returned by the GetStockQuote()method is directly saved to the Stocks.xmlfile
If the Stocks.xmlfile is available locally, the Page_Loadmethod then checks to make sure that the file
is not more than 20 minutes old If the file is more than 20 minutes old, it invokes the CreateXml()method to refresh the contents of the XML file with the latest quote from the database
else
{
//Check to make sure that the file is not more than 20 minutes old
TimeSpan elapsedTimespan = DateTime.Now.Subtract
Trang 20Click Herein the login page Clicking this hyperlink takes the user to the registration page where theuser provides all the necessary details for completing the registration
The login feature of the Web site is implemented using a forms-based authentication mechanism Toenable forms-based authentication for the Web site, add the following entry in the web.config filedirectly under the <system.web>element
to add an entry to the web.config file For example, to set the restrictions of authenticated user access for
a page called SearchFlights.aspx, set the following entry directly under the <configuration>ment of the web.config file
sys-Now that you have a general understanding of the forms-based authentication, you are ready to ine the Login.aspxpage The Login.aspxpage is discussed in Listing 11-6
exam-Listing 11-6: Implementation of Login Page That Derives from the Master Page
<%@ Page Language=”C#” MasterPageFile=”~/Common.master” Title=”Login Page” %>
Trang 21authen-{UserDB user = new UserDB();
if (user.CheckUserLogIn(txtUserName.Text, txtPassword.Text) == true){
FormsAuthentication.SetAuthCookie(txtUserName.Text, true);
Session[“UserID”] = txtUserName.Text;
Response.Redirect(“SearchFlights.aspx”);
}}catch (InValidLoginException ex){
lblMessage.Visible = true;
lblMessage.Text = ex.Message;
}}
<asp:TextBox id=”txtUserName” tabIndex=”1” runat=”server”></asp:TextBox>
<asp:RequiredFieldValidator id=”RequiredFieldValidator1” tabIndex=”10” runat=”server” ControlToValidate=”txtUserName” ErrorMessage=”*”
Trang 22<asp:Button id=”btnLogin” OnClick=”btnLogin_Click” tabIndex=”3”
runat=”server” Height=”29px” Width=”105px” Text=”Login”>
<asp:HyperLink id=”lnkUserRegistration” tabIndex=”4” runat=”server”
Height=”28px” Width=”176px” Font-Bold=”True”
NavigateUrl=”Registration.aspx”>New Users Click here</asp:HyperLink>
UserDB user = new UserDB();
if (user.CheckUserLogIn(txtUserName.Text, txtPassword.Text) == true){
Whenever the exception InValidLoginExceptionoccurs, you catch that in the catch block and displaythe exception message in the label control lblMessage
catch (InValidLoginException ex){
lblMessage.Visible = true;
lblMessage.Text = ex.Message;
}Figure 11-3 shows the login page in action
In this case study, since I utilized custom tables to store user details, I need to validate the user tials against those custom tables With ASP.NET 2.0, however, you can utilize the membership store tostore user details and also leverage the built-in security mechanisms to validate the user An exampleimplementation of this approach is discussed in Chapter 15
Trang 23creden-Figure 11-3
New User Registration Process
The registration page allows users wanting to take advantage of online reservation system to registerthemselves as members Implementation of the registration page is discussed in Listing 11-7
Listing 11-7: New User Registration Page
<%@ Page Language=”C#” MasterPageFile=”~/Common.master” Title=”New User
Trang 24}string CreateXml(){
System.Text.StringBuilder output = new System.Text.StringBuilder();
XmlWriter writer = XmlWriter.Create(output);
<asp:Label id=”lblHeading” runat=”server” ForeColor=”Black”
Height=”27px” Width=”154px” BackColor=”Transparent”
BorderStyle=”Ridge”> New User Registration</asp:Label>
Trang 25<asp:Label id=”lblConfirmPassWord” runat=”server” Height=”24px”
Width=”103px” Font-Bold=”True”>Confirm Password:</asp:Label>
Trang 26<asp:Label id=”lblOfficePhone” runat=”server” Height=”25px”
Width=”126px” Font-Bold=”True”>Office Phone:</asp:Label>
Trang 27<asp:Button id=”btnSave” OnClick=”btnSave_Click” tabIndex=”9”
runat=”server” Height=”24px” Width=”100px” Text=”Save Details”>
Figure 11-4 shows the registration page when requested from the browser
After the registration is completed, the Web site redirects the user to the SearchFlights.aspxpagethrough a call to the Server.Transfer()method
Logout Process
All you need to do to log out of the site is to click on the Logout hyperlink on the header When you click
on that link, the user is redirected to the Logout.aspxpage shown in Listing 11-8
Trang 28Figure 11-4
Listing 11-8: Implementation of Logout Functionality
<%@ Page Language=”C#” MasterPageFile=”~/Common.master” Title=”Logout Page” %>
Trang 29cookies (used for authentication purposes) in the client machine and the user will be automatically rected to the login page.
redi-Search Flight Process
This involves searching for flights based on parameters such as arrival date, start date, and startingfrom, destination, and travel class code The search page is an important page in that it showcases thevarious XML features of NET One of the important features of the search page is that it retrieves thesearch results from the server side without even posting back to the server Figure 11-5 clearly outlinesthe flow of the page as it relates to the communication from the client side to the server side as well asthe different XML features used during those steps
The XML features utilized in the search page are as follows:
❑ XSD validation of input XML search criteria
❑ Use of ASP.NET 2.0 Script Callback to asynchronously retrieve XML data from the client sidewithout refreshing the browser
❑ Use of the XML features of DataSetobject to convert the DataSetobject contents into an XMLrepresentation
❑ Transformation of XML to HTML using XSL transformation
Figure 11-5
Validates the input XML
using an XSD schema
SearchFlights.aspx(Server Side)
SearchFlights.aspx(Client Side)XML representation
of search criteria
TransformedHTML output
Gets the search
results
5
AirlineReservationsLib(.NET component)
AirlineReservationDatabase
Transforms the DataSetXML to HTML
SearchFlights Page Flow
Server Side Client Side
42
3
1
Trang 30Listing 11-9 discusses the code of the SearchFlights.aspxpage.
Listing 11-9: Implementation of Search Functionality
<%@ Page Language=”C#” MasterPageFile=”~/Common.master”
private StringBuilder _builder = new StringBuilder();
private string _callbackArg;
void ICallbackEventHandler.RaiseCallbackEvent(string eventArgument){
_callbackArg = eventArgument;
}string ICallbackEventHandler.GetCallbackResult(){
try{return GetSearchResults(_callbackArg);
}catch (Exception ex){
throw new ApplicationException(“An Error has occurred during the “ +
“processing of your request Error is :” + ex.Message);
}}string GetSearchResults(string input){
XmlDocument inputDoc = new XmlDocument();
if (IsInputXmlValid(input)){