Skip to main content.

Web Based Programming Tutorials

Homepage | Forum - Join the forum to discuss anything related to programming! | Programming Resources

Web Database Developer's Guide with Visual Basic 5

World Wide Web Database Developer's Guide with Visual Basic 5




-25-

A Card Shop Application Using ASP

In this chapter, you will learn techniques for building a complete Internet application. You will build a complete electronic card shop implemented by Active Server Pages (ASPs).

Overview

To put together all the techniques you have learned so far, we have built a database-enabled Internet application using ASPs. In addition to ASPs, the site uses Visual Basic 5 ActiveX components, Active Data Objects (ADOs), and a Microsoft Access database.

We created a simple card shop application similar to applications that most Net junkies probably have seen. This Card Shop site enables users to send free, virtual Internet greetings to their friends and loved ones. In case you have not seen this type of site before, the idea is simple: A would-be card sender hits the site and builds a card from a set of possible options. The card then is delivered via e-mail or is picked up at a "post office" by the recipient; this site follows the post office approach. The recipient must log onto a specified URL with a system-generated postal code. This code is given to the sender when he places the card order. The recipient is presented with the greeting card after he successfully enters the postal code. The Electronic Card Shop was designed to show off some of the server-side capabilities discussed so far in this book. These capabilities include using the built-in ASP objects, ADO database connectivity, and server-side and client-side ActiveX controls. This application also offers some innovative HTML techniques using styles, tables, forms, and objects.

How We Started

We used InterDev 1.0 to develop a skeleton of the Card Shop site. For the skeleton, we used the Departmental Site Wizard, which enabled us to create an instant site complete with a prebuilt navigation bar and a set of automatic, customizable feedback pages. The wizard provided an efficient way to quickly build a set of connected pages. Within minutes, a shell was constructed on which we could base our Electronic Card Shop site. We were able to choose a theme, and all the pages created followed that theme by using common graphics and style sheets. After a skeleton and general look and feel were generated, we could focus on the real importance of the site: showing off ASP capabilities. We decided to store the data for feedback and card orders in an Access database, which offered the simplicity we needed for this example.

Site Architecture

Although the Site Wizard does a good job of laying out the groundwork, a considerable amount of thought still must go into the planning of any site, such as directory organization, media management, and team-development concerns. Table 25.1 lists the major objects used in the site and the function of each.

Table 25.1. Site Objects.

Object Description
birthday.asp The actual card the recipient sees. The information provided by the sender generates a unique card for the birthday boy or girl.
card.mdb The Access database that stores all the card orders and feedback entries.
card shop.asp The home page, complete with site descriptions, card-ordering and pickup instructions, links to other pages, and credits.
default.htm The default page for IIS. Contains a simple tag that refreshes card shop.asp.
feedback.asp Here, users can enter comments about the site or the cards.
footer.inc An include file that contains the HTML code to list the Webmaster comments (author, date last modified, and so on) at the bottom of each page.
generate.dll The ActiveX component that creates a unique ID for each card order.
global.asa The file that contains variables or scripts that have application- or session-level scope. We changed the default session time-out variable here to 10 minutes.
navigation.inc An include file that contains the HTML code to implement the navigation bar as a table with links in each cell.
order.asp Here, card senders place an order for each card. They fill out a form, and the required fields are stored in a database for future retrieval.
pobox.asp The page that recipients use to receive their greeting cards. After successfully entering the post office code, users are directed to the appropriate greeting-card page.
response.asp This page delivers a response to the user after he enters comments from the feedback page, places an order for an electronic card, or enters a post office code that does not match any card orders. Most database interaction for the site occurs here.


Figure 25.1 shows how the major ASP pages are linked together and the general workflow of the application.

FIGURE 25.1. The Card Shop site architecture.

NOTE: All the files referenced in this chapter are located on the CD-ROM that accompanies this book. To construct and use the source code for this site, you must be aware that the code assumes that you have set up a DSN to the Card Shop database (card.mdb) called ElectronicCard and that you have set up a virtual directory in IIS called Card shop.

The Electronic Card Shop Home Page

Our default page in IIS is set to be default.htm, but we wanted to be able to run ASP scripts on the home page. Because ASP scripts cannot be run in standard .htm files, we placed a simple <meta> tag in default.htm that would immediately load our ASP home page (card shop.asp). Listing 25.1 shows the <meta> tag we used.

Listing 25.1. Our <meta> tag.

<HTML>
<HEAD>
<TITLE>The Electronic Card Shop</TITLE>

      <META HTTP-EQUIV="Refresh" CONTENT="0; URL=card shop.asp">

</HEAD>
<BODY>
</BODY>
</HTML>

The HTTP-EQUIV parameter of the <meta> tag binds the element in the CONTENT parameter to the desired HTTP response header. The code in Listing 25.1 tells the browser to wait zero seconds before refreshing the URL at card shop.asp. The <meta> tag is used for many types of applications. Other possible uses include providing keyword information for search engines and specifying character sets used on a particular page.

The home page for the card shop (card shop.asp) presents the purpose of the site and provides links to the ordering, receiving, and feedback sections of the site. It checks the browser's name to determine whether the client can display styles. It also uses Server-Side Includes for its navigational bar and Webmaster comments section. Figure 25.2 shows the home page.

One interesting feature of the home page is the use of style sheets. The home page, as well as the other pages, use the <link> tag to specify sets of styles that are common across similar pages. The Departmental Wizard in InterDev generated the original styles. Then simple modifications to a style sheet file can produce dramatic effects. The card shop.asp interrogates the browser-type component to determine whether the client browser is Microsoft Internet Explorer. If so, the user should be able to render text that uses style definitions. Listing 25.2 shows a fragment of the code from card shop.asp.

FIGURE 25.2. The Electronic Card Shop home page.

Listing 25.2. A fragment of the card shop.asp code.


<!------------------Start Style Sheet Call-------------------->
<LINK REL=STYLESHEET HREF="./styles/style1.css">
<!------------------End Style Sheet Call---------------------->

<!----------------------Start Title---------------------------->
<title>The Electronic Card Shop Site</title>
<!----------------------End Title---------------------------->

<meta name="GENERATOR" content="Microsoft InterDev 1.0">
</head>

<!--------------------Start Background------------------------>
<body background="./images/background/back1.jpg"
alink="#FF000" bgcolor="#FFFFFF" topmargin=0 leftmargin=0>
<img src="./images/headings/header1.gif" align="bottom" >
<!--------------------End Background-------------------------->

<!--------------------Start Page Name------------------------>
<%

`-- If we are using IE 3.0 or above, use a combination
`   of styles to offer a cool effect for the page title.

`   Determine the type of browser
Set obc = Server.CreateObject("MSWC.BrowserType")
if obc.Browser = "IE" Then %>

    <p class=title>&nbspthe electronic&nbsp</p>
    <p class=title2>Card Shop</p>
    <p class=title3>Card Shop</p>

<% else %>

   <h1>The Electronic Card Shop</h1>

<%End If%>

<!----------------------End Page Name-------------------------->

NOTE: Microsoft's Internet Explorer 3.x currently is the only browser that supports style sheets. Because of the recent acceptance of the cascading style sheet specification, though, other browsers are sure to follow.

As you can see, the script in Listing 25.2 checks the Browser property of the BrowserType object to see whether it is IE. If so, a set of styles defined in styles/styles1.css provides an interesting effect for our page title. The styles used for the title are descendent classes of the <P> style and are shown in Listing 25.3.

Listing 25.3. Title styles from styles1.css.

P {
    margin-left: 0px;
    font: 9pt/11pt "Arial";
    color: black;
    background: transparent;
    }

.title {
        font:12pt Arial Black;
        color:white;
        background:black
        }

.title2 {
         font:32pt Arial Black;
         margin-left:15px;
         margin-top:-10px
         }

.title3 {
         font:32pt Arial Black;
         color:red;
         margin-left:13px;
         margin-top:-44px
         }

The two classes title2 and title3 create the cool shadowing effect. The shadow is rendered first (P.title2). Then, by manipulating the margin-top parameter in the P.title3 class, the red text overlays the black text and produces the desired results.


RESOURCE: Using style sheets enables a more robust use of fonts and page layout. You can find more information on using cascading style sheets at
www.w3.org/pub/WWW/Style/

or




www.microsoft.com/workshop/author/



Another interesting feature of this page is the use of Server-Side Includes. SSIs are used for content that is common on each of the pages. SSIs enable you to easily maintain and modify this content without visiting each page. Listing 25.4 shows the include statement for the navigation bar.

Listing 25.4. The include statement for the navigation bar.

<!------------------Start Navigation Bar---------------------->
<!--#include virtual="/Card shop/navigation.inc"-->

<!------------------End Navigation Bar------------------------>

The server evaluates the statement in Listing 25.4 before sending the page to the client browser. Listing 25.5 shows the contents of the navigation include file, which are sent to the browser instead of the previous include tag.

Listing 25.5. The navigation include file.

<p><table bgcolor=silver cellspacing=1 cellpadding=2 width=100%>
<tr>
     <td align=center valign=center background="./images/Navigation/Nav2.jpg">
        <a href="Card shop.asp"><B>Home</B></a>
     <td align=center valign=center background="./images/navigation/Nav2.jpg">
        <a href="birthday.asp"><B>View Example Card</B></a>
     <td align=center valign=center background="./images/navigation/Nav2.jpg">
        <a href="order.asp"><B>Order Card</B></a>
     <td align=center valign=center background="./images/navigation/Nav2.jpg">
        <a href="pobox.asp"><B>Post Office</B></a>
     <td align=center valign=center background="./images/navigation/Nav2.jpg">
         <a href="feedback.asp"><B>Feedback</B></a>
</table></p>

The navigation bar is constructed of a table with a single row that spans the width of the page's margins. Each cell of the table holds a hyperlink to another page. The background of each cell is provided by a simple, shaded, square image. This table approach to a navigation bar eliminates the need to create customized buttons for each link and makes adding or removing "nav-buttons" a breeze. The colors of the links (those visited and unvisited) also are maintained in the style-sheet file for the document.

The Webmaster comment section at the bottom of all pages also is implemented by using these technique with SSIs.

The Order Page

The order page is an entry form for sending an Internet card to a friend or loved one. It contains the same background images, title styles, and include references for the navigational bar and Webmaster comments. The order page also holds a form for entering all the fields of a card-order table:

Figure 25.3 shows a card-order form that has been filled out and is ready to be submitted.

FIGURE 25.3. The E-Card Shop Order Card page.

The form the InterDev wizard generated uses the HTML <pre> tag to denote preformatted text. Many people overlook the <pre> tag when designing Web pages. The <pre> tag renders all text in a fixed-width font. The advantage of this tag is that you can format the desired output within the <pre> and </pre> delimiters as you want it to display onscreen. Line breaks occur where you place them, and all spacing is preserved. Some other HTML items, such as images, font changes, and paragraphs are not supported within the <pre> tag, however.


NOTE: Microsoft HTML documentation specifies that the <PRE> tag is included for backward compatibility for use with older browsers, and they recommend using the newer monospaced tags. One advantage of the <pre> tag is that some elements can be preformatted. In this chapter, you are formatting <input> elements. Interestingly enough, the InterDev 1.0 Departmental Wizard consistently uses this now outdated <PRE> tag when generating most of its HTML forms. You will see more of the <pre> tag used throughout the site.

Listing 25.6 shows a section of ASP code from the order page.

Listing 25.6. Some ASP code from the order page.

<%
`Set the session variable to identify the response type
Session("ResponseType") = "Order"
Session("ResponseMsg") = "Thank you for your order!"
%>

Notice that this code sets session-level variables that will be used later by the response page when the form is posted. As you will see in later sections, the response page is referenced by the ACTION parameter of all the card shop forms. The response page is used to perform database lookups and inserts, and it provides information to the user after those operations are complete.

Listing 25.7 shows the HTML form declaration.

Listing 25.7. The HTML form declaration.

<!----------------------Begin Form---------------------------->
<FORM ACTION=response.asp METHOD="POST" name="OrderForm" onSubmit=getDate>

<pre>
      Recipient        <input type="text" size="50" 
                              maxlength="50" name="txtRecipient">

      Recipient E-Mail  <input type="text" size="50" 
                               maxlength="50" name="txtREMail">

      Sender           <input type="text" size="50" maxlength="50" 					               Âname="txtSender">

      Sender E-Mail    <input type="text" size="50" maxlength="50" 		               		               Âname="txtSEMail">

      Card Greeting<BR>
                       <textarea name="txtGreeting" rows="3" cols="70" 
                                 align="top"></textarea>
</pre>

<%
     Set oBrowser = Server.CreateObject("MSWC.BrowserType")
     If oBrowser.ActiveXcontrols = "True" Then %>
<pre>      Card Send Date   <input type="hidden" 
                                   name="txtDate"><OBJECT ID="DatePicker1"
                       CLASSID="CLSID:E6AE6F49-63EB-11D0-85CE-444553540000"
                              CODEBASE="DatePicker.CAB#version=1,0,0,0"
                              ALIGN=top name="DatePicker1"></OBJECT></pre>
<%   Else%>
<pre>      Card Send Date   <input type="text" size="20" maxlength="20" 
                                   name="txtDate"></pre>
<%   End If
     Set oBrowser = Nothing%>

</Form>
<!------------------------End Form------------------------>

The interesting feature of this particular form is the use of the ActiveX Datepicker control, which was mentioned in Chapter 16, "Creating ActiveX Controls for the Web with VB 5." After a set of desired input fields is displayed, a BrowserType object is created. The ActiveXcontrols property of this object specifies whether the client browser can host these controls. If it can, an object tag is used to insert the desired control. Also, we create a hidden text-input box that stores the date chosen from the DatePicker. If the person ordering the card is using a browser that does not support ActiveX controls, a normal text-input box is presented. The input boxes were intentionally created with the same name (txtDate) to lighten the code required to post this data.

Before posting the results of the entry form to the response page, we run a preliminary procedure called getDate. The getDate function transfers the date value selected in the DatePicker1 control to the hidden input object (txtDate) by using VBScript and the object model of the IE browser. The script is placed inside a comment so that other browsers will ignore this code. The following listing displays the VBScript for the getDate function.

Listing 25.8. The getDate function

<SCRIPT language="VBScript">
<!-- hide this script from technically challenged browsers
Sub getDate()
   `-- This procedure copies the date in the DatePicker Control to
   `  the hidden txtDate field on the form so that the Response
   `  object will read it in response.asp
   document.OrderForm.txtDate.value = document.OrderForm.DatePicker1.TextDate
End Sub
-->
</SCRIPT>

The Feedback Page

The feedback page (feedback.asp) enables users to send comments about the cards or the site as a whole. These comments can be problems, complaints, or general good cheer directed toward the Webmasters. Feedback entries are stored in a separate table in the Card Shop database. Figure 25.4 shows the Card Shop's feedback page.

FIGURE 25.4. The feedback page.

The feedback page contains a simple HTML form in which the post method is directed to the response page (with the ACTION=response.asp parameter in the form tag) in the same manner as the order-form page. Listing 25.9 shows the code that sets the session-level variables to hold the state information required by the ASP script in the response page.

Listing 25.9. Setting the session-level variables.

<%
`-- Set the session variables to be used by the response form
`  to identify the calling form and provide a header to display
Session("ResponseType") = "Feedback"
Session("ResponseMsg") = "Feedback Confirmation"
%>

As shown in Listing 25.9, the session-level variable ResponseType contains the string "Feedback". As in the order page, this string tells the ASP code in the response page what type of database update to perform. The ResponseMsg string displays a header on the response page when it is called.

This page uses the same browser check and styles you saw in the other pages. Otherwise, it is a simple HTML static document that receives information via a simple form.


TIP: The feedback page again uses the <pre> tag to display some text-input boxes in a uniform manner. If the fixed-width font is not your thing, you could have accomplished the same effect with a two-column, four-row table. The alignment options in the table support many customizable layout combinations. The preformatting tag gets the job done but restricts you to using a rather dull font.

The Response Page

The response page (response.asp) posts entered data to the database for the forms on the order and feedback pages and performs a lookup for the post office. The response page also provides information on the results of these operations. If the user enters comments in the feedback page, for example, this page attempts to store that information in the Feedback table of the database. If that operation is successful, a message similar to the one in Figure 25.5 appears, thanking the user for the comments.

FIGURE 25.5. Feedback confirmation via the response page.

If the user submits an order for a new card, the response also handles the database insert. In this case, the ASP source uses a server-side ActiveX component called Generate.ID. This component's single purpose is to generate a unique string ID that will be used as a key to a single card order. This key is required when the card recipient visits to pick up the card. Figure 25.6 shows the response page when called from the order form.

FIGURE 25.6.The response page showing a successful card order.

Notice that the response page in Figure 25.6 displays the unique identifier for this card order. This code can be copied to a mail message to the person. Simply click the person's name highlighted by the red link to generate a mail message in your native mail package. In order for the recipient to get the e-card, you must provide the URL to the site and paste the P.O. Box code shown on the response page. An automatic mailing is not currently available. This is a great example of when you could use another ActiveX component to enhance this application.

The response page posts data to the database by using a method similar to the approach used to add a time-sheet entry in the srvtimes.asp example in Chapter 22, "Writing Server-Side Applications with VB 5 ActiveX Components." First, we must create a connection to our ODBC data source. Then we can perform any required queries to add or look up information in our Card Shop database. Listing 25.10 shows the complete code used for the response Active Server Page.

Listing 25.10. The response.asp ASP script.

<SCRIPT LANGUAGE=VBScript RUNAT=Server>
Function getResponse
`-- Shared routine that is used to add both the feedback
`  and the electronic card order records, and perform a P.O. Box
`  lookup.
`
    `Create an instance of the ADO object
    Set oDBCard = Server.CreateObject("ADODB.Connection")

    `Open the database
    oDBCard.Open "ElectronicCard"

    `Create an ADO recordset to add a new record
    set rsResponse = CreateObject("ADODB.Recordset")

    `Set the Recordset Properties
    rsResponse.CursorType = 0
    rsResponse.LockType = adLockOptimistic
    rsResponse.ActiveConnection = oDBCard

    `Check if this is an Order or a FeedBack
    Select Case Session("ResponseType")

    Case "Order"
        `--This is a new card order - Get a unique string to use as an ID
        `  using the ActiveX component Generate.Id
        Set oId = Server.CreateObject("Generate.Id")

        `-- Set the size of our ID string
        oID.Size = 15
        lFlag = oId.GenerateID

        `-- Check for Errors
        If lFlag <> 0 Then
            `Error found set response variable to display the error message
            sResponse = oId.ErrorMsg
        Else
            `All is well - initialize a CardOrder recordset
            rsResponse.Source = "SELECT * FROM CardOrder"

            `-- Open the recordset
            rsResponse.Open

            `-- Check to make sure Updates are supported
            sResponse = "<H2>Sorry your order was not added.
                         ÂInvalid server cursor.</H2>"
            If rsResponse.Supports(adUpdate) Then

                `-- Add a new record
                rsResponse.AddNew

                `-- Get our ID from the object
                rsResponse("ID") = oId.UniqueString

                `-- Set the data values from the form
                rsResponse("Recipient") = Trim(Request.Form("txtRecipient"))
                rsResponse("Email") = Trim(Request.Form("txtREMail"))
                rsResponse("Sender") = Trim(Request.Form("txtSender"))
                rsResponse("SenderEmail") = Trim(Request.Form("txtSEMail"))
                `-- Only Birthday card types are currently available
                rsResponse("CardType") = "Birthday"
                rsResponse("Greeting") = Trim(Request.Form("txtGreeting"))
                rsResponse("CardDate") = Trim(CStr(Request.Form("txtDate")))

                `-- Complete the add operation
                rsResponse.Update
            End If

            `-- Build the response string
            sResponse = "&nbsp;&nbsp&nbsp;&nbsp;Your card has been added.<br>"
            sResponse = "&nbsp;&nbsp&nbsp;&nbsp;Your card has been added.<br>"
            sResponse = sResponse & "&nbsp;&nbsp&nbsp;&nbsp;To view your card,"
            sResponse = sResponse & " click the Post Office Toolbar. <br>"
            sResponse = sResponse & "<br>&nbsp;&nbsp&nbsp;&nbsp;When prompted "
            sResponse = sResponse & "for a P.O. Box enter the following code:"
            sResponse = sResponse & " (without quotes)<BR><Pre>        &quot;"
            sResponse = sResponse &  oId.UniqueString & "&quot;</pre><br>"
            sResponse = sResponse & "&nbsp;&nbsp&nbsp;&nbsp;Send this "
            sResponse = sResponse & "information to <a HREF=mailto:"
            sResponse = sResponse & & Trim(Request.Form("txtREMail")) & ">"
            sResponse = sResponse & Trim(Request.Form("txtRecipient")) & "</a>"
            sResponse = sResponse & " on " & Trim(Request.Form("txtDate")) 
            sResponse = sResponse & "</br>"

        End If
        Set oId = Nothing
    Case "Feedback"
        `-- This is a feedback entry
        `  Initialize a feedback recordset
        rsResponse.Source = "SELECT * FROM Feedback"

        `-- Open the Recordset
        rsResponse.Open

        `-- Check to make sure Updates are supported
        sResponse = "<H2>Sorry your feedback was not added.
                     Invalid server cursor.</H2>"
        If rsResponse.Supports(adUpdate) Then

            `-- Add a new record
            rsResponse.AddNew
            `-- Set the data values from the form
            `   Note: In this script we do not specify the Form object.
            `         If we had objects with the same name then the first
            `         found would be returned.

            If Trim(Request("UserName")) = "" Then
                rsResponse("Name") = "Anonymous"
            Else
                rsResponse("Name") = Trim(Request("UserName"))
            End If

            rsResponse("Email") = Trim(Request("UserEmail"))
            rsResponse("Tel") = Trim(Request("UserTel"))
            rsResponse("Fax") = Trim(Request("UserFax"))
            rsResponse("CommentType") = Trim(Request("MessageType"))
            If Trim(Request("Subject")) = "(Other)" Then
                rsResponse("CommentArea") = Trim(Request("SubjectOther"))
            Else
                rsResponse("CommentArea") = Trim(Request("Subject"))
            End If
            rsResponse("Comment") = Trim(Request("Comments"))
            rsResponse("CommentDate") = Now()

            `-- Complete the add operation
            rsResponse.Update
        End If

        `-- Build the response string
        sResponse = "&nbsp;&nbsp&nbsp;&nbspThe information you supplied has"
        sResponse = sResponse & "been saved. Thank you for your feedback."

    Case "POBox Lookup"
        `-- This is a lookup from the POBox form
        sSQL = "SELECT CardType FROM CardOrder WHERE ID='"
        sSQL = sSQL & Trim(Request("txtPOBox")) & "`"
        rsResponse.Source = sSQL

        `-- Open the Recordset
        rsResponse.Open

        If not rsResponse.EOF Then
            `-- Determine the type of card to present,
            `  set the appropriate session variable and
            `  redirect to that card page.
            Select Case rsResponse("CardType")
                Case "Birthday"
                    Session("POBoxCode") = Trim(Request("txtPOBox"))
                    Response.Redirect "/Card shop/birthday.asp"
                `-- put other card types here when available
                Case Else
            End Select
        Else
            `-- Build the response string
            sResponse = "&nbsp;&nbsp&nbsp;&nbsp; No card was found with "
            sResponse = sResponse & "P.O. Box code: "
            sResponse = sResponse & Trim(Request("txtPOBox"))
        End If

    End Select

    `-- Clean up recordset and database connections
    If Not(rsResponse is Nothing) Then
        rsResponse.Close
        Set rsResponse = Nothing
    End If
    If Not(oDBCard is Nothing) Then
        oDBCard.Close
        Set oDBCard = Nothing
    End If

    `-- Return the response string to the calling script
    getResponse = sResponse

End Function
</SCRIPT>
<%
   sMsg = getResponse
%>

<!--------------Card Shop Response Page---------------------->
<!-- Skeleton Generated by Visual InterDev.                  -->
<!--   Page Modified by: Mark Spenik & Troy Rackley          -->
<!--   Date: Jan. 14, 1997                                   -->
<!--      World Wide Web Database Developer's Guide Using VB -->
<!--                                                         -->

<html>
<head>

<!------------------Start Style Sheet Call-------------------->
<LINK REL=STYLESHEET HREF="./styles/style2.css">
<!------------------End Style Sheet Call---------------------->

<!--------------------Start Page Title------------------------>
<title> <%=Session("ResponseMsg")%> </title>
<!--------------------End Page Title-------------------------->

<meta name="GENERATOR" content="Microsoft InterDev 1.0">
</head>

<!--------------------Start Background---------------------->
<body background="./images/Background/back2.jpg"
alink="#FF000" bgcolor="#FFFFFF" topmargin=25 leftmargin=0>
<!----------------------End Background------------------------>

<!--------------------Start Page Name------------------------>
<%

`-- If we are using IE 3.0 or above, use a combination
`   of styles to offer a cool effect for the page title.

`   Determine the type of browser
Set obc = Server.CreateObject("MSWC.BrowserType")
if obc.Browser = "IE" Then %>

    <p class=title>&nbsp;the e-card shop&nbsp</p>
    <p class=title2><%=Session("ResponseMsg")%></p>
    <p class=title3><%=Session("ResponseMsg")%></p>

<% else %>

   <h1>&nbsp;&nbsp;<%=Session("ResponseMsg")%></h1>

<%End If%>
<!----------------------End Page Name-------------------------->

<!------------------Start Navigation Bar---------------------->
<!--#include virtual="/Card shop/navigation.inc"-->
<!------------------End Navigation Bar------------------------>

<!------------------Begin Response Statement------------------>
<p>
<STRONG>
<%=sMsg%>
</STRONG>
</p>
<!------------------End Response Statement-------------------->

<p>
<img src="./images/rules/rule1.gif" alt="[HRule Image]" 
     align="bottom" width="650" height="25">
</p>

<!----------------Begin WebMaster Statement------------------>
<!--#include virtual="/Card shop/footer.inc"-->
<!------------------End WebMaster Statement-------------------->
<!-- #include virtual="/ASPSamp/Samples/adovbs.inc" -->
</body>
</html>

At the beginning of the function getResponse, we first create a connection object, connect to the Card Shop database, and then create a Recordset object. We then set the required Recordset properties to prepare it for use.

The case structure then determines what type of job we must perform based on the value in the ResponseType session variable. Each calling form provides a response type. The available response types are Order, Feedback, and POBox Lookup.

The Order Response

If the user is adding a new card order, an insert must be performed into the CardOrder table of our database. The Generate.ID component helps us construct a unique string to serve as the key to this record. The recipient also will use this item to pick up the card from the post office. First, we must create a Generate.ID object called oID. Then we set the desired length of the string to generate to 15 (characters). Next, we call the object's GenerateID function. This function returns a zero if all went well. If an error occurred, that error may be read from the object's Error property. All that is left to do is to acquire the ID from the oID object's UniqueString property. A successful generation populates this property with an ID that is the length specified in the Size property. Listing 25.11 contains the complete code of the ID class of the Generate component.

Listing 25.11. The ID class.

Option Explicit

Private m_nSize As Integer `The size of the ID
Private m_sID As String    `The actual ID string
Private m_sError As String `An error string if there is a problem

Private Sub Class_Initialize()
   `-- This occurs when a new instance of this object
   `  is created
   Randomize    ` Initialize random-number generator.
   m_nSize = 10 ` Set a default size for an ID
End Sub

Public Property Get Size() As Integer
    Size = m_nSize
End Property

Public Property Let Size(ByVal nData As Integer)
    m_nSize = nData
End Property

Public Property Get Error() As String
    Error = m_sError
End Property

Public Property Get UniqueString() As String
    UniqueString = m_sID
End Property

Public Function GenerateID() As Long
Dim lStatus As Long
Dim i As Integer
Dim nRandom As Integer
Dim sID As String
Dim sChar As String

On Error GoTo GenerateID_Error

    For i = 1 To m_nSize
        `-- Generate a random number from 1 to 3 to
        ` determine which character set to use:
        ` 0-9, A-Z, or a-z
        nRandom = GetRandomInt(1, 3)
        Select Case nRandom
            Case 1
                sChar = Chr$(GetRandomInt(Asc("0"), Asc("9")))
            Case 2
                sChar = Chr$(GetRandomInt(Asc("A"), Asc("Z")))
            Case 3
                sChar = Chr$(GetRandomInt(Asc("a"), Asc("z")))
            Case Else
                sChar = "-"
        End Select

        m_sID = m_sID & sChar

    Next

GenerateID_Exit:
    GenerateID = lStatus
    Exit Function

GenerateID_Error:
    lStatus = 1
    m_sError = "Error generating ID: " & Err.Description
    Resume GenerateID_Exit

End Function

Public Function GetRandomInt(ByVal nLowerbound As Integer, 
                             ByVal nUpperbound As Integer) As Integer
   `-- Generate a random integer in the range
   `  of: Lowerbound to Upperbound
   GetRandomInt = Int((nUpperbound - nLowerbound + 1) * Rnd + nLowerbound)

End Function

The main function in this class is GenerateID. This function contains a loop that iterates from 1 to the Size property. Each iteration through the loop generates a random alpha or numeric character. First, a random number from 1 to 3 is generated. If this number is 1, it generates a random character from the numbers 0 to 9. If the number is 2, it then generates a random letter in the range of uppercase letters--A to Z. Finally, if the original random number is 3, a random character is generated from the lowercase range of a to z. The random character is added to a string until the end of the loop. This string becomes the UniqueString property of this object.

If no errors occur while generating the UniqueString, the response page attempts to add the record to the database. First, a check is performed to ensure that the current database cursor supports updates. Next, we open the recordset and perform an AddNew operation. The fields of a CardOrder record are set from the response object's form variables, and then the recordset's Update method is called. Any default values for fields are set here.


NOTE: Notice that the card type here is set to birthday. At the time of this writing, a birthday card is the only type of card you can send from the Card Shop site.

After all updates, a response message is created to inform the user of the results of the record insertion. The ID generated is provided to the user in this response message, as well as a mailto hyperlink that can be clicked to launch the user's mail application. We finish this case by removing our Generate.ID component instance by setting it equal to Nothing.

The Feedback Response

The response for the feedback is very similar to the order; however, we do not need to use Generate.dll to produce any unique identifiers. The key in our Feedback table is on the Username and CommentDate fields. If the username is left out of the feedback form, we fill it with Anonymous. The CommentDate field is filled with a call to the VBScript Now() function. The remaining fields are pulled directly from the response object and stored in the record. The response string that is built on completion of the update is a simple message thanking the users for their comments.

The Post Office Response

If the response page is being called from the post office, instead of adding a record, we want to ensure that a particular record exists. The postal code from the post office form is used to build a SQL statement to query for a selected record. If it is available, we check the CardType field to determine the page to which the user will be redirected. Because we currently have only one card type (the birthday card), the decision logic is fairly short. This approach simply leads to future expansion.

The ID of this card is stored in a session-level variable (POBoxCode), which is referenced by the respective ASP card page. Then the Redirect method of the response object is called with the correct page to open.

If no card matches that ID, we build a message string. This time, the message states that a record was not found, and the rest of the page is evaluated and sent to the browser.


NOTE: The Redirect method sends an HTML header to the client telling it to launch another URL. Because HTTP protocol requires that all headers be sent before content, you must call Redirect in your script before sending any HTML output. Our HTML beginning content tag (<html>), therefore, must be placed after the getResponse script to avoid a runtime error.

At the end of the script, we clean up any objects that were used. The recordset rsResponse is closed, and its variable is dereferenced by setting it to Nothing. The same is done with our database connection object.

The remainder of the response.asp source code repeats some of the same HTML you saw in the other pages, such as the navigation bar, title styles, and Webmaster comments. The page title (shown in the browser's caption bar as well as above the navigation bar) is filled with the session-level variable ResponseMsg. You might remember that the calling form set this variable. The message displayed below the navigation bar is the one returned from the getResponse function earlier in the file.

The Post Office Page

The post office page is a simple ASP file that contains a form to enter the postal code needed to look up any particular card order. Figure 25.7 shows how a user picks up a card from the post office page.

FIGURE 25.7. The Card Shop post office.

Like the other pages, we check for style capabilities and display the same navigation bar and comments. Listing 25.12 shows the ASP script used by the response page to identify the calling form.

Listing 25.12. Post office session variables and form.

<%
`-- Set the session variables to identify the response type
Session("ResponseType") = "POBox Lookup"
Session("ResponseMsg")  = "No card available"

`-- Clear the session postal code variable
Session("POBoxCode")    = ""
%>

<form ACTION=response.asp METHOD="POST">
     <b>&nbsp;&nbsp;&nbsp;&nbsp Enter P.O. Box code: </b>
     <input type="text" size="20" maxlength="15" name="txtPOBox">
     <input type="submit"> </pre>
</form>

The code in Listing 25.12 also contains the HTML for the simple form. It contains one text-input box called txtPOBox and one Submit button. The post office code given to the user can be pasted or typed into this text field. The Submit button posts this field to the response.asp file.

A Sample Birthday Card

The birthday.asp page is the actual card the recipient sees after he passes the post office security guard. Figure 25.8 shows a sample card generated by this site.

FIGURE 25.8. A sample birthday card.

You can call the birthday page from the response page via a post office lookup or from the link on the navigation bar. If you call this page from the response.asp file, a session variable POBoxCode is filled with a valid card-order ID, and an attempt to look up that card is made. If this variable is blank, we will look up a sample card order provided by the Webmasters. Listing 25.13 provides the complete ASP and HTML code for the birthday page.

Listing 25.13. The complete birthday page listing.

<html>
<!--#include virtual="/ASPSamp/Samples/adovbs.inc"-->
<%

    `-- Check the session variables for a successful
    `   Post-Office login attempt
    If session("POBoxCode") <> ""  then
        sPOBox    = session("POBoxCode")
    Else
        sPOBox    = "Default"
    End if

    `-- Create an instance of the ADO object
    Set oConn = Server.CreateObject("ADODB.Connection")

    `-- Open the database
    oConn.Open "ElectronicCard"

    `-- Build a sql statement to query the card table
    sSQL = "SELECT * FROM CardOrder WHERE ID='" & sPOBox & "`"

    Set rsCard = oConn.Execute(sSQL)

    If not rsCard.EOF Then
        `-- retrieve the data for this card
        sSender      = rsCard("Sender")
        sSenderEmail = rsCard("SenderEmail")
        sGreeting    = rsCard("Greeting")
        sName        = rsCard("Recipient")

        rsCard.Close
    Else
        `-- no card exists with this information
        `  the post office must have made a mistake
    End if

    oConn.Close
    Set oConn  = Nothing
    Set rsCard = Nothing
%>

<head>
<title> Happy Birthday <% =sName %> </title>
<link rel=stylesheet href="./styles/style2.css">
</head>
<body background="./images/background/back2.jpg"
alink="#FF000" bgcolor="#FFFFFF" topmargin=0 leftmargin=0>

<!------------------Start Navigation Bar---------------------->
<!--#include virtual="/Card shop/navigation.inc"-->
<!------------------End Navigation Bar------------------------>

<!------------------Begin Birthday Card---------------------->
<center>
<table cellspacing=0 border=0 WIDTH=100%>
   <tr><td width="33%" align="right" valign="middle">
        <img src="./images/birthday/balloon1.gif" width=105 height=125></td>
   <td width="33%" align="center" valign="middle">
        <img src="./images/birthday/happy.gif" width=300 height=137></td>
   <td width="33%" align="left" valign="middle">
        <img src="./images/birthday/balloon2.gif" width=105 height=125></td>
</tr>
</table>

<br>
<H2><% =sName %>, this birthday wish is for you!!!</H2>
<p><img src="./images/birthday/confetti.gif" alt="[Confetti image]" 
        align="bottom" width="600" height="10"></p>

<p><h3>
<img src="./images/birthday/partyhats.gif" alt="[Party hats image]" 
     align="middle" width="84" height="78">
This card was sent from <a href=<% =sSenderEmail %>><% =sSender %></a>
and <% =sSender %> writes:
<img src="./images/birthday/whistle.gif" alt="[Whistle image]"
     align="middle" width="84" height="78">
</h3></p>

<h3><%
=sGreeting
%></h3>

<p><img src="./images/birthday/confetti.gif" alt="[Confetti image]" 
        align="bottom" width="600" height="10"></p>
</center>
<!--------------------End Birthday Card---------------------->

<!----------------Begin WebMaster Statement------------------>
<!--#include virtual="/Card shop/footer.inc"-->
<!------------------End WebMaster Statement------------------>

</body>
</html>

The page begins with an ASP script that builds a SQL query string to look up a particular card. As mentioned before, if the session variable is empty, we present a default card stored in the CardOrder table with the ID default. Running the Execute method of the connection object produces our recordset. If the session variable is not empty, we store its fields in the local variables sName, sGreeting, sSender, and sSenderEmail. These fields then are output to the browser as inline ASP script when the rest of the HTML is evaluated.

Along with the recipient's name are a few festive birthday graphics. A mailto link is created with the sender's e-mail address so that the recipient can immediately convey his or her gratitude.

Finally, the greeting field is displayed. An interesting aspect of this field is that it can contain HTML tags itself. So, if the sender wants to format his message with HTML, all that is required is that he enter those formatting tags into the greeting textbox when ordering the card. We used <br> tags for hard returns for the greeting of the default card, for example.

The remainder of the card uses simple HTML to display some confetti piles and the usual Webmaster comments.

Summary

Now that you have taken an in-depth tour of our Card Shop site, you might have come up with some ideas to improve it. You already might have noticed the need for other card types. We could design a list of greetings ranging from anniversaries, congratulations, or get-well cards to cards for particular holidays throughout the year. A drop-down listbox would be needed to list the card types on the order page.

Other improvement ideas could include a Preview button on the order page that presents the output to the sender before the card order is submitted. Another idea is to build a custom SMTP component that sends the e-mail notification automatically on the requested day. This component would have to be tailored to each site's mail infrastructure. We also are considering minimizing connections to the database by creating a global connection for each session. This could reduce page-load times when database lookups or inserts are required.


RESOURCE: We continually modify and expand this site to take advantage of new features and standards using Microsoft Internet products. You are invited to check out our recent improvements and even send an e-card in the process. The Electronic Card Shop is housed at our site at
http://www.kscsinc.com/Card shop/


Although we used InterDev for the original structure of this site, most of the code was written in simple text editors. With the new crop of visual WYSIWIG HTML editors on the market, this site could be redone in one of those editors to take advantage of their advanced layout capabilities. Using that approach, monospaced fonts and preformatted text could be replaced by easily modified tables and frames. As you probably know, when performing any type of Web development, the techniques may vary to accomplish similar effects, and the possibilities are endless. This example should have given you some ideas on developing your own Active Web pages and sites, as well as some ammunition for when you need to battle converting any old static sites to more dynamic formats.