22.6. Using Web Forms and Web Services Our prior examples accessed Web services from Windows applications. You can just as easily use Web services in Web applications. In fact, Web-based businesses are becoming increasingly prevalent, so it's common for Web applications to consume Web services. Figure 22.20 presents an airline reservation Web service that receives information regarding the type of seat a customer wishes to reserve and makes a reservation if such a seat is available. Later in this section, we present a Web application that allows a customer to specify a reservation request, then uses the airline reservation Web service to execute the request. The code and database used in this example are provided with the chapter's examples, which can be downloaded from www.deitel.com/books/vbforprogrammers2. Figure 22.20. Airline reservation Web service. 1 ' Fig. 22.20: ReservationWebService.vb 2 ' Airline reservation Web Service.Imports System.Web 3 Imports System.Web.Services 4 Imports System.Web.Services.Protocols 5 6 <WebService(Namespace:="http://www.deitel.com/")> _ 7 <WebServiceBinding(ConformsTo:=WsiProfiles.BasicProfile1_1)> _ 8 <Global.Microsoft.VisualBasic.CompilerServices.DesignerGenerated()> 9 Public Class ReservationWebService 10 Inherits System.Web.Services.WebService 11 ' create TicketsDataSet object for caching data 12 ' from the Tickets database 13 Private ticketsDataSet As New TicketsDataSet() 14 15 ' create SeatsTableAdapter for interacting with the database 16 Private seatsTableAdapter As _ 17 New TicketsDataSetTableAdapters.SeatsTableAdapter() 18 19 ' checks database to determine whether matching seat is available 20 <WebMethod(Description:="Method to reserve a seat.")> _ 21 Public Function Reserve(ByVal seatType As String, _ 22 ByVal classType As String) As Boolean 23 ' fill TicketsDataSet.Seats with rows that represent untaken 24 ' seats that match the specified seatType and classType 25 seatsTableAdapter.FillByTypeAndClass( _ 26 ticketsDataSet.Seats, seatType, classType) 27 28 ' if the number of seats returned is nonzero, 29 ' obtain the first matching seat number and mark it as taken 30 If ticketsDataSet.Seats.Count <> 0 Then 31 Dim seatNumber As String = ticketsDataSet.Seats(0).Number 32 33 seatsTableAdapter.UpdateSeatAsTaken(seatNumber) 34 Return True ' seat was reserved 35 End If 36 37 Return False ' no seat was reserved 38 End Function ' Reserve 39 End Class ' ReservationWebService | The airline reservation Web service has a single Web methodReserve (lines 2038)which searches a seat database (Tickets.mdf) to locate a seat matching a user's request. If it finds an appropriate seat, Reserve updates the database, makes the reservation and returns true; otherwise, no reservation is made, and the method returns False. Note that the statements at lines 2526 and line 33, which query and update the database, use objects of classes TicketsDataSet and TicketsDataSetTableAdapters.SeatsTableAdapter. Recall from Chapter 20 that DataSet and TableAdapter classes are created for you when you use the DataSet Designer to add a DataSet to a project. We discuss the steps for adding the TicketsDataSet in Section 22.6.1. Reserve receives two parametersa String representing the desired seat type (i.e., Window, Middle or Aisle) and a String representing the desired class type (i.e., Economy or First). Our database contains four columnsthe seat number (i.e., 110), the seat type (i.e., Window, Middle or Aisle), the class type (i.e., Economy or First) and a column containing either 1 (TRue) or 0 (false) to indicate whether the seat is taken. Lines 2526 retrieve the seat numbers of any available seats matching the requested seat and class type. This statement fills the Seats table in ticketsDataSet with the results of the query SELECT Number FROM Seats WHERE (Taken = 0) AND (Type = @type) AND (Class = @class) The parameters @type and @class in the query are replaced with values of the seatType and classType arguments to SeatsTableAdapter method FillByTypeAndClass. In line 30, if the number of rows in the Seats table (ticketsDataSet.Seats.Count) is not zero, there was at least one seat that matched the user's request. In this case, the Web service reserves the first matching seat number. We obtain the seat number in line 31 by accessing the Seats table's first element (i.e., Seats(0)the first row in the table), then obtaining the value of that row's Number column. Line 33 invokes the SeatsTableAdapter method UpdateSeatAsTaken and passes to it seatNumberthe seat to reserve. The method uses the UPDATE statement UPDATE Seats SET Taken = 1 WHERE (Number = @number) to mark the seat as taken in the database by replacing parameter @number with the value of seatNumber. Method Reserve returns TRue (line 34) to indicate that the reservation was successful. If there are no matching seats (line 30), Reserve returns False (line 37) to indicate that no seats matched the user's request. 22.6.1. Adding Data Components to a Web Service Next, you'll use Visual Web Developer's tools to configure a DataSet that allows our Web service to interact with the Tickets.mdf SQL Server database file. You'll add a new DataSet to the project, then configure the DataSet's TableAdapter using the TableAdapter Configuration Wizard. The wizard allows you to select the data source (Tickets.mdf) and to create the SQL statements necessary to support the database operations discussed in Fig. 22.20's description. The following steps for configuring the DataSet and its corresponding TableAdapter are similar to those you saw in Chapters 20 and 21. Step 1. | Create ReservationWebService and Add a DataSet to the Project
Begin by creating an ASP.NET Web Service project named ReservationWebService. Rename the file Service.vb as ReservationWebService.vb and replace its code with the code in Fig. 22.20. Next, add a DataSet named TicketsDataSet to the project. Right click the App_Code folder in the Solution Explorer and select Add New Item… from the popup menu. In the Add New Item dialog, select DataSet, specify TicketsDataSet.xsd in the Name field and click Add. This displays the TicketsDataSet in design view and opens the TableAdapter Configuration Wizard. When you add a DataSet to a project, the IDE creates appropriate TableAdapter classes for interacting with the database tables.
| Step 2. | Select the Data Source and Create a Connection
You'll use the TableAdapter Configuration Wizard in the next several steps to configure a TableAdapter for manipulating the Seats table in the Tickets.mdf database. Now, you must select the database. In the TableAdapter Configuration Wizard, click the New Connection… button to display the Add Connection dialog. In this dialog, specify Microsoft SQL Server Database File as the Data source, then click the Browse… button to display the Select SQL Server Database File dialog. Locate Tickets.mdf on your computer, select it and click the Open button to return to the Add Connection dialog. Click the Test Connection button to test the database connection, then click OK to return to the TableAdapter Configuration Wizard. Click Next >, then click Yes when you are asked whether you would like to add the file to your project and modify the connection. Click Next > to save the connection string in the application configuration file.
| | | Step 3. | Open the Query Builder and Add the Seats Table from Tickets.mdf
You must specify how the TableAdapter will access the database. In this example, you'll use SQL statements, so choose Use SQL Statements, then click Next >. Click Query Builder… to display the Query Builder and Add Table dialogs. Before building a SQL query, you must specify the table(s) to use in the query. The Tickets.mdf database contains only one table, named Seats. Select this table from the Tables tab and click Add. Click Close to close the Add Table dialog.
| Step 4. | Configure a SELECT Query to Obtain Available Seats
Now let's create a query which selects seats that are not already reserved and that match a particular type and class. Select Number from the Seats table at the top of the Query Builder dialog. Next, specify the criteria for selecting seats. In the middle of the Query Builder dialog, click the cell below Number in the Column column and select Taken. In the Filter column of this row, type 0 (i.e., false) to indicate that we should select only seat numbers that are not taken. In the next row, select Type in the Column column and specify @type as the Filter to indicate that the filter value will be specified as an argument to the method that implements this query. In the next row, select Class in the Column column and specify @class as the Filter to indicate that this filter value also will be specified as a method argument. Uncheck the checkboxes in the Output column for the Taken, Type and Class rows. The Query Builder dialog should now appear as shown in Fig. 22.21. Click OK to close the Query Builder dialog. Click Next > to choose the methods to generate. Name the Fill and Get methods FillByTypeAndClass and GetdataByTypeAndClass, respectively. Click the Finish button to generate these methods.
Figure 22.21. QueryBuilder dialog specifying a SELECT query that selects seats that are not already reserved and that match a particular type and class. | | | Step 5. | Add Another Query to the SeatsTableAdapter for the TicketsDataSet
Now, you'll create an UPDATE query that reserves a seat. In the design area for the TicketsDataSet, click SeatsTableAdapter to select it, then right click it and select Add Query… to display the TableAdapter Query Configuration Wizard. Select Use SQL Statements and click Next >. Select Update as the query type and click Next >. Delete the existing UPDATE query. Click Query Builder… to display the Query Builder and Add Table dialogs. Then add the Seats table as you did in Step 3 and click Close to return to the Query Builder dialog.
| Step 6. | Configure an UPDATE Statement to Reserve a Seat
In the Query Builder dialog, select the Taken column from the Seats table at the top of the dialog. In the middle of the dialog, place the value 1 (i.e., true) in the New Value column for the Taken row. In the row below Taken, select Number, uncheck the checkbox in the Set column and specify @number as the Filter value to indicate that the seat number will be specified as an argument to the method that implements this query. The Query Builder dialog should now appear as shown in Fig. 22.22. Click OK to return to the TableAdapter Query Configuration Wizard. Then click Next > to choose the name of the update method. Name the method UpdateSeatAsTaken, then click Finish to close the TableAdapter Query Configuration Wizard. At this point, you can use the ReservationWebService.asmx page to test the Web service's Reserve method. To do so, select Start Without Debugging from the Debug menu. In Section 22.6.2, we build a Web form to consume this Web service.
Figure 22.22. QueryBuilder dialog specifying an UPDATE statement that reserves a seat. | 22.6.2. Creating a Web Form to Interact with the Airline Reservation Web Service Figure 22.23 presents the code for a Web Form through which users can select seat types. This page allows users to reserve a seat on the basis of its class (Economy or First) and location (Aisle, Middle or Window) in a row of seats. The page then uses the airline reservation Web service to carry out users' requests. If the database request is not successful, the user is instructed to modify the request and try again. When you create this ASP.NET application, remember to add a Web reference to the ReservationWebService of Fig. 22.20 Figure 22.23. ASPX file that takes reservation information. 1 <%-- Fig. 22.23: ReservationClient.aspx --%> 2 <%-- Web Form that allows users to reserve seats on a plane. --%> 3 <%@ Page Language="VB" AutoEventWireup="false" 4 CodeFile="ReservationClient.aspx.vb" Inherits="ReservationClient" %> 5 6 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 7 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 8 9 <html xmlns="http://www.w3.org/1999/xhtml" > 10 <head runat="server"> 11 <title>Ticket Reservation</title> 12 </head> 13 <body> 14 <form id="form1" runat="server"> 15 <div> 16 <asp:Label ID="instructionsLabel" runat="server" 17 Text="Please select the seat type and class to reserve:"> 18 </asp:Label> 19 <br /><br /> 20 <asp:DropDownList ID="seatList" runat="server" 21 Height="22px" Width="100px"> 22 <asp:ListItem>Aisle</asp:ListItem> 23 <asp:ListItem>Middle</asp:ListItem> 24 <asp:ListItem>Window</asp:ListItem> 25 </asp:DropDownList> 26 27 <asp:DropDownList ID="classList" runat="server" Width="100px"> 28 <asp:ListItem>Economy</asp:ListItem> 29 <asp:ListItem>First</asp:ListItem> 30 </asp:DropDownList> 31 32 <asp:Button ID="reserveButton" runat="server" Text="Reserve" 33 Width="102px" /> 34 <br /><br /> 35 <asp:Label ID="errorLabel" runat="server" ForeColor="#C00000" 36 Height="19px" Width="343px"></asp:Label> 37 </div> 38 </form> 39 </body> 40 </html> | This page defines two DropDownList objects and a Button. One DropDownList (lines 2025) displays all the seat types from which users can select. The second (lines 2730) provides choices for the class type. Users click the Button named reserveButton (lines 3233) to submit requests after making selections from the DropDownLists. The page also defines an initially blank Label named errorLabel (lines 3536), which displays an appropriate message if no seat matching the user's selection is available. Line 9 of the code-behind file (Fig. 22.24) attaches an event handler to reserveButton. Figure 22.24. Code-behind file for the reservation page. 1 ' Fig. 22.24: ReservationClient.aspx.vb 2 ' ReservationClient code behind file. 3 Partial Class ReservationClient 4 Inherits System.Web.UI.Page 5 ' object of proxy type used to connect to Reservation Web service 6 Private ticketAgent As New localhost.ReservationWebService() 7 8 Protected Sub reserveButton_Click(ByVal sender As Object , _ 9 ByVal e As System.EventArgs) Handles reserveButton.Click 10 If ticketAgent.Reserve(seatList.SelectedItem.Text, _ 11 classList.SelectedItem.Text.ToString()) Then 12 ' hide other controls 13 instructionsLabel.Visible = False 14 seatList.Visible = False 15 classList.Visible = False 16 reserveButton.Visible = False 17 errorLabel.Visible = False 18 19 ' display message indicating success 20 Response.Write("Your reservation has been made. Thank you.") 21 Else ' WebMethod returned false, so signal failure 22 ' display message in the initially blank errorLabel 23 errorLabel.Text = "This type of seat is not available." & _ 24 "Please modify your request and try again." 25 End If 26 End Sub ' reserveButton_Click 27 End Class ' ReservationClient | Line 6 of Fig. 22.24 creates a ReservationWebService object. When the user clicks Reserve (Fig. 22.25), the reserveButton_Click event handler (lines 826 of Fig. 22.24) executes, and the page reloads. The event handler calls the Web service's Reserve method and passes to it the selected seat and class type as arguments (lines 1011). If Reserve returns TRue, the application hides the GUI controls and displays a message thanking the user for making a reservation (line 20); otherwise, the application notifies the user that the type of seat requested is not available and instructs the user to try again (lines 2324). You can use the techniques presented in Chapter 21 to build this ASP.NET Web Form. Figure 22.25 shows several user interactions with this Web application. Figure 22.25. Ticket reservation Web Form sample execution.
a) Selecting a seat.
b) Seat reserved successfully.
c) Attempting to reserve another seat.
d) No seats match the requested type and class. |