Chapter 11

Building a Foundation of Interactivity With Request and Response Objects


The first new business asset the World Wide Web gave us, and the single most important thing about the Web that changes traditional business models, is interactivity.

There are many ways to make a Web site interactive. Forms are the most basic because they use static pages in an interactive, goal-directed manner. In Part III, "Working With Active Server Objects and Components," and Part IV, "Database Management with Active Server Pages," you learn about the other kinds of dynamic content that are not only possible now, but are actually easy to implement.

You will see that this capability can be tapped at two levels: First, ActiveX controls provide dynamic content on static pages; second, Active Server Programs provide dynamic content with dynamic pages. In other words, ActiveX controls provide objects to insert on a page, whereas Active Server Pages provides objects to create pages on-the-fly. With all this power, the ASP developer can now reach the ultimate in interactivity: commercial transactions.

In this chapter you lay a foundation for the next generation of basic interactivity. Even at this fundamental level, we feel strongly that with such a quantum leap in productivity and ease of use, ASP development will spawn an equally abrupt leap in the amount of "interactive variety" on the Web.

In the beginning...

The beginning of interactivity on the Web is the Common Gateway Interface (CGI). In the UNIX world, CGI remains the predominant technology of interactivity. CGI is an open architecture; it can implemented in almost innumerable ways. This open-mindedness comes with a price, however. CGI is difficult to write and maintain, especially for those unfamiliar with UNIX computing. It is processor-intensive: Each CGI call spawns another process for the server, increasing demands on processing resources. Database connectivity remains the most difficult and expensive aspect of CGI interactivity. All of these weaknesses are reasons that CGI has limited appeal to on-line business models.

Arguably the most popular means of implementing CGI is the Practical Extraction and Reporting Language (Perl). For all their shortcomings, these two technologies, CGI and Perl, are modern miracles. CGI worked with stateless servers, and Perl was a powerful language designed to work with text files. They were mutually reinforcing.

There was only one problem: Most Webmasters had little hope of exploiting this synergy, unless they hired a Perl programmer. We used to define a serious Webmaster as one who wasn't intimidated by the CGI/Perl alliance. To a serious Webmaster, interactivity was worth whatever cost it exacted, whether in cash to buy the Perl programs called scripts, or in the exertion necessary to learn a new programming language. This make or buy decision is really tough for most people who face the dilemma. The Web is a technology for all of us, not just the big corporations and the well-trained Information Technology staffs. How maddening it is to be within reach of the prize and yet frustrated by ignorance.

Imagine, for a moment, the number of people who have had a great Web idea but who couldn't implement it. There are at least a dozen things over the last year we would like to have hosted on our Web sites. Multiply this by millions. There is a pent-up supply of creativity behind this block to dynamic interactivity. Active Server Programs will set loose this creativity. It's "scripting for the rest of us." Just imagine what the Web is going to look like when all of those ideas are implemented. It's going to be marvelous.

A Little Story

When one of the authors brought his first commercial Web site, investing.com, on-line in June of 1995, there was one de rigueur interactive feature he had to include, the Guestbook. The author's boss said, "I just want a form that has three lines and a button. How tough can that be?" Three days later after scouring the Internet, changing the source code to work on our site, uploading it to the UNIX server, changing the file permissions, testing, debugging and testing again, he finally had a working Guestbook. Three days. That's one day for each line on the form. The button's a bonus.

Perhaps the single most frustrating thing about working with the Internet is having to be almost equal parts programmer and businessman. Most people don't have time to make them equal parts. The only option is to write as little code as possible and to suffer the consequences.

This quandary leads to one other important point about this section, "In the Beginning..." : In the past, one could not take interactivity for granted. At the processor level, for example, interactivity is a subtle and sophisticated series of events. Looking at the technical details that follow will help you understand what is happening, and it should help you appreciate the luxury of relying on ASP objects to attend to these details on your behalf.

Before you begin to see, in detail, what this liberation force of Active Server Programming will bring, take a look at a typical (and justly famous) guestbook written in Perl by Matt Wright, a very good Perl programmer; many of us owe him much for his ubiquitous gem. By the way, Matt's source code is seven pages long! We're not going to clog up this chapter by listing it all here, but we are going to abstract key code blocks from it. If you've never done this kind of programming before, consider yourself lucky.

ON THE WEB

http://www.quecorp.com/asp—The entire CGI/Perl Guestbook is included at the Web site. For our purposes, we are ignoring the e-mail component of the application as well as, in the CGI version, the feedback form.

The ASP Guestbook components (that you examine shortly) are also included in their entirety at the Web site. The Access 97 database, which is used to store Guestbook entries, is also available to the reader there.

OK, so what does it take to make a Guestbook work using CGI, and why is it so difficult?

CGI Input

So, the first step is to get information from the client to the server. The CGI/Perl technique parses the standard input from the POST method, used in the form found in guestbook.html. Standard input is UNIX-speak for the stream of data used by a program. This stream can be all of the characters entered from a keyboard up to and including the Enter keypress, or it can be the contents of a file that is redirected to a program.

The Guestbook gets its stream of data from the transmission received through the POST method, used by the form in addguest.html. Recall from Chapter 4, "Introducing Active Server Pages," that in the HTTP transaction between the client and the server, something like this stream of data is called the "request body" (a term used often throughout this book). In the case here, this stream is a collection of name/value pairs for each form variable on the Guestbook (for fields left blank, the name variable has no value which is, itself, a value). Here's your first look at the CGI source code (it reads standard input into a memory buffer for the number of characters passed to the server from the client):

# Get the input

read(STDIN, $buffer, $ENV{'CONTENT_LENGTH'});

Next, in Listing 11.1, the program splits these name/value pairs and stores them in an array (another memory buffer that stores values in a row, rather like a stack of kitchen plates). It can tell the boundary between pairs because the & character is used to encode them.

Listing 11.1 GUESTBOOK.PL--An Associative Array of Form Variables and Their Values

# Split the name-value pairs

@pairs = split(/&/, $buffer);

foreach $pair (@pairs) {

($name, $value) = split(/=/, $pair);

Now, each row in the array called @pairs has a string that contains the data entered in the form. Each row might also contain other special characters if the form data itself contains spaces or non-alphanumeric characters like & or %. These non-alphanumeric characters are converted to their hexadecimal ASCII equivalents. An % sign is inserted before these hex numbers to identify them as encoded characters (if the form data itself included a % sign then that character must first be converted to its ASCII value of 25. So that this value is not misinterpreted as the numeric value 25, it too must be encoded as %25). Spaces are always encoded with the plus sign.

If you ever find that you need to imitate the client (e.g., when you set the value of Cookies or you need to append a query string to a URL), rely on the Server Object's URLEncode method to do the dirty work for you. You'll be seeing lots of examples of this technique in Part III, "Working With ActiveX Server Objects and Components."

So, when a Web client program makes a request of a Web server, the client passes everything from the type of client software making the request to the name/value pair of form variables filled in by the user on the client side of the transaction.

For example, when visitors to a Web site fill in the Guestbook form completely, they send the following variables to the Web server: realname, username, url, city, state, country, and comments. Each variable has a value, and the pair is sent to the Web server in a form like this:

realname=Michael+Corning.

The entire string of variable/value pairs is encoded with the ampersand character like this:

realname=Michael+Corning&username=mpc%40investing%2Ecom…

Note the hexadecimal value for @ and . are 40 and 2E respectively, and each is identified as an encoded character with the %. Actually, this is a rather clever scheme that is very efficient. I've heard it said that the best way to tell a true programmer is to look at her tax return. Real programmers file in hex.

A Note from the Author

This highlights an important point as we move from the programmer's world to the business world: Because HTML is a formal specification, a generally accepted standard, all browsers are compelled to send form data to a Web server the same way. It follows that there need be only one program that's necessary to decode the environment variable in the server that contains that string of form data.

It does not follow, however, that there is only one way to produce this program. Programmers live to find new and more efficient ways to do things. It matters not how pedestrian the process is, even something as prosaic as a query string. That's not the point. It's a matter of aesthetics. It's a matter of Quality.

And it's this perfectionism that's so engrained in the programmer's work ethic that has made the Internet what it is today rather than some leftover notes on a white board at the Advanced Research Program Agency in the Department of Defense. To programmers, the Internet is never good enough.

So, back in Listing 11.1, because each name/value pair is separated by an equal sign, the script puts everything to the left of the = in the name field and to the right of the = in the value field. Presto! A decoded query string.

Next, in Listing 11.2, any special non-alphanumeric characters must be identified and converted back to their original values.

Listing 11.2 GUESTBOOK.PL--Decode Non-alphanumeric Characters

# Un-Webify plus signs and %-encoding

$value =~ tr/+/ /;

$value =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg;

$value =~ s/<!--(.|\n)*-->//g;

if ($allow_html != 1) {

$value =~ s/<([^>]|\n)*>//g;

}

$FORM{$name} = $value;

}

Keep in mind that all of this splitting and decoding of strings is going on behind the scenes during ASP processing. As you will see shortly, the QUERY_STRING is the same regardless of the technology driving the server. We will turn to a detailed discussion of the Request Object in the next section, but first take a look at what else is lurking in guestbook.pl.

CGI Output

After the Perl script has figured out exactly what the Guestbook was saying, the program in Listing 11.3 opens the Guestbook's data file. Once open, the data file moves any contents currently in the file into another array (the Perl script is written so that new entries can be inserted or appended to existing data, according to the user's preference). The data file is then immediately closed with the close statement.

It's interesting to note that at this level of programming, and when file I/O is limited to text format, you have to make many design choices that are moot when you use more abstract technology such as database tables. The ASP alternative below in the section "Guestbook Made Easy," uses databases to store guestbook entries, and we leave sorting issues to the database engine; we don't have to worry about it when we first store the entries in a file.

Remember, we're showing you all this so that you appreciate how much work Active Server Pages is saving you.

Listing 11.3 GUESTBOOK.PL--Editing of the Guestbook Entries File

# Begin the Editing of the Guestbook File

open (FILE,"$guestbookreal");

@LINES=<FILE>;

close(FILE);

$SIZE=@LINES;

# Open Link File to Output

open (GUEST,">$guestbookreal");

Listing 11.4, then, writes the form data to the Guestbook data file.

Listing 11.4 GUESTBOOK.PL--Writing the Entries to the Guestbook Entries File

for ($i=0;$i<=$SIZE;$i++) {

$_=$LINES[$i];

if (/<!--begin-->/) {

if ($entry_order eq '1') {

print GUEST "<!--begin-->\n";

}

$FORM{'comments'} =~ s/\cM\n/<br>\n/g;

print GUEST "<b>$FORM{'comments'}</b><br>\n";

if ($FORM{'url'}) {

print GUEST "<a href=\"$FORM{'url'}\">$FORM{'realname'}</a>";

}

else {

print GUEST "$FORM{'realname'}";

}

if ( $FORM{'username'} ){

if ($linkmail eq '1') {

print GUEST " \&lt;<a href=\"mailto:$FORM{'username'}\">";

print GUEST "$FORM{'username'}</a>\&gt;";

}

else {

print GUEST " &lt;$FORM{'username'}&gt;";

}

}

print GUEST "<br>\n";

if ( $FORM{'city'} ){

print GUEST "$FORM{'city'},";

}

if ( $FORM{'state'} ){

print GUEST " $FORM{'state'}";

}

if ( $FORM{'country'} ){

print GUEST " $FORM{'country'}";

}

if ($separator eq '1') {

print GUEST " - $date\n<hr>\n";

}

else {

print GUEST " - $date<p>\n\n";

}

if ($entry_order eq '0') {

print GUEST "<!--begin-->\n";

}

}

else {

print GUEST $_;

}

}

close (GUEST);

Examples of How Much Easier ASP is than CGI

Did you notice all of the embedded HTML code. Again, with Perl and CGI using text file data storage, you have to do everything at the beginning. That is, you store everything you will later need to display the contents of the data file. In one respect, you are not only storing data entered from the form, you are storing the programming necessary to display it later.

Again, with ASP, you don't have to be so meticulous. You can also be more flexible. For example, you might change your mind and not want to display comments entered in the Guestbook in bold type. With ASP, you change the tag once. With the data file, you have to change it many times and only in certain places (e.g., around the comments but not around the name (if the name were also meant to be in bold type)).

Things are looking pretty good, aren't they? With ASP technology you are going to be seeing a lot more interactivity and variety because more people will understand Active Server Pages than currently understand CGI, don't you think?

Ninety-two lines of code! As we said previously, the other five pages of the guestbook.pl script are dedicated to sending an e-mail message to the person who just submitted an entry into the Guestbook and to displaying the contents of the entry for confirmation.

Whew!

Care must be taken when designing interactive systems, even something as simple as a guestbook. The problem arises when there is a mistake in data entry. Haven't you ever filled in a guestbook and submitted it to later regret it? You look at your entry and find an embarrassing misspelling. You accidentally enter the form twice. Something. Anything.

Interactivity that is data-based is much more forgiving. Exploit that power and make the interactive experience more pleasant and less threatening for the visitor. In the short run, such thoughtfulness is a competitive advantage.

Interactive Liberation

In this section, we are going to introduce the basics of the Request and Response Server Objects. You will learn just enough about these remarkable assets to construct a simple guestbook, exactly like the one you just looked at. In Chapter 12, "Enhancing Interactivity with Cookies, Headers, and the Server Object," you will have fun with a really powerful feature of Active Server Pages: their ability to call themselves.

The Request Object

In Chapter 10, "Managing States and Events with Application and Session Objects," you caught your first glimpse of the Request Object in action. There we saw how its Cookies collection was used to give the developer control over ASP sessions. In this section you explore a detailed discussion of this object. You will be going into some of the inner workings of HTTP. If that is material that you have been able to avoid up to this date, refer to the notes and sidebars we provide to fill the gaps in your understanding.

The Request Object is the first intrinsic server object you need to fully understand. It is the connection between the Web client program and the Web server. Across this connection flows information from the following sources: the HTTP QueryString, form data in the HTTP Request body, HTTP Cookies, and predetermined ServerVariables. Because the Request Object accesses these collections in that order, so will we.

Calls to this Server Object take the following generalized form:

Request[.Collection]("variable")

As you can see, it is not necessary to specify which collection you are referring to when using the Request Object. It will search for the variable in all collections until it finds the first one, and it searches in the order given previously. If it finds no occurrence of the variable in any collection, Request returns empty.

If you do specify a collection, however, you ensure two things:

The QueryString Collection

The QueryString collection is the first one the Active Server searches. This is because query strings come from an HTTP GET method, and the GET method is the default request method in HTTP (makes sense because it's the original method appearing in HTTP/0.9 in 1991 the POST method didn't appear until HTTP/1.0 when HTML forms were introduced).

ON THE WEB

For more information about the GET method, see the very readable and historic documents of the early development of Web and the HTTP protocol at

http://www.w3.org/pub/WWW/Protocols/Classic.html

Query strings are the text that follows a question mark in a URL (which, by the way, is the reason they are called "query (or "question") strings"), and can be sent to a Web server two ways:

The first method is, by far, the most common way to create the query string. The second method is used by the Active Server when the client doesn't support (or has disabled) Cookies, and when you want to pass a parameter to an .asp file but don't want the trouble of a form. Session properties could also be used to pass parameters to an .asp file (see Chapter 12), but using the manual form of setting query strings takes less overhead (see note at the end of Chapter 12).

See "URLEncode" for more information about variables passed to the server using URL encoding, in Chapter 12.

A Look Under the Hood of HTTP

HTTP is a stateless protocol. This means that each request from a client requires a new connection to the server. In the strictest implementation of the protocol, this means that an HTML document with text and an image requires two separate transactions with the server: one to get the text and a second connection to retrieve the image.

If the browser is capable, an HTTP connection header can be sent to the server with the keyword "Keep-Alive" so that subsequent calls by the client to the server will use the same TCP network connection. Internet Explorer 3.0 supports this header and owes much of its improvement in performance to this HTTP enhancement.

In HTTP/1.0 there are three primary methods with which a Web client requests information from a Web server: GET, POST, and HEAD. We will focus here on the first two.

As we said, GET is the most often used request method used on the Web. Every hypertext link uses it implicitly. When an HTML form is used, however, the HTML author decides which method to use to implement the Form element's ACTION. With forms there are issues the author needs to face in order to choose wisely. For the ASP developer, knowledge of the difference between these two methods ensures that the use of the Request Object will not yield unexpected results. For example, if you use a POST method in your form, don't expect to find the variable/value pairs to appear in the Request.QueryString collection. This collection is populated only when the form uses the GET method.

The difference lies in the fact that the GET method is basically the read request of HTTP, and the POST method is the write method. That's why the GET method is still the default request method because most of the time you want to merely read the contents of an HTML file somewhere.

Sometimes, however, you only want to read something special, so you include a query string along with your read request. Relying on an appended string is one of the major weaknesses of the GET method. The problem is that the URL and the query string go into an environment variable on the server. Each system administrator sets aside a fixed amount of memory for all environment variables. Many DOS programmers faced the same challenge as well. Because the environment space is limited, so is the size of the query string. There is no specific size to this limit, but there is always some size.

The POST method, on the other hand, does not use a query string to communicate with the server. This frees it from the limitations of the old GET method and enables much more complex form data to be sent to a Web server. With the Post method, content is sent to the server separately from the request to read a URL. For this reason, the server variables CONTENT-TYPE and CONTENT-LENGTH are used by the POST method (and not by the GET method).

Because the POST method is the write request of HTTP, we should not leave it before we note one important attribute of this method: It can write persistent data to the server. In other words, it can (theoretically at this writing) upload files. In November 1995, a Request For Comment was published by researchers at Xerox PARC. Their recommended changes to the HTML Document Type Definition (viz., the formal specification of some aspect of HTML) were simple, and the results of implementing the changes profound. It is important to remember that the POST method can write data to the server, and the GET method can't.

Confused? Let's recap with Table 11.1.

Table 11.1 Who's Who in the Request Object?

Activity

GET

POST

Appends query string to requested URL?

Y

N

Limited in amount of data passed to requested URL?

Y

N

Typically used outside of HTML Forms?

Y

N

Sends form variables to the Request.QueryString collection?

Y

N

Uses the QUERY_STRING server variable?

Y

N

Sends data to requested URL in separate transaction with server?

N

Y

Uses CONTENT-TYPE and CONTENT-LENGTH server variables?

N

Y

Sends form parameters to the Request.Form collection?

N

Y

Can write data to the server?

N

Y

Every time you use a search engine you send a GET request to a server with a query string attached. For example, when you enter the following URL in your Web client

http://guide-p.infoseek.com/Titles?col=WW&sv=IS&_lk=noframes&qt=HTTP+GET

you are telling the InfoSeek search engine to find all files in its database that have the words HTTP and GET. Everything after the ? is the query string and would appear in the QueryString collection of the Request Object. Note, this URL is one long string with no spaces (they've been URL encoded and will be converted back to spaces on the server).

Note there are actually four variables being passed to the server, though we are interested in the variables used to query the InfoSeek database. Note, too, that the qt variable has two values: HTTP and GET. As we will see in a moment, the Request Server Object creates something like a 3-D spreadsheet when it parses an HTTP query string like this, creating a collection of variables and their values and a separate collection for variables that have more than one value.

Now that you have a better understanding of the differences and similarities of GET and POST methods, return to a focused discussion of the QueryString collection.

The full specification of this method includes the way you access variables with multiple values:

Request[.Collection]("variable")[(index)|.Count]

The brackets indicate optional details. You must always specify the variable in the Request collections to be retrieved, and you can optionally specify the collection name and/or information about any "data sets" that might be coming in from the client.

If, for some reason, your application needs to see the URL encoded query string being sent from the client, you can access this string by calling the Request.QueryString object without any parameters at all. The result is the single string of characters received by the Web server and stored in its Request.ServerVariables collection.

What is a "data set?" It is a collection of data with a common parent, and the parent, in turn, is a member of the QueryString collection. An example will make this clear.

Suppose there is a form that is filled out by a financial planner. Financial planners can have many different designations, and they may want to be identified with all of them. So they fill out a membership application form giving their names and addresses. At the bottom of the form is a multi-select list box. If one particularly ambitious planner wants to add yet another acronym to his name, he must select all those designations that currently define his competence.

As a result, the filled-out form is sent to the membership program on the Web server with all the usual personal identification fields along with this special field named "designations" that contains the following values: "CFP," "CPA," and "CFA."

The Request.QueryString collection would have an item for each of the form variables, including one for "designations." The "designations" item would have a collection of its own (sometimes referred to as a "data set") and would return the value three with the call:

Request.QueryString("designations").Count

You could enumerate this data set two ways: First, by simply executing the command

Request.QueryString("designations")

you would see this result: "CFP, CPA, and CFA" (note it is a single comma-delimited string).

Alternatively, you can walk through the data set with the following code block:

<% For I = 1 to Request.QueryString("designations").Count %>

<BR><% =Request.QueryString("designations")(i) %><BR>

<% Next %>

The result is three separate text strings, one for each designation in the collection.

The Form Collection

As we said in the previous section, the POST method in HTTP/1.0 was designed to enable large amounts of data to be passed between client and server. In contrast, the GET method is limited to a fixed number of characters that it can append to the URI (limited by operating environment constraints on the server). This data is processed by the server as if it were STDIN data (such as data entered from a keyboard or redirected from a file). The data passed to the server with the POST method is usually formatted the same way as the GET method (viz., by URLEncoding), but it can also be formatted in a special way when necessary.

There is one other subtle difference in terminology between GET and POST. With the GET method, elements of the query string are referred to as variables, and with the POST method they are parameters. This distinction serves to reinforce the simplicity of GET and the open-ended sophistication of POST.

Fortunately for ASP developers, the way we handle Form and QueryString collections is virtually identical. The most important things to remember about these two collections and the methods that populate them are:

The Response Object

The Response Object is responsible for managing the interaction of the server with the client. The methods of this object include:

All but the Write method are advanced features of this powerful Response Object. In this section, you will learn the two ways this function is performed in .asp files, and you will see examples of when one method is more convenient than the other. We will also make some stylistic suggestions aimed at making your .asp files easier to read and to debug.

As with our preliminary discussion of the Request Object, we introduce enough of these tools of the ASP trade to construct a simple Guestbook. In Chapter 12, "Enhancing Interactivity with Cookies, Headers, and the Server Object," we will cover the salient features of the remaining collections, methods, and properties of the Response and Request Objects.

The Write Method

The most fundamental process of ASP development is writing to the HTML output stream destined for the client. Everything else that .asp files may (or may not) do ultimately ends up at the Write method.

Response.Write has a simple syntax. It needs only a quoted text string or a function that returns a string.

You can put parentheses around the string or function, but you can save a keystroke if you skip the parentheses and insert a space between Response.Write and its parameter.

There are two ways of instructing the Active Server to output characters: explicitly with the Response.Write syntax, and implicitly with the .asp code delimiters. That is, anything appearing outside the <% (to mark the beginning of Active Server Pages source code) and %> (to mark its end) tags is implicitly written by the Active Server to the HTML file returned to the client.

Do not nest <%…%> tags. That is, once you use <% in your source code, don't use it again until you have first used the closing source code delimiter, %>. This is a trap that is particularly easy to fall into when you are using the special case of the <%…%> delimiters, viz., when you are writing the value of a variable or method to the output stream.

Specifically, whenever you need to output a value, surround the expression with the <%= …%> tags. But remember to first close off any open script with the %> tag. If you look closely at the following example (that would fail if you tried this at home), you will see that you are nesting tags.

<% 

If True Then

<%= varResult%>

Else

Call MyProgram

End If

%>

In the extreme, you could write all your .asp files using Response.Write to send all HTML commands to the client. All the other characters in your .asp file, then, would be .asp source code, and every line would be wrapped in the <%…%> marker. Alternatively, all the HTML source code in your .asp file could be written as if it were merely an HTML file, and you would cordon off the ASP commands with judicious use of the <%…%> delimiters.

Good programmers are far too lazy to use this method, but Listing 11.5 works:

Listing 11.5 A Method for PeoplE who Like to Type <% and %.

<%Response.Write("<!-- Created with HomeSite v2.0 Final Beta -->")%>

<%Response.Write("<!DOCTYPE HTML PUBLIC " & CHR(34) & "-//W3C//DTD HTML 3.2//EN"& CHR(34) & ">")%>

<%Response.Write("<HTML>")%>

<%Response.Write("<HEAD>")%>

<%Response.Write("<TITLE>Registration Results</TITLE>")%>

<%Response.Write("</HEAD>")%>

<%Response.Write("<BODY>")%>

<%Response.Write("<FONT SIZE=+3>Thanks for writing! </FONT><P>")%>

<%Set objConn = Server.CreateObject("ADODB.Connection")%>

<%objConn.Open("guestbook")%>

<%Set objRst = Server.CreateObject("ADODB.Recordset")%>

<%Set objRst.ActiveConnection=objConn%>

<%objRst.LockType = 3%>

<%objRst.Source = "tblGuestbook"%>

<%objRst.CursorType = 3%>

<%objRst.Open%>

Choosing which syntax to use should be guided by the rules of syntax in the English language and the rules of good government: less is better. Use punctuation only when it is absolutely necessary or when it improves clarity; write the fewest laws possible to ensure order and civility. In ASP development use the fewest delimiters possible.

There are two reasons for this: laziness and program maintenance. Clearly, <% %> has fewer (though awkward) keystrokes, so it serves the laziness inherent in all good programmers; and fewer odd characters makes for more lucid logic (unnecessary delimiters are distracting to the human eye and virtually transparent to the server's eye). Lucid logic is easier to maintain (thereby further serving the programmer's natural laziness do I belabor the point?).

There is one other reason for choosing implicit Write over the explicit, but we will have to wait a moment to see why.

Listing 11.6 is easier to type and easier to read:

Listing 11.6 GUESTBOOK.ASP--Opening the Guestbook Database

<!--#INCLUDE VIRTUAL="/ASPSAMP/SAMPLES/ADOVBS.INC"

<!-- This document was created with HomeSite v2.0 Final Beta -->

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">

<HTML>

<HEAD>

<TITLE>Registration Results</TITLE>

</HEAD>

<BODY>

<FONT SIZE="+3">Thank you for registering!</FONT><P>

<%

Set objConn = Server.CreateObject("ADODB.Connection")

objConn.Open("guestbook")

Set objRst = Server.CreateObject("ADODB.Recordset")

Set objRst.ActiveConnection=objConn

objRst.LockType = adLockOptimistic

objRst.Source = "tblGuestbook"

objRst.CursorType = adOpenKeyset

objRst.Open

%>

As with URLEncoding, there is one special case when Response.Write will get confused: when the character string %> appears in the method's parameter. This happens, for example, when you use Response.Write to define an HTML TABLE WIDTH as a percentage of the screen. If you absolutely must use Response.Write in these circumstances, use the following modification: %\>

There is also another time when Response.Write can be a hassle: when you have embedded quotes in the string. As a matter of fact, this is a perennial programming problem. My favorite solution is to insert CHR(34) wherever an embedded quote appears.

ON THE WEB

http://www.quecorp.com/que/asp/respfix.asp—A small .asp file, respfix.asp, is included at this book's Web site to demonstrate each of these workarounds. By the way, the source code makes use of the PLAINTEXT tag to render .asp syntax directly, without processing the .asp command first. There is also a note about errors (that cannot be trapped) if you don't implement the workarounds properly.

Because VBScript functions and subroutines can only be created using the <SCRIPT>...</ SCRIPT> tags and not the <%...%> tags, if you need to return HTML from a VBScript procedure, Response.Write is exactly what you need because you can't use <%= ... %>.

If most of your .asp file is .asp source code (e.g., it has lots of ADO programming in it as the following Guestbook does), then you will use Response.Write only when you need to include HTML source code and it is not convenient to insert the end of .asp source tag, %>. This is awkward to describe, but easy to see, so take a careful look at the ASP version of the Guestbook that follows. Note: There isn't a single use of Response.Write in it.

It's worth emphasizing a subtle point here that will be frustrating to you later if you overlook it now. You separate script from HTML with either the <%...%> .asp source code tags or the <SCRIPT>...</ SCRIPT> VBScript tags. Use the latter when you are creating named script functions, and when you do, use the Response.Write method to send HTML back to the client. Pay close attention to the demos and templates scattered throughout this book, and you will quickly make this second nature, part of your growing ASP programming sensibility.

Guestbook Made Easy

Now that you understand the basic operation and tradeoffs for using the Request Object and its QueryString and Form collections, take a look at how ASP can radically reduce the work required to deliver even the most basic kind of interactivity on the Web.

Standard HTML

Using ActiveX and exploiting the power of ADO (which we will dive into with gusto in Part IV, "Database Management with Active Server Pages"), our Active Server Program uses 33 lines of code instead of 92, and it gives us the feedback form to boot! And we don't know about you, but we can actually read the Active Server Program.

The first part of the .asp file, given in Listing 11.7, is simple HTML.

What is important to note here is that the following HTML code is part of the program that processes the form data but that this first block does something the Perl script did not: It provides the feedback form displayed after the client posts their entry.

Listing 11.7 GUESTBOOK.ASP--The Header of the Guestbook Feedback Form

<!--#INCLUDE VIRTUAL="/ASPSAMP/SAMPLES/ADOVBS.INC"

<!-- This document was created with HomeSite v2.0 -->

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">

<HTML>

<HEAD>

<TITLE>Registration Results</TITLE>

</HEAD>

<BODY>

<FONT SIZE="+3">Thank you for registering!</FONT><P>

A Quick Review

For those readers who are new to HTML, here's a brief detour into the header of an .html file (only in this case it's an .asp file that will produce HTML output).

The first line is a Server-Side Include directive. This tells the Active Server to insert everything in the adovbs.inc file, viz., all VBScript constants, into the guestbook.asp file while it interprets the VBScript.

The second line is required to meet the specs on HTML/3.2, and it is inserted automatically by my ASP editor, HomeSite.

The HTML and BODY tags are closed with </HTML> and </BODY> tags at the end of the .asp file (see Listing 11.10). They tell the Web client that everything in between needs to be treated as HTML output. Within the HEAD section, nothing is printed to the Web client's display window. The text within the TITLE tags is printed in the border of the Web client's main window. The FONT tag increases the default font by 3 sizes.

ASP code

At this point we start writing .asp code. In the first block, Listing 11.8, we are making a connection with a database and a table. We need access to the table that permits us to append a new record and edit the contents of that record with the values passed to guestbook.asp from guestbook.html. We instruct the Active Server to open this table with a keyset cursor, using optimistic record locking, and we instruct it to complete the update of Guestbook entries with Listing 11.9.

See "Learning About Locks" for more information on record locking, in Chapter 17.

Note how we have organized the .asp code in Listing 11.8 so that we only need one set of <%...%> tags.

Listing 11.8 GUESTBOOK.ASP--Opening the Connection to a Database and a Table Within that Opened Database

<%

Set objConn = Server.CreateObject("ADODB.Connection")

objConn.Open("guestbook")

Set objRst = Server.CreateObject("ADODB.Recordset")

Set objRst.ActiveConnection=objConn

objRst.LockType = adLockOptimistic

objRst.Source = "tblGuestbook"

objRst.CursorType = adOpenKeyset

' Alternatively you could move the values from the previous four

' lines of code onto the next line as properties of the Open method.

objRst.Open

Note the form variables have already been decoded using the Request Object. We don't need all the low level source code provided by the Perl script. See Listing 11.1 and Listing 11.2.

Listing 11.9 GUESTBOOK.ASP--Adding a New Entry

objRst.AddNew

objRst("realname") = Request.Form("realname")

objRst("username") = Request.Form("username")

objRst("url") = Request.Form("url")

objRst("city") = Request.Form("city")

objRst("state") = Request.Form("state")

objRst("country") = Request.Form("country")

objRst("comments") = Request.Form("comments")

objRst.Update

%>

If you're accustomed to doing database programming in Microsoft Access or Visual Basic, then you will find programming in ADO very easy. The only real difference between Listing 11.9 and Access or Visual Basic is the use of the Response Object and its Write method.

Note the ending %> tag. If you think about these tags as if they were, themselves, programming logic (e.g., similar to the If...Then...Else construct), then you can see that to forget the %> would be like forgetting the End If in a regular code block. You're certainly welcome to surround all ASP commands with <%...%>, but why bother?

Back to HTML

Having updated the underlying table with the new Guestbook entry, we continue writing the HTML file to the client. If we add another dozen lines to this program we can also redisplay the contents of the form and include a button that permits reentry. Alternatively, we could rename the guestbook.htm file into guestbook.asp and have it call itself changing the original "Submit" button to an "Update" button. We'll show you how to do this in the next Chapter 12, "Enhancing Interactivity with Cookies, Headers, and the Server Object."

Listing 11.10 GUESTBOOK.ASP--Finishing Touches

<HR>

<A HREF="guestbook.html">Return to Guestbook</A>

</BODY>

</HTML>

That's all there is to it. Remember our story at the beginning of this chapter? Well, if ASP was around back then, we would have been able to say to our boss, "Sure, boss; that's a slam dunk. We'll have a Guestbook for you before lunch."

More Power To You

We have just skimmed over the power and features of the Request and Response Server Objects, just enough to be able to construct a simple Guestbook. There's much more available to the Active Server Program developer, however.

As you continue reading this book, please keep in mind one very important idea somewhere near the front of your mind: Active Server Programming is going to enable those of us who are not professional programmers to do things not even they have been able to do before. We are going to see an explosion of creativity the depth and breadth of which will surprise everyone. Everyone but you. You're leading the way.

From Here...

In this chapter, we have built a new programming foundation for interactivity. You have seen what it used to take to get a simple Guestbook implemented on our Web sites, and you have tried your hand at doing it the ASP way. It really is amazing how much work we can get done with two ASP objects like Request and Response, isn't it?

We turn our attention next to a discussion of the rest of the features of the Request and Response Objects, and we will introduce the Server Object.


© 1997, QUE Corporation, an imprint of Macmillan Publishing USA, a Simon and Schuster Company.