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).
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.
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.
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. |
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.
<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> the electronic </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-------------------------->
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.
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 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.
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 (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.
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 = "   Your card has been added.<br>" sResponse = "   Your card has been added.<br>" sResponse = sResponse & "   To view your card," sResponse = sResponse & " click the Post Office Toolbar. <br>" sResponse = sResponse & "<br>   When prompted " sResponse = sResponse & "for a P.O. Box enter the following code:" sResponse = sResponse & " (without quotes)<BR><Pre> "" sResponse = sResponse & oId.UniqueString & ""</pre><br>" sResponse = sResponse & "   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 = "    The 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 = "   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> the e-card shop </p> <p class=title2><%=Session("ResponseMsg")%></p> <p class=title3><%=Session("ResponseMsg")%></p> <% else %> <h1> <%=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.
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.
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.
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 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.
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.
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 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>   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.
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.
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.
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.