Implementing the Island Hopper Application Presentation Layer

For the remainder of this chapter, we'll look at the implementation of parts of the Island Hopper application. We'll focus on the code that uses the business objects to manage customers and classified ads.

Design Decisions

During the modeling phase, discussed in Chapter 7, we noted two primary groups of users for the Island Hopper application: employees and customers. Employees of the Island Hopper News must be able to manage classified ads, invoices, and payments. External customers must be able to browse ads and place ads over the Internet. This suggests two presentation layer applications are needed: a Web-based application for external customers and a second application for employees. The employees' application could be either a native application or a Web-based application. For Island Hopper, we have chosen to make the employees' application a native application.

For the native application used by employees, we'll assume that all users have a Win32-based operating system with DCOM enabled. Thus, the Win32 client application can make remote COM calls directly to the business objects on the server. The application, named Classifieds, has been written using Visual Basic. Because the application is written so that it can be built using either Visual Basic 5.0 or Visual Basic 6.0, it does not use ADO data-binding. Instead, the forms contain code to populate controls from ADO Recordset objects returned by business objects and to retrieve user input from controls to pass to business objects.

For the Island Hopper Web-based application, we'll assume that all users have Web browsers that support DHTML but that neither client-side COM components nor remote COM calls can be used. Thus, the Island Hopper Web-based application uses ASP pages to access the business objects on the server and generate DHTML pages that are returned to the client via HTTP. Users enter data via standard HTML forms. When these forms are submitted, the ASP pages parse the form parameters and use server-side script to call the necessary business objects. Client-side scripting will be used to perform simple validation of data before submitting the form.

Implementing the Classifieds Application

The Classifieds application is a fairly standard forms-based Visual Basic application. The Ad Maintenance form for this application is shown in Figure 11-1. Most of the code is devoted to displaying the correct form, based on user selections, and enabling or disabling controls on the forms so that users know which values must be filled in or can be modified.

click to view at full size.

Figure 11-1. The Classifieds application Ad Maintenance form.

The code that interests us handles three tasks: creating business objects, calling business objects, and handling errors. Listing 11-1 contains most of the business object_related code from the Ad Maintenance form. (The code to retrieve customer information by ID is not shown.)

Listing 11-1. FrmAdC form source code fragments.

 Option Explicit Private objErrPlus As New ErrPlus.Logger Private epRV As ErrPlus.LogRetCodes Private objCustomer As bus_CustomerC.Customer Private iCustomerLookup As IBUSCUSTOMERLib.IbusCustomerLookup Private iCustomerChange As IBUSCUSTOMERLib.IbusCustomerChange Private Const Modname As String = "frmAdC" . . . Private Sub Form_Load()    Set objCustomer = CreateObject("bus_CustomerC.Customer")    .    .    . End Sub . . . Private Sub cmdRetrieveEmail_Click()    Dim rsCustomer As ADODB.Recordset    Dim rsPassword As ADODB.Recordset         On Error GoTo ErrorHandler        Me.MousePointer = vbArrowHourglass    ' Use variable objCustomer, which is an instance of a     ' bus_CustomerC.Customer object and global to this form,     ' to retrieve information about this customer.    Set iCustomerLookup = objCustomer    iCustomerLookup.GetByEmail txtField(frmAdC_Email).Text, _             rsCustomer, rsPassword             If rsCustomer.EOF And rsCustomer.BOF Then   ' No records in set       ' Customer was not found.       MsgBox LoadResString(CUSTOMER_NOT_FOUND)       cmdCancel_Click    Else       ' Customer was found. Fill the text fields with information.       FillFields rsCustomer                ' Prevent the user from searching again until the Cancel        ' button is clicked, and disable the user from editing the        ' text fields.       cmdRetrieveEmail.Enabled = False       DisableText    End If    Me.MousePointer = vbDefault         ' Clean up Recordset objects on the way out.    Set rsCustomer = Nothing    Set rsPassword = Nothing    Set iCustomerLookup = Nothing         Exit Sub ErrorHandler:    epRV = objErrPlus.Log(Err.Number, Err.Description, _             App.Title, Err.Source, "RetrieveByEmail", _             Modname, logToEventViewer, elShowUserYes)    Me.MousePointer = vbDefault End Sub . . . '******************************************************************* ' FillAdList ' Purpose: Lists the ads for this customer ID in the flex grid '******************************************************************* Public Sub FillAdList()    On Error GoTo ErrorHandler    Dim rsAd As ADODB.Recordset    Dim objAd As bus_AdC.Ad    Dim i As Integer    ' Create an instance of the bus_AdC.Ad object to retrieve ads     ' from the database for this customer.    Set objAd = CreateObject("bus_AdC.Ad")    Set rsAd = objAd.ListByCustID _               (CLng(txtField(frmAdC_CustomerID).Text))    If rsAd.EOF And rsAd.BOF Then ' No ads were found.      MsgBox LoadResString(NO_ADS_FOUND)    Else      ' Ads were found. Loop through Recordset, filling the flex      ' grid with ad information, until Recordset EOF is reached.       i = 1       Do Until rsAd.EOF       With flxAdList          .Rows = .Rows + 1          .TextMatrix(i, 0) = rsAd!AdvertisementID          .TextMatrix(i, 1) = rsAd!Title          .TextMatrix(i, 2) = rsAd!StartDate          .TextMatrix(i, 3) = rsAd!EndDate          End With          i = i + 1          rsAd.MoveNext       Loop       With flxAdList          .ForeColorSel = &H8000000E          .BackColorSel = &H8000000D          .ColSel = 3          .SetFocus       End With    End If        ' Clean up the Recordset object on the way out.    Set rsAd = Nothing        Exit Sub      ErrorHandler:    epRV = objErrPlus.Log(Err.Number, Err.Description, _           App.Title, Err.Source, "FillAdList", Modname, _           logToEventViewer, elShowUserYes) End Sub . . . '******************************************************************* ' FillFields ' Purpose: Fills in the customer information text fields '******************************************************************* Private Sub FillFields(rsCustomer As ADODB.Recordset)    ' Fill text fields with customer information.    txtField(frmAdC_CustomerID).Text = rsCustomer!CustomerID    txtField(frmAdC_Email).Text = rsCustomer!Email    txtField(frmAdC_LastName).Text = rsCustomer!LastName    txtField(frmAdC_FirstName).Text = rsCustomer!FirstName             ' Disable the Retrieve and Search buttons until the user clicks    ' the Cancel button.    cmdRetrieveID.Enabled = False    cmdRetrieveEmail.Enabled = False    cmdSearchCustomer.Enabled = False    cmdPlaceAd.Enabled = True         ' Fill the flex grid with ad information.    FillAdList End Sub . . . 

For the most part, this code is no different from code you would write to use client-side COM objects. However, a few interesting points warrant review. First, as noted earlier, base client applications should acquire and hold pointers to MTS objects rather than re-creating the objects each time they are needed. In the Classifieds application, the MTS objects needed by each form are usually created when the form is loaded and the object references are held in variables global to the form. For example, on the Ad Maintenance form, a Customer object is created in the Form_Load function, with the reference stored in the form's global variable objCustomer. When the form is unloaded, Visual Basic will automatically release the object reference. Objects that are used for only one specific operation are normally created within a specific function. For example, the Ad Maintenance form creates an Ad object in FillAdList, since this is the only function that needs to use the Ad object.

Notice that nothing in the call to CreateObject indicates that the object should be created remotely. In Visual Basic 5.0, CreateObject has no way to specify the remote server location. Instead, it relies on information in the system registry on the client machine to determine where the object should be created. In Visual Basic 6.0, CreateObject takes an optional argument to specify the remote server name. However, you will still need to have information in the system registry to map the ProgID specified in the CreateObject call into a CLSID. This information is written by the client install programs generated when you export an MTS package.

Second, recall that some of the Island Hopper application business objects expose more than one interface. The bus_CustomerC.Customer class exposes the IbusCustomerLookup and IbusCustomerChange interfaces, as well as the default _Customer interface. When Form_Load creates the Customer object, it obtains a reference to the default _Customer interface. To look up customer information, however, the Classifieds application needs a reference to the IbusCustomerLookup interface. In Microsoft Visual C++, you would use IUnknown QueryInterface to get a reference to another interface on the same object. In Visual Basic, all you need to write is a Set statement, as shown here:

 Private iCustomerLookup As IBUSCUSTOMERLib.IbusCustomerLookup Set iCustomerLookup = objCustomer 

This statement has the same effect as calling QueryInterface. If you want to release a reference to an object, you set the variable to Nothing, as shown here:

 Set iCustomerLookup = Nothing 

Third, remember that we elected not to use ADO data-binding to connect user interface controls to ADO Recordset objects returned by the business objects. Instead, each form includes code to populate controls with data retrieved from the business objects and to take new data from the controls before calling the business objects to create or update records. On the Ad Maintenance form, the code to populate controls with data retrieved from a Recordset is contained in the functions FillFields and FillAdList. FillFields simply pulls individual field values out of the Recordset for the current record and places the values in form controls, as shown here:

 txtField(frmAdC_CustomerID).Text = rsCustomer!CustomerID txtField(frmAdC_Email).Text = rsCustomer!Email txtField(frmAdC_LastName).Text = rsCustomer!LastName txtField(frmAdC_FirstName).Text = rsCustomer!FirstName 

FillAdList is a little more complicated because it is filling a grid control with a set of records. Thus, it uses ADO to iterate through the Recordset object, pulling information from the current record and putting it into a new row in the grid. The following code from the Ad Details form, FrmAdDetailC, shows how data is retrieved from controls and passed to business object methods:

 '******************************************************************* ' UpdateAd ' Purpose: Updates an ad in the database '******************************************************************* Private Sub UpdateAd()    Dim datEndDate As Date    Dim objAd As bus_AdC.Ad    Dim rsCustomer As ADODB.Recordset    Dim lngAdID As Long         On Error GoTo ErrorHandler         ' Check whether information in text boxes is valid.        If ValidateFields Then        ' Use variable objCustomer, which is an instance of        ' a bus_CustomerC.Customer object and global to this        ' form, to retrieve information about this customer.       objCustomer.GetByID lngCustomerID, rsCustomer       ' Determine end date by adding the selected duration        ' to the start date.       datEndDate = CDate(txtField(frmAdDetailC_StartDate).Text) _                    + (cboDuration.ListIndex + 1) * 7 - 1                ' Create an instance of the bus_AdC.Ad object to update        ' ad and customer information in the database.       Set objAd = CreateObject("bus_AdC.Ad")       objAd.UpdateAd CLng(txtField(frmAdDetailC_AdID)), _                      txtField(frmAdDetailC_Title), _                      txtField(frmAdDetailC_Body), _                      txtField(frmAdDetailC_StartDate), _                      CStr(datEndDate), _                      cboCategory.ItemData(cboCategory.ListIndex), _                      lngCustomerID, _                      rsCustomer!Email, _                      rsCustomer!LastName, _                      rsCustomer!FirstName, _                      rsCustomer!Address, _                      rsCustomer!City, _                      rsCustomer!State, _                      rsCustomer!PostalCode, _                      rsCustomer!Country, _                      rsCustomer!PhoneNumber       MsgBox LoadResString(UPDATE_AD_CONFIRM)    End If         ' Clean up Recordset object on the way out.    Set rsCustomer = Nothing         Exit Sub      ErrorHandler:    epRV = objErrPlus.Log(Err.Number, Err.Description, _           App.Title, Err.Source, "InsertAd", Modname, _           logToEventViewer, elShowUserYes) End Sub 

Finally, note that errors generated by the business objects (and other run-time errors) are handled in a consistent manner throughout the code. The Classifieds application uses a COM object, ErrPlus.Logger, to handle error logging, as shown here:

 Private Sub MyFunction()    On Error GoTo ErrorHandler       .       .       .    Exit Sub ErrorHandler:    epRV = objErrPlus.Log(Err.Number, Err.Description, _           App.Title, Err.Source, "MyFunction", Modname, _           logToEventViewer, elShowUserYes) End Sub 

The error-logging component optionally displays errors to the user, and the errors are also written to the Windows NT Event Log. This redundancy helps system administrators or help desk technicians troubleshoot errors encountered by application users, who might not understand what a message displayed on the screen means or who might not record the message before asking for help.

The other forms in the Classifieds application use the same techniques as the Ad Maintenance and Ad Details forms for communicating with the Island Hopper business objects. Figure 11-2 illustrates the relationships between the various forms in the Classifieds application.

click to view at full size.

Figure 11-2. The Classifieds application architecture.

Implementing the Internet Client

Let's switch gears now and look at the Web-based application. The Ad Entry page from the Internet client is shown in Figure 11-3. This application uses DHTML and JavaScript on the client. ASP and VBScript are used on the server to generate the DHTML pages returned to the client. Only the ASP pages communicate with the Island Hopper business objects; all data is embedded within the DHTML pages returned to the client.

click to view at full size.

Figure 11-3. The Island Hopper application's Internet client Ad Entry page.

As with the native Win32 application, most of the code—in particular, all the client-side JavaScript code—is devoted to the user interface. The interesting code is contained in the server-side scripts and ASP directives in the ASP pages. Listing 11-2 contains the relevant portions of the Ad Entry page.

Listing 11-2. ADENTRY.ASP page source code.

 <%@LANGUAGE="VBSCRIPT"TRANSACTION=REQUIRED%>  <% Option Explicit %> <%    ' File: ADENTRY.ASP     ' Overview: Uses COM objects to perform the following tasks:    '           Verify user's e-mail and password    '           Enter user information on the page    '           Generate list of categories    '           Get unit price of an ad %> <!--#INCLUDE FILE = "strFile.vbs"--> <%    ' ASP Variables    ' Module-level variables used throughout the page    Dim m_strEmail, m_strLastName, m_strFirstName, m_strAddress, _        m_strCity, m_strState, m_strPostalCode, m_strPhoneNumber, _        m_strCountry, m_arrCategory(), m_unitPrice(), _        m_intNavBarLeft, m_intNavBarTop, m_intCounter, m_strPassword    VerifyUserByEmail    AdUnitPrice %> <!--#INCLUDE FILE = "BROWSERCHECK.VBS"--> <HTML> <HEAD> <META NAME="GENERATOR" CONTENT="Microsoft Developer Studio"> <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1"> <TITLE>Online Classified Advertisement Entry </TITLE> <LINK REL=STYLESHEET HREF="STYLES.CSS" TYPE="text/css"> <SCRIPT LANGUAGE="JavaScript"> . . . </SCRIPT> </HEAD> <BODY CLASS=body> . . . <FORM METHOD=POST NAME="frmAd" ACTION="ADCONFIRM.ASP"> <INPUT type="hidden" value="<% =m_strPassword %>" name="Password">   <!-- This is the Ad Entry form. --> . . . <TABLE BORDER=0 CELLPADDING=0 CELLSPACING=0    STYLE="position:absolute; top:30; left:83">    <TR>       <TD CLASS=label ALIGN=right>Email&nbsp;&nbsp;</TD>       <TD COLSPAN=3>          <INPUT CLASS=text ID=strEmail readOnly NAME=strEmail              TYPE=TEXT SIZE=36 VALUE="<%= m_strEmail %>"></INPUT>       </TD>    </TR>    <TR>       <TD CLASS=label ALIGN=right>Category&nbsp;&nbsp;</TD>       <TD COLSPAN=3>          <SELECT CLASS=label ID=lngCategoryId NAME=lngCategoryID>             <OPTION ID=lngCategoryIdColl VALUE="" SELECTED>                Please choose a category.             <% ListCategories %>          </SELECT>       </TD>    </TR>    <TR>       <TD CLASS=label ALIGN=right>Ad Title&nbsp;&nbsp;</TD>       <TD COLSPAN=3>          <INPUT CLASS=text SIZE=36 ID=strTitle NAME=strTitle              TYPE=TEXT MAXLENGTH=30 VALUE=""></INPUT>       </TD>    </TR>    <TR>       <TD CLASS=label ALIGN=right>Body&nbsp;&nbsp;</TD>       <TD COLSPAN=3>          <TEXTAREA CLASS=text WRAP=physical rows=4 cols=72              ID=strBody NAME=strBody SIZE=200 VALUE=""></TEXTAREA>       </TD>    </TR>    <TR>       <TD CLASS=label ALIGN=right>Start Date&nbsp;&nbsp;</TD>       <TD>          <INPUT SIZE=36 CLASS=text NAME=varStartDateTime              TYPE=TEXT SIZE=10 VALUE=""></INPUT>       </TD>       <TD CLASS=label ALIGN=right>Duration &nbsp;&nbsp;</TD>       <TD COLSPAN=2 ALIGN=left>          <SELECT CLASS=text ID=varDuration NAME=varDuration>           <!-- Did not use radio button here because object value                was inaccessible. -->             <OPTION VALUE=1 SELECTED>1 Week             <OPTION VALUE=2>2 Weeks          </SELECT>       </TD>    </TR>    <TR>       <TD CLASS=label ID=last ALIGN=right>Last Name&nbsp;&nbsp;</TD>       <TD COLSPAN=3>          <INPUT SIZE=36 CLASS=text ID=strLastName NAME=strLastName               MAXLENGTH=40 TYPE=TEXT SIZE=48               VALUE="<%= m_strLastName %>"></INPUT>       </TD>    </TR>    <TR>       <TD CLASS=label ALIGN=right SIZE=36>First Name&nbsp;&nbsp;       </TD>       <TD COLSPAN=3>          <INPUT CLASS=textBox ID=strFirstName NAME=strFirstName               MAXLENGTH=40 TYPE=TEXT SIZE=36               VALUE="<%= m_strFirstName %>"></INPUT>       </TD>    </TR>    <TR>       <TD CLASS=label ALIGN=right>Address&nbsp;&nbsp;</TD>       <TD><INPUT SIZE=36 CLASS=text ID=strAddress NAME=strAddress           MAXLENGTH=40 TYPE=TEXT SIZE=10            VALUE="<%= m_strAddress %>"></INPUT>       </TD>       <TD CLASS=label ALIGN=right>State&nbsp;&nbsp;</TD>       <TD ALIGN=left><INPUT CLASS=text ID=strState NAME=strState           MAXLENGTH=40 TYPE=TEXT SIZE=10           VALUE="<%= m_strState %>"></INPUT>       </TD>    </TR>    <TR>       <TD CLASS=label ALIGN=right>City&nbsp;&nbsp;</TD>       <TD>          <INPUT CLASS=text SIZE=36 ID=strCity NAME=strCity               MAXLENGTH=40 TYPE=TEXT VALUE="<%= m_strCity %>">          </INPUT>       </TD>       <TD ALIGN=right CLASS=label>Postal Code&nbsp;&nbsp;</TD>       <TD ALIGN=left>          <INPUT CLASS=text ID=strPostalCode NAME=strPostalCode               MAXLENGTH=40 TYPE=TEXT SIZE=10             VALUE="<%= m_strPostalCode %>"></INPUT>       </TD>    </TR>    <TR>       <TD CLASS=label ALIGN=right>Phone Number&nbsp;&nbsp;</TD>       <TD>          <INPUT SIZE=36 CLASS=text ID=strPhoneNumber              NAME=strPhoneNumber MAXLENGTH=40 TYPE=TEXT SIZE=10              VALUE="<%= m_strPhoneNumber %>"></INPUT>       </TD>       <TD ALIGN=right CLASS=label>Country&nbsp;&nbsp;</TD>       <TD ALIGN=left>          <INPUT CLASS=text ID=strCountry NAME=strCountry MAXLENGTH=40             TYPE=TEXT SIZE=10 VALUE="<%= m_strCountry %>"></INPUT>       </TD>    </TR> </TABLE> . . . </FORM> <!--#INCLUDE FILE = "NAVIGATIONBAR.JS" --> </BODY> </HTML> <SCRIPT RUNAT=SERVER LANGUAGE=VBScript> ' ServerSide Helper Functions ' ********************************************************************** ' AdUnitPrice ' Purpose: Retrieves cost of an ad from the database, adding scalability ' ********************************************************************** Sub AdUnitPrice()    Dim objProduct    On Error Resume Next    ' Create the unitPrice array.    Redim m_unitPrice(2)    ' Create an instance of db_productC object.    Set objProduct = Server.CreateObject("db_ProductC.Product")    ' Check for errors in creating the object.      ' Show error messages if there are any.    If Err.Number <> 0 Then       Response.Write(ERROR_GETTING_PRICES)       Err.Clear       Exit Sub    End If    ' Find unit prices for 100-word ads and 200-word ads in the     ' database.    m_unitPrice(0)= objProduct.GetUnitPrice("AD-100")    m_unitPrice(1) = objProduct.GetUnitPrice("AD-200") End Sub ' ****************************************************************** ' VerifyUserByEmail ' Purpose: Validates user's e-mail address and password before  '          proceeding; fills out form if information is valid ' ****************************************************************** Sub VerifyUserByEmail()     Dim objCustomer    Dim rsCustomer    ' Establish error handling.    On Error Resume Next    ' Create an instance of bus_Customer object.    Set objCustomer = CreateObject("bus_CustomerC.Customer")    ' Check for errors in creating object.    If Err.Number <> 0 Then        Response.Write(ERROR_RETRIEVING_CUST)       Err.Clear       Exit Sub    End If    ' Check for an e-mail address for the user; send user to     ' login page if no address exists.    If len(Request.Form("UserEmail")) = Null Then       Response.Redirect("Login.asp?FailedAttempt=Yes")    Else       ' Validate the password and e-mail address.       Set rsCustomer =  _           objCustomer.Validate(Trim(Request.Form("UserEmail")), _           Trim(Request.Form("Password")))       ' An error means that password was not validated and        ' user must be sent to login page.       If Err.Number <> 0 Then          Response.Redirect("Login.asp?FailedAttempt=Yes&Email=" _                            & Trim(Request.Form("UserEmail")))       End If    End If    ' If the preceding code completes without errors, fill in the    ' Ad Entry form with user information.    FillOutForm rsCustomer End Sub ' ****************************************************************** ' FillOutForm ' Purpose: Enters customer information from database into form  '          variables ' Inputs: rsCustomer--an ADODB Recordset object containing user  '         information ' ****************************************************************** Sub FillOutForm(rsCustomer)    On Error Resume Next    ' Insert values from rsCustomer into the module-level     ' variables on the form.    m_strEmail = rsCustomer("Email")    m_strLastName = rsCustomer("LastName")    m_strFirstName = rsCustomer("FirstName")    m_strAddress = rsCustomer("Address")    m_strCity = rsCustomer("City")    m_strState = rsCustomer("State")    m_strPostalCode = rsCustomer("PostalCode")    m_strCountry = rsCustomer("Country")    m_strPhoneNumber = rsCustomer("PhoneNumber")    m_strPassword = Trim(Request.Form("Password"))    If Err.Number <> 0 Then       ' Display a friendly message.       Response.Write(ERROR_UPDATING_CUSTOMER)       Err.Clear    End If  End Sub ' ****************************************************************** ' ListCategories ' Purpose: Writes category names in an option box on the Ad Entry form  ' ****************************************************************** Sub ListCategories    Dim dbCat, rsCat, intID, strName, m_intCounter    ' Establish error handling.    On Error Resume Next    ' Set initial value for counter.    m_intCounter = 0     ' Create db_Category object.    Set dbCat = Server.CreateObject("db_CategoryC.Category")    ' Make rsCat a Recordset object containing all categories.    Set rsCat = dbCat.ListAll()    ' Check for errors.    If Err.Number <> 0 Then       ' Return friendly error message to the user.       Response.Write(ERROR_GETTING_CATEGORIES)       Err.Clear       Exit Sub    End If    ' Write the option list from list of categories.     Do While Not rsCat.EOF        intID = rsCat("CategoryID")        strName = rsCat("Name")        Response.Write("<OPTION ID=lngCategoryId(" _                      & m_intCounter & ") VALUE=" & _                      intID & " NAME=" & strName & _                      ">" & _                      strName & "</OPTION>" & _                      vbCrLf)       rsCat.MoveNext       m_intCounter = m_intCounter + 1    Loop     If Err.Number <> 0 Then       ' Return friendly error message to the user.       Response.Write(ERROR_GETTING_CATEGORIES)       Err.Clear    End If End Sub </SCRIPT> 

We start by marking the page as transactional using the TRANSACTION directive. Because transaction processing does add some overhead, you should mark pages as transactional only if they might need to perform special processing based on the transaction outcome or if they directly modify managed resources, such as databases.

A large portion of the code is devoted to constructing a data entry form. The main point of interest here is that the form is initialized using data retrieved from our business objects. The data is retrieved in pagewide variables by calling the functions VerifyUserByEmail and AdUnitPrice, as shown here:

 <%    ' ASP Variables    ' Module-level variables used throughout the page    Dim m_strEmail, m_strLastName, m_strFirstName, m_strAddress, _       m_strCity, m_strState, m_strPostalCode, m_strPhoneNumber, _       m_strCountry, m_arrCategory(), m_unitPrice(), _       m_intNavBarLeft, m_intNavBarTop, m_intCounter, m_strPassword    VerifyUserByEmail    AdUnitPrice %> 

Once the variables have been initialized, the ASP "=" directive can be used to write the variable value into the Web page returned to the client. For example, the following code initializes the value of a text input field with the current e-mail address of a customer:

 <INPUT CLASS=text ID=strEmail readOnly NAME=strEmail      TYPE=TEXT SIZE=36 VALUE="<%= m_strEmail %>"></INPUT> 

The server-side script functions VerifyUserByEmail and AdUnitPrice are responsible for creating and calling Island Hopper business objects. The objects are created by calling the Server CreateObject method. You might also notice that error handling is a little different in the script code than in the Visual Basic code we've looked at. In VBScript, you cannot jump to an error handler. All you can do is continue with the next line of code and examine the Err object for error conditions. When an error occurs, you can write a message into the Web page returned to the user. The following code from AdUnitPrice demonstrates this technique:

 Dim objProduct On Error Resume Next ' Create the unitPrice array. Redim m_unitPrice(2) ' Create an instance of db_ProductC object. Set objProduct = Server.CreateObject("db_ProductC.Product") ' Check for errors in creating the object. ' Display error message if an error occurs. If Err.Number <> 0 Then    Response.Write(ERROR_GETTING_PRICES)    Err.Clear    Exit Sub End If 

The ADENTRY.ASP page is responsible for setting up the data entry form for new advertisements. When the user submits a new ad, the form is processed by the ADCONFIRM.ASP page. The following code from the InsertAd method shows how to abort a transaction from script code using the object context's SetAbort method if an error occurs:

 Sub InsertAd    Dim objAd, objCustomer    Dim strResultID    On Error Resume Next    ' Create bus_Ad component.    Set objAd = Server.CreateObject("bus_AdC.Ad")    ' Verify that object was created.    If Err.Number <> 0 Then       strErrorMessage = ERROR_CREATING_BUS_AD & "<BR>"       GetObjectContext.SetAbort       Err.Clear    End If    .    .    . End Sub 

The ADCONFIRM.ASP page also implements the OnTransactionCommit and OnTransactionAbort event handlers, to adjust the Web-page contents depending on whether the transaction is successful, as shown here:

 '******************************************************************* 'Purpose: Verifies successful transaction through MTS '******************************************************************* Sub OnTransactionCommit()     response.write("<DIV CLASS=box-label FONT SIZE=3 " & _         "STYLE='position:absolute; top:75; left:120'>" & _         AD_PLACED_SUCCESSFULLY & m_strResultID & "</DIV>") End Sub '******************************************************************* 'Purpose: Reports unsuccessful transaction through MTS '******************************************************************* Sub OnTransactionAbort()    response.write ("<DIV CLASS=box-label FONT SIZE=4 " & _       "STYLE='position:absolute; top:75; left:25'>" & _       ERROR_INSERTING_AD & "<BR>" & strErrorMessage & "</DIV>") End Sub 

The other ASP pages in the Island Hopper application use the same techniques as ADENTRY.ASP and ADCONFIRM.ASP to communicate with business objects and return information to user machines. Figure 11-4 shows the relationships between the ASP pages in the Island Hopper application.

click to view at full size.

Figure 11-4. The Island Hopper application architecture.



Designing Component-Based Applications
Designing Component-Based Applications
ISBN: 0735605238
EAN: 2147483647
Year: 1997
Pages: 98
Authors: Mary Kirtland

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net