ASP
Home Up Search Trademarks how to use

For best results: this site requires that cookies be enabled for proper operation - see Legal Page for more info

 

Select Any of These

ASP

LAST UPDATED: 08 March 2009 17:02:15 -0600

This page is currently under redevelopment.  So it will be changing.  Thank you.

Translate this page      using FreeTranslation.com

horizontal rule

A ONE-PAGE WEB SITE   A QUICK BACK LINK   ACCESSING CLIENT MACHINE INFORMATION

ACCESSING OBJECT PROPERTIES  ACCESSING REQUEST DATA

ACCESSING SQL SERVER THROUGH AN ASP PAGE   ADDING A SPELL-CHECKER

ADDING COMMENT BLOCKS   ADDING DEBUGGING STATEMENTS

ADDING NEW TEMPLATES FOR VISUAL INTERDEV   ADDING PERMANENT DEBUGGING CODE

ADDING PLAIN HTML TO THE OUTPUT     ADDING RECORDS TO TABLES WITH AUTOINCREMENT FIELDS

ADO 2.5    ALWAYS PROVIDE A CASE ELSE     ASP AND DATABASE SUPPORT

ASP CERTIFICATION TESTS    ASP CODE DOESN'T GO ACROSS THE WEB

ASP CODE DOESN'T GO ACROSS THE WEB--PART 1 OF 2

ASP CODE DOESN'T GO ACROSS THE WEB--PART 2 OF 2

ASP CODE NOT EXECUTING   ASP COMMENT BLOCKS    ASP CRASH COURSE WEB SITE NOW AVAILABLE

ASP FILE NOT PROCESSING    ASP MAGIC EIGHT BALL    ASP NOT LOADING IN NETSCAPE

ASP ON OTHER PLATFORMS    ASP PAGES CAN'T CONTROL GRAPHICAL APPLICATIONS

ASP+ NEWSGROUPS    ASP+ RESOURCE DIRECTORY    ASP-BASED CHAT SYSTEM

ASPERROR OBJECT    ATTACHING FILES TO E-MAIL    AVOID THE ADO ADDNEW AND DELETE METHODS

BROWSER-SPECIFIC CODE     BUFFERING AND DEBUG STATEMENTS    BUFFERING IN WINDOWS 2000

BUILDING A FORMAT FUNCTION--PART 1 OF 2    BUILDING A FORMAT FUNCTION--PART 2 OF 2

BUILDING A LIST AUTOMATICALLY    BUILDING A SORTING QUERY

BUILDING ARRAYS DYNAMICALLY    BUILDING MULTIPAGE FORMS    CACHING OBJECT DATA

CALLING ANOTHER PAGE    CALLING SUBROUTINES    CAN'T CLONE RECORDSET

CASE SENSITIVITY IN THE REPLACE FUNCTION--PART 1 OF 2 

CASE SENSITIVITY IN THE REPLACE FUNCTION--PART 2 OF 2 

CDO LIBRARY AVAILABLE FOR DOWNLOAD    CHANGING TIME FOR A VIRTUAL SERVER

CHANGING URL PARAMETERS    CHECKING CHECK BOXES    

CHECKING FOR EMPTY VS. CHECKING FOR NULL    CLASSES IN VBSCRIPT    CLEANING YOUR SQL DATA

CLIENT VERSUS SERVER VALIDATION    CLIENT-SIDE SCRIPTING VS. SERVER-SIDE SCRIPTING

CLOSING RECORDSETS     COM COMPONENTS AND TEXT GENERATION

COMBINING ASP, EXCEL, XML, AND XSL    COMMENT YOUR CODE    COMPARING DATE VALUES IN SQL SERVER

COMPLETELY HIDING YOUR ASP CODE    CONDITIONAL SERVER-SIDE INCLUDES

CONFIGURING PERSONALIZATION AND MEMBERSHIP SERVER

CONNECTING TO ACCESS 2000    CONNECTING TO NON-MICROSOFT DATABASES

CONVERTING BITS TO YES/NO VALUES    COOKIE LIMITS    COUNTING RECORDS IN A RECORDSET

CREATEOBJECT FAILED    CREATING A DUAL-PURPOSE PAGE    CREATING A JAVA OBJECT IN ASP

CREATING A PAGE COUNTER    CREATING A QUICK ROLLOVER     CREATING A QUICK SEARCH BOX

CREATING A REGISTRATION COOKIE   CREATING A TOP QUERY     CREATING A WRITELINE FUNCTION

CREATING FORWARD-ONLY RECORDSETS  CREATING HIDDEN INPUT FIELDS 

CREATING OBJECTS    CREATING STATELESS PAGES    CREATING WINDOWS SCRIPT COMPONENTS

DATA ACCESS CONSTANTS AVAILABLE    DATABASE FIELD DUMP    DATABASE PERFORMANCE TESTING

DATE AND TIME FUNCTIONS    DEALING WITH SINGLE QUOTES    DEALING WITH THE BACK BUTTON

DEJA.COM IS NOW GOOGLE.COM     DELETING A COOKIE    DELETING DEPENDENT RECORDS

DELETING RECORDS, REVISITED     DEPLOYING AN ASP APPLICATION    DETECTING A SECURE CONNECTION

DETECTING A SECURE PORT    DETECTING INTERNET EXPLORER        DETERMINING A DATABASE PATHNAME

DETERMINING AND CHANGING THE DEFAULT DATABASE    DETERMINING HOW MANY RECORDS ARE AFFECTED

DETERMINING IF A FIELD CAN BE NULL    DEVELOPERSITES.COM

DIFFERENT TYPES OF COOKIES    DISABLING COOKIES    DISABLING SESSION COOKIES

DISPLAYING A MESSAGE BOX   DON'T INSTALL WEB SERVER PATCH    DON'T USE ID FOR SORTING 

DON'T USE OBJECTS IN SESSION VARIABLES    DOWNLOAD A NEW ADOVBS.INC

DYNAMIC COPYRIGHT LINE    DYNAMIC SERVER-SIDE INCLUDES, REVISITED

ELIMINATE SPACE IN TABLES    ELIMINATE TOP AND LEFT MARGINS    EMBEDDING DOUBLE QUOTES

EMBEDDING NEW LINES IN EMAIL    ENCODING YOUR SCRIPT    ENCRYPTING COOKIE INFORMATION

ENCRYPTING THE QUERY STRING    ENVIRONMENT VARIABLE DUMP    ERROR WHEN CREATING COOKIES

ERRORS OPENING ACCESS DATABASES     EXPORTING DATA FROM ASP PAGES

FILESYSTEMOBJECT CONSTANTS    FILTERING A RECORDSET    FILTERING BY MULTIPLE FIELDS

FINDING A PLACE TO BUILD ASP PAGES    FINDING INFINITE LOOPS    FINDING OLE DB PROVIDERS

FINDING OUT WHERE THE USER CAME FROM    FLEXIBLE CLIENT-SIDE VALIDATION

FORM SUBMISSION LIMITS    FORMATTING PHONE NUMBERS

GENERATING STATIC HTML FROM ASP    GETSTRING METHOD    GETTING A LIST OF TABLES

GETTING BROWSER CAPABILITIES    GETTING BROWSER CAPABILITIES 2

GETTING DATA FROM TWO (OR MORE) DATABASES    GETTING INFORMATION FROM EXTERNAL WEB SITES

GETTING NEWLY CREATED RECORD ID    GETTING SECURITY INFORMATION    GETTING THE PAGE NAME

GETTING THE PREVIOUS PAGE WITH HTTP_REFERER    GLOBAL.ASA NOT REQUIRED    GREEKING TEXT

HANDLING MULTIPLE CHECK BOXES   HANDLING MULTISELECT HTML LISTS    HARDCODING PAGE NAMES

HEADER ERRORS WITH REDIRECT METHOD    HIGH TRAFFIC CRASHES WEB SITE        

HIGHLIGHTING SEARCH RESULTS    HOW TO USE SSL    HTTPS SERVER VARIABLE

IIS FAQ    ILLEGAL OPERATION ERRORS IN INTERNET EXPLORER    IMPROVING OUTPUT PERFORMANCE

IMPROVING SITE PERFORMANCE--PART 1 OF 4    IMPROVING SITE PERFORMANCE--PART 2 OF 4

IMPROVING SITE PERFORMANCE--PART 3 OF 4    IMPROVING SITE PERFORMANCE--PART 4 OF 4

INCLUDING REMOTE FILES    INDEXING ROBOTS AND YOUR SITE    

IN-PAGE LINKS AND QUERYSTRING PARAMETERS    INPUT BOXES FOR NUMBERS    INSTALLING ASP+

INSTALLING PERSONAL WEB SERVER    INTEGRATION WITH QUICKBOOKS

KNOW WHEN TO USE WHICH LANGUAGE

LEARNING XML    LIMIT GLOBAL VARIABLES    LIMITING RESULTS    LIMITING SEARCH RESULTS

LINKING TO EXTERNAL SITES    LISTING THE SYSTEM DSNS    LONG-RUNNING ASP PAGES

MACROMEDIA ULTRADEV REVIEWED    MAINTAINING STATE BETWEEN WINDOWS    

MANAGING IMAGES WITH A DATABASE    MANAGING SAVED RECORDSETS

MANUALLY CREATING A RECORDSET    MANUALLY CREATING A RECORDSET--PART 1 OF 3

MANUALLY CREATING A RECORDSET--PART 2 OF 3    MANUALLY CREATING A RECORDSET--PART 3 OF 3

MANUALLY INCLUDING A FILE    METHOD=POST VS. METHOD=GET    

MICROSOFT .NET FRAMEWORK SDK AVAILABLE    MICROSOFT ACCESS AND WEB SERVERS

MICROSOFT DATA ENGINE VS. MICROSOFT ACCESS    MICROSOFT PARTY LINE ON VBSCRIPT AND JSCRIPT

MIGRATING FROM IIS 4 TO IIS 5    MODIFYING A RECORD'S PRIMARY KEY    MODULARIZING HTML RENDERING

MORE ASP TIPS AT ASPTIPS.COM    MOVE METHODS NOT AVAILABLE    MOVEPREVIOUS NOT WORKING

MTS COMPONENTS MUST BE REGISTERED    MULTI-LINE COMMENTS    MULTI-LINE COMMENTS IN ASP 

MULTIPLE SUBMIT BUTTONS ON A FORM

NEW FEATURES AT ASP TECHNIQUES    NEW TIMER FUNCTION    NO CONTROL ARRAYS IN VBSCRIPT

ODBC AND ADO    OMIT EMPTY GLOBAL.ASA FILE    OPENING THE LOCAL SQL SERVER

OPTION EXPLICIT IN ASP+    OPTIONAL FEATURE NOT IMPLEMENTED    OPTIONS FOR ORDERED LISTS

OWNERSHIP OF CODE

PAGE SIZE ISSUES    PAGING THROUGH LARGE RECORDSETS    PASSING VARIABLES BETWEEN PAGES

PERFORMANCE IMPROVEMENTS IN IIS 5.0    PERMANENT VS. TEMPORARY COOKIES    

PERMISSION DENIED FOR E-MAIL    PERSISTING A RECORDSET    PERSONAL WEB SERVER AND WINDOWS ME

PERSONAL WEB SERVER WORKSHOP    PREVENTING A PAGE FROM CACHING    

PRINTING VALUES WITHOUT THE RESPONSE.WRITE STATEMENT    PROBLEMS WITH ACCESS DATABASES

PROBLEMS WITH CDONTS.NEWMAIL    PROTECTING YOURSELF FROM SCRIPTING ATTACKS

PUTTING IIS AND WINDOWS 2000 ON A LAPTOP    

READ PROPERTIES SPARINGLY    READING USER'S EMAIL ADDRESS    READY OR NOT, HERE COMES XML

REBOOTING THE WEB SERVER    RECORDCOUNT = -1    REGISTER YOUR DLLS    REGISTERING A DOMAIN

REGISTERING DLLS     RELEASING OBJECTS    REMEMBER TO SET COMMANDTYPE 

REMEMBERING A USER'S INPUT    REMEMBERING A USER'S INPUT part 2    REMOTE ADMINISTRATION    

 REMOTE SERVER-SIDE INCLUDES    REMOTELY RESTARTING THE SERVER

REMOVING YOUR SITE'S COOKIES    REQUEST OBJECT COLLECTIONS ARE OPTIONAL

RESERVED WORDS AS VARIABLES    RETRIEVING RECORDSETS    

RETRIEVING XML DATA INTO ASP    RUNNING ASP SCRIPTS

SAFELY SHOWING VALUES IN FORM FIELDS    SAVING A RECORDSET    SAVING SEARCHES

SCHEDULING A PAGE    SCRIPT TIMEOUTS    SCRIPTLESS ASP FILES    

SEARCHING LONG TEXT FIELDS IN SQL SERVER    SEARCHING TEXT FILES    SENDING DATA TO EXCEL

SENDING DATA TO MICROSOFT WORD    SENDING E-MAIL FROM ASP    SENDING EMAIL WITHOUT A COMPONENT

SENDING PLAIN TEXT    SERVER.CREATEOBJECT FAILED    SERVER.EXECUTE WORKS LOCALLY

SERVER.TRANSFER VS. RESPONSE.REDIRECT    SERVER-SIDE INCLUDES FOR REMOTE FILES

SESSION VARIABLES AND LOAD BALANCING    SHOWING GRAPHS AND CHARTS ON A WEB PAGE

SHOWING HTML EFFICIENTLY    SHOWING VALUES IN FORM FIELDS    SIMPLE EMAIL VALIDATION

SINGLE QUOTES AND SQL    SITE SERVER'S DIRECTMAIL FUNCTIONALITY    SITEEXPERTS.COM

SPECIFYING NETWORK LIBRARY FOR SQL SERVER    SQL SERVER FOR STRING PROCESSING

STACK RECORDSET RETURNS    STANDALONE ASP DEVELOPMENT    

STATE PRESERVATION AND THE SESSION OBJECT    STORING PICTURES IN A DATABASE

STRUCTURING YOUR INCLUDE FILES    SUBSCRIBE TO ASPWIRE    SYSTEM LIBRARY LOCATIONS

TESTING ASP APPLICATIONS    TEXT BOX DATA TRUNCATED    THE FILE ACCESS COMPONENT

TIMER FUNCTION FIXES    TIMING OUT A LOGIN    TIMING THE EXECUTION OF SCRIPTS

TRACKING CLICKTHROUGHS TO AN EXTERNAL SITE    TRACKING IP ADDRESSES    TUTORIAL ON COOKIES

UPDATING A DATE/TIME FIELD IN SQL SERVER    UPDATING AN ACCESS DATABASE

UPDATING COMPONENTS AND MICROSOFT TRANSACTION SERVER    USE CONSTANTS FOR FILENAMES

USE SERVER.TRANSFER INSTEAD OF RESPONSE.REDIRECT    USING ACCESS DATABASES WITH ASP

USING ASP WITH ODBC DATABASES    USING ASSIGNMENT STATEMENTS    USING CLASSES IN VBSCRIPT 5.0

USING MOVE METHODS WITH RECORDSETS    USING MTS COMPONENTS WITH ASP    USING OPTION EXPLICIT

USING PARAMETERIZED STORED PROCEDURES    USING PERLSCRIPT WITH ASP    USING SERVER.EXECUTE

USING SERVER.HTMLENCODE    USING SESSION VARIABLES    USING SESSION VARIABLES FOR SECURITY

USING SQL SERVER FOR DATE PROCESSING    USING SQL SERVER FOR STRING PROCESSING

USING STYLE SHEETS AND SQL FOR OUTPUT    USING THE ADO FIELD ATTRIBUTES PROPERTY

USING THE BILL OF MATERIALS STRUCTURE    USING THE EVAL FUNCTION    

USING THE JET 4.0 PROVIDER WITH ACCESS 97    USING THE LIKE KEYWORD    USING THE METADATA TAG 

USING THE RECORDSET SORT PROPERTY    USING VARIANTS IN COM COMPONENTS    

VALIDATING ADDRESSES    VALIDATING AND CLEANING TEXT    VALIDATING DATA    

VALIDATING EMAIL ADDRESSES, REVISITED    VBSCRIPT IN MSGBOX TITLE    VIEWING A LIST BOX'S DATA

VIEWING ASP PAGES IN INTERNET EXPLORER    VISIT ACTIVE SERVER CORNER    

VISUAL BASIC DIRECTORY AT ABOUT.COM    VISUAL SOURCESAFE AND ASP    

VISUAL STUDIO SERVICE PACK 4 AVAILABLE

WHAT IS ASP ERROR 0115?    WHAT'S WRONG WITH RENDER BLOCKS    WHEN A SESSION EXPIRES

WHERE TO PUT COOKIE CODE    WHERE TO VALIDATE DATA    WHICH ORACLE DRIVER TO USE

WORKING WITH MULTIPLE CHECK BOXES    WORKING WITH MULTIPLE FORMS    

WORKING WITH MULTIPLE SUBMIT BUTTONS    WORKING WITH SQL SERVER CURRENCY FIELDS

WORKING WITH THE BACK BUTTON    WRITECOMMENT FUNCTION    WRITING A WEB PAGE COUNTER

WRITING AN XML FILE

MANAGING IMAGES WITH A DATABASE

For those of you interested in storing images in a database, I have two words for you: Don't bother. While you can do it, it's much easier to do the following.

First, create a field in your table to store a filename. Then, store the image on disk somewhere with that filename. Finally, link to the image from your Web application or your client/server application.

In my experience, it's much easier to work with images in this fashion unless you have some high-performance systems specifically designed for working with large batches of images. For more users, storing the files on a shared disk makes them easier to get to for both Web and client/server applications.

horizontal rule

ADDING PLAIN HTML TO THE OUTPUT

If you need to include plain, constant HTML in your ASP page's output, don't mess with lots of Response.Write statements to generate it. Instead, do something like this:

' ASP code
%>
<UL>
<LI>List 1
<LI>List 2
</UL>
<%
' more ASP code

This makes your code easier to read and is a lot easier than crafting lots of Response.Write statements.

horizontal rule

USING ASSIGNMENT STATEMENTS

In ASP, you can cause a variable or expression to be printed using the <% = syntax. However, you can't make the statement longer than one line. If you are using this syntax and need to make your assignment longer than a single line, use a Response.Write to do it instead, or break the assignment into multiple sections. Since ASP only inserts
line breaks where you put in HTML-based line breaks (P or BR tags), you don't have to worry about a value printing on more than one line.

horizontal rule

COMMENT YOUR CODE

One of the biggest faults of ASP programmers is that they don't comment their code. Comments make it easier for both you and other programmers to understand what you were thinking when you wrote the code. You have two main ways of commenting your code. The first is an HTML comment that should not be placed within the ASP delimiters:

<!-- this is an HTML comment -->

The other type of comment goes within the ASP delimiter tags and is marked with a single quote, as shown here:

<%
' This comment goes within ASP code
%>

These comments aren't sent to the user's browser, whereas the HTML comments are, so be careful what content you're putting in your comments. Storing your database passwords and IP addresses in HTML-based comments is not normally a good idea.

horizontal rule

RETRIEVING RECORDSETS

If you need a read-only copy of data from a database to populate some sort of list or table, the best type of recordset to use is a forward-only, read-only recordset. The code to do this is

Dim dcnDB ' As ADODB.Connection
Dim rsData ' As ADODB.Recordset
Set dcnDB = Server.CreateObject("ADODB.Connection")
dcnDB.Open "some connection string"
Set rsData = dcnDB.Execute("SELECT * FROM LookupTable")

The default recordset is a read-only, forward-only recordset using this method.

horizontal rule

INSTALLING PERSONAL WEB SERVER

A reader alerted me to the fact that Personal Web Server is also available on the Windows 98 CD-ROM. This version includes the ASP engine, Transaction Server, and Message Queues. PWS is installed automatically with FrontPage 98. You have to install the ASP engine manually, but the instructions for doing this are included in the 60-Minute Intranet Kit. Apparently, installing from the NT Option Pack has caused problems for people, as evidenced by the number of
questions and issues raised in the Usenet groups relevant to this product.

horizontal rule

PROBLEMS WITH ACCESS DATABASES

Here's a quick tip if you're using an Access database (or other file-based database) with Active Server Pages. You have to make sure that the directory in which the database lives is marked as writeable for the user ID used by the IIS process. Otherwise, the database won't operate properly from your ASP applications.

horizontal rule

MULTIPLE SUBMIT BUTTONS ON A FORM

If you have a form with multiple SUBMIT buttons on it, you can determine which button was clicked by looking at the button's value in the Request.Form data collection. If the button has a value, it was the one pressed. For instance:

<form action="submit.asp" method="post">
<input type=submit name=cmdButtonA value="A">
<input type=submit name=cmdButtonB value="B">
</form>

Your ASP code would check Request.Form("cmdButtonA") against an empty string. If the value in cmdButtonA is not an empty string, Button A was pressed.

horizontal rule

USING OPTION EXPLICIT

If you don't regularly declare your variables, you can run into problems with typos in variable names. VBScript by default automatically creates variables as it sees the names. However, if you put Option Explicit as the very first line in your file, all variables will have to be declared in the page. Just add it to the top of the file like this:

<% Option Explicit %>

Make sure you put it before any other script code or you'll get an error, since this line has to be the very first line in the file.

horizontal rule

PRINTING VALUES WITHOUT THE RESPONSE.WRITE STATEMENT

If you are embedding HTML in your ASP page, you can print variables and expressions without having to use the esponse.Write statement. Here's an example:

<UL>
<LI><% = rsData("UserID") %>

This will print out the value of the UserID field of the rsData recordset immediately following the LI tag. The only restriction is that you can't stretch the delimiters over more than one line.

horizontal rule

ASP CODE DOESN'T GO ACROSS THE WEB

I got a question the other day about how to protect your source code so users can't see it. The person asking wanted to make sure that the code he created in his ASP page wouldn't be visible on the Web. The fact is that ASP code (anything between the delimiter tags) is evaluated (and basically removed) from the ASP page before it gets sent to the user's browser. All the user gets is the HTML that's left or that you created with your ASP code.

horizontal rule

WHAT IS ASP ERROR 0115?

Have you ever developed an ASP page and gotten an ASP Error 0115? After you get it, no matter what you do, you keep getting the same error. The reason is that 0115 means a component used by ASP has crashed, and ASP can't get anymore information from the component to help diagnose the problem. Often, the solution involves stopping and starting the IIS service. For more information on this problem, visit this URL:

http://207.141.47.107/aspfaq/0115.asp

horizontal rule

SENDING E-MAIL FROM ASP

One of the most common questions I get is how to send e-mail from an ASP page. Using the Collaboration Data Objects (CDO), it's quite easy. The object you need is the CDONTS.NewMail object, and it can be used like so:

Dim objMail ' As CDONTS.NewMail
Set objMail = Server.CreateObject("CDONTS.NewMail")
objMail.To = "destination@host.com"
objMail.From = "sender@host.com"
objMail.Subject = "Subject goes here"
objMail.Body = "The message goes here."
objMail.Send
Set objMail = Nothing

There are several other properties and methods with this object. You can refer to MSDN for a complete list.

horizontal rule

ATTACHING FILES TO E-MAIL

In a previous tip, you learned how to send e-mail from ASP using the Collaboration Data Objects. Besides just sending plain text, you can attach files to messages. The AttachFile method allows you to add a file to an outgoing e-mail message, as shown here:

Dim objMail ' As CDONTS.NewMail
Set objMail = Server.CreateObject("CDONTS.NewMail")
objMail.To = "destination@host.com"
objMail.From = "sender@host.com"
objMail.Subject = "Subject goes here"
objMail.Body = "The message goes here."

objMail.AttachFile "C:\Autoexec.bat", "Autoexec.bat"
objMail.Send
Set objMail = Nothing

The first parameter is the pathname to the file. The second parameter is the name that appears with the attachment in the person's e-mail. This is especially helpful if you have a long pathname or don't want to show the user the original filename.

horizontal rule

SESSION VARIABLES AND LOAD BALANCING

A number of readers have written about the positives and negatives of using Session variables. In an article by Bart  Gerardi, the implications of Session variables are discussed when it comes to running your application in a  load-balanced environment. Check out the article at

http://www.asptoday.com/articles/20000118.htm

horizontal rule

THE FILE ACCESS COMPONENT

A number of readers have asked me recently about the "File Access Component" of ASP. This is a bit of a misnomer and is 
not a new component of any sort. The File Access Component of ASP refers to the FileSystemObject and the related 
objects, such as File, Folder, and so on. The MSDN Library lists it as a separate component but provides a link to the 
FileSystemObject section.

horizontal rule

USING PERLSCRIPT WITH ASP

A reader asked why we hadn't mentioned PerlScript as a language to use with ASP. Any supported scripting language on 
Windows NT can be used to write ASP code, which includes PerlScript and other languages, like Python and REXX. Feel free  to use whatever language you like . . . it's just that most documentation you'll see from Microsoft will use VBScript 
for any code examples, so you'll have to figure out how to use the objects on your own if you don't use VBScript.

horizontal rule

USING VARIANTS IN COM COMPONENTS

If you're building COM components for your Web applications, remember that VBScript knows only one data type: Variant. This has two implications for COM components: The first implication involves parameters you might have to supply to a function or subroutine. For example, if your COM component is set to accept a Long, you'll have to use the CLng function on the input value before passing it. This is fine, but an easier way to handle this is to accept a Variant and perform any conversions after the value is inside the COM component. This has the added benefit of keeping all the conversion code in one place. Also, remember to do any necessary validation on the input.

The other implication involves return values from functions. For instance, while you might want to return an ADODB.Recordset object to your code, you should use a return type of Variant. You'll still be able to return the object, and VBScript will know how to handle the object, since you're using the Set statement to store the result in a Variant variable.

horizontal rule

WHICH ORACLE DRIVER TO USE

In a previous tip, we talked about the Oracle driver that had been created by Microsoft when ADO was first released. At the time, it had better performance than any driver that Oracle had created. However, this situation has since changed. According to several readers, the Oracle OLE DB provider has improved dramatically and is now the recommended driver for accessing Oracle databases through OLE DB/ADO. Users estimate a 30 percent performance improvement over the Microsoft Oracle driver.

horizontal rule

A ONE-PAGE WEB SITE

One of the goals in writing an ASP application is to minimize the number of places you have to work with code. There are lots of mechanisms for doing this, such as server-side includes, which allow you to include the contents of a common file into another.

However, in some cases you can minimize the total number of ASP files in your site by consolidating your code into one place. On the new ASP Techniques site, for instance, I have one file that is intelligent enough to show all the content on the site. Here's the code from the Sub Main routine that runs first on the page. It's just a Select/Case statement that checks the action codes and then calls the right routine. Each routine gets the appropriate key values to show the content, as well as a reference to an MTS component managing database access.


Sub Main
Dim strAction ' As String
Dim lngSectionID ' As Long
Dim lngPageID ' As Long
Dim lngCategoryID ' As Long
Dim lngContentID ' As Long
Dim strCommonID ' As String
Dim objDB ' As NCSBackOffice.Database

strAction = Request(ACTION)
Set objDB = Server.CreateObject("NCSBackOffice.Database")
Select Case strAction
Case ACTION_RETR_COMMON
strCommonID = Request("cID")
RetrieveCommonContent objDB, strCommonID

Case ACTION_RETR_SECT
lngSectionID = Request("sID")
RetrieveSection objDB, lngSectionID

Case ACTION_RETR_CAT
lngCategoryID = Request("cID")
If Request("pID") = "" Then
lngPageID = 1
Else
lngPageID = Request("pID")
End If
RetrieveCategory objDB, lngCategoryID, lngPageID

Case ACTION_RETR_CONTENT
lngSectionID = Request("sID")
lngContentID = Request("cID")
RetrieveContent objDB, lngSectionID, lngContentID
End Select
Set objDB = Nothing
End Sub
Doing something like this is all a matter of organization. It's not hard... it just takes some planning to make it work. If you're interested in this sort of development, watch the ASP Techniques site for some upcoming articles about this topic.

horizontal rule

ACCESSING REQUEST DATA

When retrieving data from the Request object, you can access the data using one of two different methods: either directly through the Request object or indirectly through one of the collections of the Request object. While either method works fine, if you're looking to gain a bit more speed, directly select the precise collection so the system doesn't have to search all the collections for the data you want.

In addition, accessing data from the Request object is more time consuming than getting data from a locally defined variable. If you need to retrieve data more than once, create a temporary variable for the field, copy the data to it, and then use that variable whenever you need the data.

horizontal rule

ADDING A SPELL-CHECKER

Ever wanted to provide a spell-checking feature to your Web forms? In a recent article at ASP Today, you can learn how to do this with a bit of database coding and some font formatting. Best of all, this solution doesn't require any downloaded components or expensive third-party tools.

http://www.asptoday.com/articles/20000406.htm

horizontal rule

ADDING COMMENT BLOCKS

To remind myself what I've done to an ASP file, I will add a comment block to the top of each file (after Option Explicit, of course). This comment block usually contains the following:

Name of the file
Basic description of what the file does
Date created
Modification log containing dates, initials, and descriptions of what has been done to the file

This information helps me keep track of changes to the file, and it's especially helpful for use with a source code control program like SourceSafe or PVCS.

horizontal rule

ADO 2.5

ADO 2.5 is included with Windows 2000, and it is also available as a separate download from the Microsoft Data Access site:

http://www.microsoft.com/data

If you go into the Program Files\Common Files\System\ADO directory, you'll find a bunch of files, some of which have version numbers in the filenames. However, there aren't any with the version number 2.5 in their names. That's because ADO 2.5 is stored in MSADO15.DLL. If you bring up the properties for this library (or any other DLL file), you'll be able to see the version number stored in the library file itself.

horizontal rule

ASP ON OTHER PLATFORMS

If you're looking to run ASP on platforms such as Linux, the best approach (for now) is to use a product called ChiliSoft. It can handle ASP code, just like IIS, as well as custom components written in a variety of languages. It currently has broad server support and is the market leader for this technology. Visit the ChiliSoft Web site at

http://www.chilisoft.com

horizontal rule

ASP-BASED CHAT SYSTEM

Brian Gillham has released an ASP-based chat system that you can integrate into your Web site. You can download the code, for free, from this URL:

http://www.aspfree.com/authors/briang/chat.asp

horizontal rule

BUFFERING IN WINDOWS 2000

With the change from IIS 4.0 to IIS 5.0, there also has been a change in the way buffering is implemented. (Buffering refers to whether content from the ASP page is sent before or after the page is complete.) Under IIS 4.0, buffering is turned off by default, but in IIS 5.0, buffering is turned on. Keep in mind that if you're debugging your page and print values before you get an error, those values won't show up if the page is being buffered. To turn buffering on or off on a per-page basis, you can use this code:

Response.Buffer = True (or False)

To change the buffering status on your Web server, first use the Internet Service Manager to bring up the Properties window for your Web site. Then, select the Home Directory tab and click the Configuration button near the bottom of the window. In the resulting window, select the App Options tab and deselect (or select) the Enable Buffering checkbox. Click OK to exit and save your changes.

horizontal rule

CHANGING TIME FOR A VIRTUAL SERVER

A reader who has his ASP site hosted at a virtual server farm asked me whether it's possible to change the system date/time for just that site. Since ASP uses the NT system time just like everyone else, the basic answer is no. However, you can easily create your own "time" and "date" functions that add or subtract time from the current system time. If you're creating a site for the UK and it's hosted in the US, you can simply add the appropriate number of hours to the US system time, and voila, you've got the UK's time.

horizontal rule

CHANGING URL PARAMETERS

One of the disadvantages of using command-line parameters to link to an ASP file is that the user can simply change those parameters. Depending on the application and use for those numbers, this could be a security risk. If you don't want the user changing them, you need to keep the parameters out of the Web page. Even if you insert the data as hidden input fields, the user could potentially still change the file and resubmit it from his or her server. If you need to keep confidential data, leave it on the server and send a reference to that set of data instead. That way, the user won't know what he or she is changing.

horizontal rule

CHECKING FOR EMPTY VS. CHECKING FOR NULL

Depending on the database you're using, checking a field value may involve checking it against an empty string (two double quote characters together) or against Null using the IsNull function. For numeric values, you almost always need to check them against Null, and not an empty string or zero. An easy way to test if a value is Null is to just print the value of the IsNull function in the page (or in a comment). That way, you can tell very quickly what's going on in your application.

horizontal rule

CLEANING YOUR SQL DATA

One of the big problems people have when they're writing SQL within asP is dealing with data supplied by users. For example, you may have some code that looks like this:

Dim strSQL
strSQL = "SELECT * FROM Customers WHERE CompanyName = '" _
& Request.Form("Keywords") & "'"

This code will return all the customers where the CompanyName field is equal to whatever the person put in the Keywords field on a form. The problem comes, however, when you have a name with a single quote in it, such as the name O'Reilly. The single quote character breaks the SQL statement.

The easiest solution is to "clean" the input data before putting it into the SQL statement. Here's a quick function you can use to do just that. (Note that the SQ constant holds a single quote.)

Const SQ = "'"
Function Clean(strData)
Clean = Replace(strData, SQ, SQ & SQ)
End Function

With the Clean function in place, the original chunk of code looks like this:

Dim strSQL
strSQL = "SELECT * FROM Customers WHERE CompanyName = '" _
& Clean(Request.Form("Keywords")) & "'"

horizontal rule

COMPARING DATE VALUES IN SQL SERVER

When comparing dates within SQL Server, you may get unexpected results if you don't remember that every date value has both date and time components in it. For instance,

6-19-2000

is not the same as

6-19-2000 7:00 PM

Because any date without a time is given a time of 00:00:00. If you do need to compare the dates, you can use any number of functions to compare month, day, and year. You can also convert both dates to text using the CONVERT function and then compare just the date portion.

horizontal rule

COMPLETELY HIDING YOUR ASP CODE

A reader asked if there was any way to completely hide the ASP source code, even from the IIS administrator. No, I didn't ask WHY he wanted to do this, but here are a few basic facts:

* ASP source code is in a text format.
* The IIS administrator typically is the machine administrator, which means he/she can see any file on the machine.
* In order for the files to be viewed by Web visitors, they have to be readable by the Web user ID, which means they are readable by everyone.

If you don't want anyone looking at your source code, you'll have to put all the source code (or as much as possible) within a compiled component developed in VB or some other language. I do this for performance reasons, by the way, and it also doubles as a security precaution.

horizontal rule

CONFIGURING PERSONALIZATION AND MEMBERSHIP SERVER

In an article at Microsoft's Web site, you can learn how to configure the Personalization and Membership components of Microsoft Site Server. The article is a bit aged, but the information is still correct for Site Server 3.0.

http://msdn.microsoft.com/workshop/server/nextgen/perstutor.asp

horizontal rule

CONNECTING TO ACCESS 2000

This question keeps coming up, so I'll answer it again: To connect to an Access 2000 database, you need to use the Jet 4.0 provider with ADO/OLE DB, like so:

Dim dcnDB ' As ADODB.Connection
Set dcnDB = Server.CreateObject("ADODB.Connection")
dcnDB.ConnectionString = "Provider=Microsoft.Jet.OLEDB.4.0;" _
& "Data Source=D:\Mydatabase.mdb;"
dcnDB.Open

I've seen some users using syntax involving DBQ and curly braces, which seems to work OK. However, MSDN uses this method and syntax for examples, so that's what I stick with.

horizontal rule

CREATING A DUAL-PURPOSE PAGE

On this site it shows another page or two to maintain the links and categories. Without creating  two sites, it  merges the administration and the viewer into a single application. At the bottom of the toolbar, there's a link to log into the page. Once I've logged into the system, I get a number of additional options on each page:

* A link to modify the existing link
* A link to delete the link
* Each category shows a link to allow me to enter a new link.
* At the top and bottom of each category page, there's a link to add new categories.

Of course, for operations I need to do infrequently, I can always go directly to the underlying database. The main idea behind this option is to consolidate all the shared code (showing a form, showing a link, etc.) in one place.

Check it out for yourself at

http://eric.northcomp.com

horizontal rule

CREATING A JAVA OBJECT IN ASP

ASP is one of those languages that plays well with others. If you have a Java class that you want to use in ASP, you have two options, depending on what you want to do with the class. You can use Server.CreateObject to create the instance; however, the class must be registered as a COM component on the server. This can be done using the JavaReg program.

The second option is to use the GetObject statement, in which you specify the full name of the Java class, in the form java:classname. Here's an example:

<%
Dim dtmDate
Set dtmDate = GetObject("java:java.util.Date")
%>

The date is <%= dtmDate.toString() %>

Objects created by calling GetObject instead of Server.CreateObject can also access the ASP built-in objects and participate in a transaction. To use Java class names (also known as monikers), you must be using version 2.0, or later, of the Microsoft virtual machine.

horizontal rule

CREATING A RECORDSET MANUALLY, REVISITED

One of the features of the ADO recordset is that you can create it manually. Instead of creating a recordset by way of a database, you can create a recordset, add fields of various types to it, and then add data to it. You can then manipulate it just like a database-created recordset, save it to disk, or pass it back from a component for use in an application.

After you create a recordset object, you can use the Add method of the Fields collection to create new fields. When you create these fields, you can specify the data type, the field length, and so on. Once you've added the fields, you can use the Open method to open the recordset for modification. You then use the AddNew method to create a new record, followed by the Update method to commit the record to the recordset. Refer to the ADO Fields collection for more information about this feature.

Alan Silver mentioned another use for this feature. He was retrieving filenames from disk and needed to sort them. Instead of writing his own sort routine, he created an ADO recordset, loaded the filenames (along with the other data), and used the Sort property to automatically sort the data. This is far less effort than any other sort routine I've used in the past. 

horizontal rule

DATE AND TIME FUNCTIONS

A user asked how to use the server date/time to control access to files. The thing to remember is that any date/time functions--such as Date, Time, and Now--work based on the server's date and time, not the client computer's date and time. This, of course, assumes we're talking about server-side scripting. This is especially important when dealing with international sites and users. If you are showing a date and time, make sure you know to whom you're showing it.

horizontal rule

DEALING WITH THE BACK BUTTON

Several people have asked me how to stop a user from clicking the browser's Back button. Typically, this causes problems for submitting form data, and it would be nice if we could prevent the user from clicking the Back button. Unfortunately, there's no completely reliable way to do this. Instead, think about designing your application to allow the user to press the Back button, just like a wizard might allow. It will involve more coding but will provide a better experience for your users.

horizontal rule

DETECTING A SECURE PORT

If you're running a secure Web site with IIS, you can easily verify that the user is viewing a page through a secure port. Just check the HTTP variable called SERVER_PORT to determine how the user is looking at the page. Here's a snippet of code that checks the port and redirects the user to the secure site if he/she isn't using port 443 to access the site:

If Request("SERVER_PORT") <> 443 Then
Response.Redirect SECURESITE & "adm_login.asp"
Exit Sub
End If

horizontal rule

DETERMINING HOW MANY RECORDS ARE AFFECTED

Using the ADO Connection object, you can use the Execute method to run queries. However, it's often helpful to know how many new records were created, updated, or deleted. If you pass a variable into the Execute method as the second parameter, ADO will fill that variable with the number of records that were touched. Here's an example:

Dim cnDB ' As ADODB.Connection
Dim lngRecords ' As Long
cnDB.ConnectionString = "some connection string"
cnDB.Open
cnDB.Execute "UPDATE Products SET UnitPrice = UnitPrice * 1.05", lngRecords

In this case, the variable lngRecords will hold the number of records that were updated.

horizontal rule

ELIMINATE SPACE IN TABLES

Ever have an HTML table that doesn't quite line up in Netscape? It could be because of extra blank lines in the HTML code. While it's not supposed to make a difference to HTML, it does seem to matter to Netscape. To eliminate the chance of getting some stray white space, construct your tables like this:


<table>
<tr>
<td><!--
--><a href="test.asp"><!--
--><img src="test.gif"><!--
</a></td>
</tr>
</table>
The goal is to make everything within a TD tag a continuous line of text with no white space in the file. Using the comments to break the lines accomplishes this goal.

horizontal rule

ELIMINATE TOP AND LEFT MARGINS

One feature available in Internet Explorer that isn't currently available (as of 4.71) in Netscape Navigator is the ability to change the margins of your HTML page. By setting the LEFTMARGIN and TOPMARGIN properties of the BODY tag, you can change how much space is displayed on the top and left of the page. The stripe is a background image, but you'll see that the text is all forced to the left edge of the page.  By setting the leftmargin and topmargin properties of the BODY tag, you can change how much space is displayed on the top and left of the page. In fact, you can eliminate these margins by setting the following parameters:

<body leftmargin=0 topmargin=0>

If you're using Netscape, you have to use different parameters in order for this to work. In Netscape, you can create this tag for the same effect:

<body marginheight=0 marginwidth=0>

If you're writing for both browsers, you can use this version of the tag as well:

<body leftmargin=0 topmargin=0 marginheight=0 marginwidth=0>

Internet Explorer 5.0 users can visit the following site to see this in action:

http://www.northcomp.com/

horizontal rule

EMBEDDING DOUBLE QUOTES

One thing you have to do often when writing ASP is generate HTML links. This may involve embedding double quote characters in your printed output, like this:

Response.Write "<a href=""contents.asp?id=253"">Click here</a>"

While the double quotes in the link are not required, they are recommended. However, this code gets even more cumbersome if you embed a variable value for the ASP filename, as in this example that uses the SCRIPT_NAME server variable:

Response.Write _ "<a href=""" & Request("SCRIPT_NAME") & "?id=253"">Click here</a>"

To help ease this situation, I define a constant for the double quote character, called DQ, like so:

Const DQ = """"

Yes, there are four double quote characters here--the first and last delimit the string, and the inner two represent a double quote character that I want to print. Now, the previous code can be changed to

Response.Write _ "<a href=" & DQ & Request("SCRIPT_NAME") & "?id=253" _
& DQ & ">Click here</a>"

For many users, this code is easier to understand (and to write) than the three double quote characters in a row.

horizontal rule

ENCODING YOUR SCRIPT

Users have asked me if there's a way to secure the script in a Web page. The short answer is: Yes, using the new Microsoft Script Encoder. You can download this tool (for free) from the Microsoft Scripting site:

http://msdn.microsoft.com/scripting

horizontal rule

FILTERING A RECORDSET

If you have a recordset already created and want to filter it by some criteria, you can use the Filter property of the recordset to do it. Just change the recordset's Filter property to a WHERE clause and then set the recordset object to another recordset variable, like this:


Dim objRS, objFilter ' As ADODB.Recordset
Dim dcnDB ' As ADODB.Connection
Set dcnDB = Server.CreateObject("ADODB.Connection")
dcnDB.Open "Some connection string"
Set objRS = Server.CreateObject("ADODB.Recordset")
objRS.Open "SELECT * FROM tblOrders", dcnDB, adOpenStatic

objRS.Filter = "CustomerName Like %Smith%"
Set objFilter = objRS
Depending on how big the recordset is, you may want to simply do another query from the database. It will probably run faster, especially if you create a stored procedure to do the work for you. Also, make sure you have indexes on the fields that you're using in your filters.

horizontal rule

FINDING OLE DB PROVIDERS

When you're using ADO, you have to use an OLE DB provider to access the database. If you're using a database that doesn't have an OLE DB provider, you can get one from several companies. Microsoft maintains a site with all of the third-party OLE DB providers available. Here's the URL:

OLE DB Providers List

horizontal rule

FLEXIBLE CLIENT-SIDE VALIDATION

The ASPToday site has a good article on creating flexible, client-side, JavaScript-based validation for your Web pages. Here's the URL:

http://www.asptoday.com/articles/20000328.htm

This technique provides a good alternative to roundtrips to the server, if you are allowed to use client-side scripting in your application.

horizontal rule

GETTING INFORMATION FROM EXTERNAL WEB SITES

Ever want to include information like stock quotes or headlines on your Web site? In this article at the FourGuysFromRolla Web site, you can see how to use the Internet Transfer control (included with Visual Basic) to do just that. Here's the URL for the article:

http://www.4guysfromrolla.com/webtech/040600-1.shtml

horizontal rule

IMPROVING OUTPUT PERFORMANCE

To increase the performance of your Web page output, you can use output buffering. Output buffering stores all of the output while the page is being built. However, users won't see any output until the page is complete. In long-running pages, this could cause users to cancel the connection. To turn on output buffering, use this statement:

Response.Buffer = True

To cause the buffer to be sent to the user, you can call the Response.Flush method. To erase the buffer, call Response.Clear.

One of the nice things about buffering is that you can use Response.Redirect any time after you've put content in the buffer and before you send it to the user. This makes it a bit easier to code your application, but keep in mind that the user won't see any content until you've finished building the page.

Another important thing to remember is that in IIS 4.0, buffering is turned off by default. In IIS 5.0 running on Windows 2000, buffering is turned ON by default. If you've relied on using unbuffered pages, you'll need to turn off buffering at the beginning of your page.

horizontal rule

IMPROVING SITE PERFORMANCE--PART 1 OF 4

There are some simple things you can do to improve your Web site's performance--depending, of course, on the structure of your site. For the purposes of this series of tips, let's assume you're using a database to get data and show it on the output page.

The first thing you can do to improve performance is to use predefined queries or stored procedures (depending on your database). With most databases, this feature allows the database to skip the work involved in optimizing the query. This alone will often speed up operations significantly, depending on the types of queries you're doing.

horizontal rule

IMPROVING SITE PERFORMANCE--PART 2 OF 4

There are some simple things you can do to improve your Web site's performance--depending, of course, on the structure of your site. For the purposes of this series of tips, let's assume you're using a database to get data and show it on the output page.

One such way to improve performance is to retrieve only the fields you need from the database. There's always a temptation to simply say SELECT * FROM allmytables, when in fact you need only a field or two. Depending on the size of the table, this tip can vary in its effectiveness.

horizontal rule

IMPROVING SITE PERFORMANCE--PART 3 OF 4

There are some simple things you can do to improve your Web site's performance--depending, of course, on the structure of your site. For the purposes of this series of tips, let's assume you're using a database to get data and show it on the output page.

If you have access to Microsoft Transaction Server (MTS) and the ability to create COM DLLs, you can gain quite a bit of performance by creating an MTS object that handles your database activity. This has the benefit of holding the connection open until a timeout period expires. Since making the connection is the most "expensive" part of getting data, you just chopped your request time down significantly.

horizontal rule

IMPROVING SITE PERFORMANCE--PART 4 OF 4

There are some simple things you can do to improve your Web site's performance--depending, of course, on the structure of your site. For the purposes of this series of tips, let's assume you're using a database to get data and show it on the output page.

If you're doing a lot of database recordset manipulation in ASP, this is best handled within a COM DLL, since the code is all compiled. I have part of my ad system that's currently in an ASP page. It requests three or four recordsets through an MTS database object, but I'll be moving the logic into a COM object and should see the performance improve greatly.

horizontal rule

KNOW WHEN TO USE WHICH LANGUAGE

This question keeps coming up, so I thought I should answer it again. Several users have asked whether they can use JavaScript with ASP. Here's the answer: Yes. You can use JavaScript (or any other language that you can install on Windows NT) with ASP. You can use it both on the server and as part of the client page. However, don't expect to find much support for JavaScript on the server. All of the ASP books I've picked up lately use VBScript exclusively on the server. All the support information you'll find at Microsoft's site for ASP is written using VBScript, as are all the examples in the Microsoft Developer Network Library.

However, nearly every book I've seen uses JavaScript on the client side. This is because VBScript isn't supported universally (that is, in Netscape) as a client-side scripting language. JavaScript is supported by both major browsers (and some of the minor ones, as well) and has widespread book and third-party support through Web sites and other support mechanisms.

horizontal rule

LEARNING XML

You've probably heard about XML and the great potential it has as the next language for the Web. If you want to try out your XML skills, you can download an XML parser from Microsoft's Developer Downloads section:

http://msdn.microsoft.com

There's also a validation tool that you can use to make sure your code is correct before you send it out. This is a good way to build your skills until the next version of Internet Explorer--which will support XML--is released.

horizontal rule

MANUALLY CREATING A RECORDSET

One of the features of the ADO recordset is that it can be created manually. Instead of creating a recordset by way of a database, you can create a recordset, add various types of fields to it, and then add data to it. You can then manipulate it just like a database-created recordset, save it to disk, or pass it back from a component for use in an application.

After you create the recordset object, you can use the Add method of the Fields collection to create new fields for your recordset. When you create these fields, you can specify the data type, the field length, and so on. Once you have the fields added, you can use the Open method to open the recordset for modification. You then use the AddNew method to create a new record, followed by the Update method to commit the record to the recordset. Refer to the ADO Fields collection for more information about this feature.

horizontal rule

MICROSOFT DATA ENGINE VS. MICROSOFT ACCESS

While Microsoft Access works reasonably well for small Web sites, it just doesn't have the scalability of SQL Server. However, for most people, SQL Server's price puts it out of reach. Halfway between these two options is the Microsoft Data Engine (MSDE). This product provides better scalability and reliability than Access does, but it doesn't have SQL Server's price tag. For more information on MSDE, go to Microsoft's Web site and download this white paper, which discusses the differences between Access and MSDE:

http://www.microsoft.com/sql/productinfo/Access2000Jet&MSDE.doc

horizontal rule

MICROSOFT PARTY LINE ON VBSCRIPT AND JSCRIPT

Want to hear about Microsoft's plans for VBScript and JScript? Read this article by the product manager of the scripting group to learn how Microsoft intends to support both languages and how you should use them yourself:

http://msdn.microsoft.com/workshop/languages/clinic/vbsvjs.asp

horizontal rule

MODIFYING A RECORD'S PRIMARY KEY

A user asked if it was possible to modify the primary key of a database record. This depends on how the database table was created. If the database table uses a counter or auto-number field, you won't be able to update the key. However, if the primary key is on a field that is just a number or other modifiable value, changing the primary key is just like changing any other field. Remember that once the change is saved to the system, you'll need to access the record with the new key and not the old one.

horizontal rule

MOVE METHODS NOT AVAILABLE

Recently, a user asked why, when he created a recordset, some of the move methods (such as MovePrevious and MoveLast) are not available. The reason for this is that the recordset was created as a ForwardOnly recordset. The other three types of recordsets can use the Move, MovePrevious, MoveFirst, and MoveLast methods. In many cases, you'll just need to do a MoveNext as you loop through a recordset. However, if you need to move around throughout a recordset, be sure to first create it as a different type of recordset.

horizontal rule

MTS COMPONENTS MUST BE REGISTERED

We've recently published some tips about using Microsoft Transaction Server with DLLs created in tools like Visual Basic. One thing to remember is that while you can drag a DLL from Explorer into the MTS Explorer, that DLL must be registered with the system (using Regsvr32.exe). If it's not, you won't be able to create objects from your DLL, regardless of whether it's in an MTS package.

horizontal rule

NEW TIMER FUNCTION

If you've ever wanted to time your scripts to make sure they don't take too long, VBScript 5.0 has a new feature for you: the Timer function. This function returns the number of seconds that have elapsed since midnight, which lets you easily determine the length of time a chunk of code takes to execute. Here's an example from the MSDN documentation on this new function:

Function TimeIt(N)
Dim StartTime, EndTime
StartTime = Timer
For I = 1 To N
Next
EndTime = Timer
TimeIt = EndTime - StartTime
End Function

This function will return the number of seconds it took to count from 1 to N. This can be helpful if you're doing performance-tuning on your application. Simply wrap checks of the Timer function around the code in question to get the amount of time required for it to execute.

horizontal rule

SQL SERVER FOR STRING PROCESSING

As you're probably well aware, VBScript in ASP is relatively slow when it comes to string manipulation. However, if you're doing a lot of string "stitching" using data from a database like SQL Server, you can let the server do more of the work for you. Here's a quick example of this in action: This stored procedure is designed to retrieve the name and URL of a bunch of Web sites that are stored in a database table. Instead of having ASP put the URL together with the name, I let SQL Server do it in the stored procedure. In fact, the only thing that ASP has to do is loop through the records and print out the value of the Web site field. Add a UL tag to the top and bottom, and you've got a bulleted list of Web sites. Here's the stored procedure code:


CREATE Procedure sp_RetrieveClientSites As
SELECT
'<li><a href="http://' + RTrim(URL) + '">' + RTrim(Name) + '</a>' As Web site
FROM tblClientSites
WHERE IsActive = 1
Order By Name
You can see this code in action at this URL:

http://www.northcomp.com/res_clients.asp

horizontal rule

OPTIONS FOR ORDERED LISTS

Besides the default Arabic numerals normally used for ordered lists (created with the OL tag), you can create lists that use other number formats to list items. You use the TYPE parameter in the OL tag, along with the following values:


(TYPE=A) - capital letters. e.g. A, B, C ...
(TYPE=a) - small letters. e.g. a, b, c ...
(TYPE=I) - large roman numerals. e.g. I, II, III ...
(TYPE=i) - small roman numerals. e.g. i, ii, iii ...
(TYPE=1) - default numbers. e.g. 1, 2, 3 ...
You can also specify the starting number by using the START parameter. This parameter needs to be used with an Arabic number, as shown here:

<ol type=I start=5>

For this tag, the items will start with Roman numeral 5 (V) and continue from there. This is helpful if you have multiple lists that aren't together or are on separate pages but should be shown as part of the same "outline."

horizontal rule

OWNERSHIP OF CODE

Here's a non-technical tip for today. A user asked about ownership of code that he wrote for a client. The basic answer is: It depends on what you negotiated. (You did get a contract, I hope!) Typically, if you work full-time for someone as an employee, your employer owns anything you create. If you're an independent consultant working for a client, it's up to you (and the client).

I will typically give ownership to the client but include provisions that allow me to use the code for other clients, as long as they don't compete directly with the first client. This lets me reuse code in other projects. Whatever you decide, make sure it's on paper. Also, it's a good idea to get in touch with an intellectual property lawyer if you're really concerned about ownership.

horizontal rule

PASSING VARIABLES BETWEEN PAGES

A user asked how to pass a "variable" between pages without using the Session object. Without using the Session or Application object, there is currently (IIS 4.0) no way to do this. (Windows 2000 folks, there is a way... hang on a sec.) You can, however, pass data between pages in a number of ways:

Make it part of the URL and accessible through the Request.QueryString collection.
Use invisible form fields that are accessible through the Request.Form collection.
Save the data to a disk file and reopen it in the next page.
Save the data to a database table and open it in the next page.

In Windows 2000 and IIS 5.0, you can use the Server.Transfer method to move some information from one page to another. For instance, any data in the Request object will be made available to the second page. However, local variables that you declare won't be available in the new page.

horizontal rule

PERMANENT VS. TEMPORARY COOKIES

If you're using cookies in your application, know whether you're using temporary or permanent cookies. Temporary cookies are cookies that are created without an expiration date, using code like this:

Response.Cookies("MyCookie") = "My Value"

This cookie goes away when the browser is quit. If you need a permanent cookie (for a saved login, for instance), you can set the Expires property like so:

Response.Cookies("MyCookie") = "My Value"
Response.Cookies("MyCookie").Expires = DateAdd("d", 30, Date)

This will give the cookie an expiration date of 30 days. In this case, the cookie will be written to your browser's cookie directory/storage area.

horizontal rule

PERSISTING A RECORDSET

In multipage applications, there is often a need to pass a recordset's data from one page to another. Besides passing the SQL statement or storing the recordset in the Session or Application object, you have more options in ADO. You can, for example, save the recordset to a disk file. Once you've saved the recordset, you can reopen the recordset by filename. The Save method of the recordset object allows you to specify a pathname. To reopen a file in another recordset, you specify the pathname in the Open method instead of a SQL string. One thing to remember is that the directory to which you write your saved recordsets must be writeable by your Web server user ID, whatever that happens to be.

horizontal rule

READY OR NOT, HERE COMES XML

Not sure how your ASP application fits in with XML? Here's a recent article in Windows NT magazine that explains how the two technologies fit together:

http://www.winntmag.com/Articles/Content/8523_01.html

horizontal rule

REMEMBER TO SET COMMANDTYPE

I recently ran into a problem involving an ADO Command object. I was trying to use a stored procedure with SQL Server, but after setting everything, including the parameters, I was getting no results. Of course, the error messages didn't make any sense, either. After reviewing the code, I realized I hadn't set the CommandType property of the Command object. Once I set that, things worked properly. Here's the complete code:

Set cmdQuery = Server.CreateObject("ADODB.Command")
With cmdQuery
Set .ActiveConnection = dcnDB
.CommandType = adCmdStoredProc
.CommandText = "sp_KeywordSearch"
Set parItem = .CreateParameter("Keyword", adVarChar, _
adParamInput, 255, Request("txtKeywords"))
.Parameters.Append parItem
End With
Set rsData = Server.CreateObject("ADODB.Recordset")
rsData.Open cmdQuery, , adOpenStatic

In this case, the stored procedure is named sp_KeywordSearch and takes a parameter called Keyword. The parameter is created and then appended to the Command object. Accordingly, when you open the recordset object, instead of specifying a SQL string, you supply a Command object.

horizontal rule

REMOTE ADMINISTRATION

One of the most overlooked features of Internet Information Server 4.0 is its ability to be administered remotely via the Web. Depending on the installation options you use, you may have up to three directories (Web shares) in your default Web site. BOADMIN is the BackOffice Administrator site, NTADMIN is the NT Administrator site, and IISADMIN is the IIS Administrator site. These shares are restricted, by default, to console users only. However, if you've set up the appropriate security, you can allow them to be used by anyone who has permission. You can change the security for each share by using the Security tab in the Properties dialog box.

horizontal rule

REMOTELY RESTARTING THE SERVER

Here's a tip on how to create a script to start and stop your Web server without having to be on the console. The script, which follows, will prompt for the server name and whether you want to start or stop the services. The script even works via dial-up connection. Of course, you'll first need administrator privileges on the server.

'This script will Start or Stop the IIS related services on a remote server'

Dim ServerName

Dim ServiceSet

Dim Service

Dim StartStop

 

Sub StopServices()

Set ServiceSet =

GetObject("winmgmts:{impersonationLevel=impersonate}!//" _& servername).ExecQuery("select * from Win32_Service")

For each Service in ServiceSet if Service.Description = "World Wide Web Publishing Service"

then

If Service.State = "Running" Then Service.StopService()

End If

ElseIf Service.Description = "Microsoft SMTP Service" then If Service.State = "Running" Then

Service.StopService()

End If

ElseIf Service.Description = "FTP Publishing Service" then If Service.State = "Running" Then

Service.StopService()

End If

ElseIf Left(Service.Description, 9) = "IIS Admin" then

If Service.State = "Running" Then

Service.StopService()

End If

ElseIf Service.Description = "MSDTC" then

If Service.State = "Running" Then

Service.StopService()

End If

End If

Next

End Sub

 

Sub StartServices()

Set ServiceSet =

GetObject("winmgmts:{impersonationLevel=impersonate}!//" & servername).ExecQuery("select * from Win32_Service")

For each Service in ServiceSet

if Left(Service.Description, 9) = "IIS Admin" then

If Service.State <> "Running" Then

Service.StartService()

End If

ElseIf Service.Description = "Microsoft SMTP Service" then

If Service.State <> "Running" Then

Service.StartService()

End If

ElseIf Service.Description = "FTP Publishing Service" then

If Service.State <> "Running" Then

Service.StartService()

End If

ElseIf Service.Description = "World Wide Web Publishing

Service" Then

If Service.State <> "Running" Then

Service.StartService()

End If

ElseIf Service.Description = "MSDTC" then

If Service.State <> "Running" Then

Service.StartService()

End If

End If

Next

End Sub

 

ServerName = InputBox("Enter the NetBIOS Name of the Server you would like to process")

StartStop = InputBox("Would you like to START or STOP the IIS services? " _

& (Chr(13) & Chr(10)) & "Please Enter 'start' or 'stop'" & (Chr(13)

&

Chr(10)) _

& "OR 'quit' to Exit","Start Or Stop Remote IIS Services","quit")

If lcase(StartStop) = "stop" Then

StopServices

Wscript.Echo "Services Stopped!"

ElseIf lcase(StartStop) = "start" Then

StartServices

Wscript.Echo "Services Started!"

Else

Wscript.Echo "No Action Taken."

End If

horizontal rule

SAVING A RECORDSET

One of the features of the ADO Recordset (in ADO 2.5) is the ability to save the recordset to a disk file. There are currently two file formats you can use. The first (and default) is called the Advanced Table DataGram Format. This file format will allow you to reload the recordset by specifying its filename as the source when you open your recordset. Here's the code for saving the recordset:

Dim dcnDB ' As ADODB.Connection
Dim rsData ' As ADODB.Recordset

Set dcnDB = Server.CreateObject("ADODB.Connection")
dcnDB.ConnectionString = _
"Provider=SQLOLEDB;" _
& "Data Source=Server;" _
& "Initial Catalog=DB;" _
& "User ID=user;" _
& "Password=password;"
dcnDB.Open
Set rsData = dcnDB.Execute("SELECT * FROM Customers")
rsData.Save "C:\DataFile.txt"
rsData.Close
dcnDB.Close

To reopen this file, you do the reverse:

Dim rsData ' As ADODB.Recordset
Set rsData = Server.CreateObject("ADODB.Recordset")
rsData.Open "C:\DataFile.txt"
Do Until rsData.EOF
Response.Write rsData("CompanyName") & "<br>"
rsData.MoveNext
Loop
rsData.Close

If you need to save searches, this is a fairly straightforward way to do it: Save the results to a file that you can reload later.

horizontal rule

SCHEDULING A PAGE

A reader asked if there's a way to schedule an ASP page to run every month at a specific time. Not knowing the specific purpose our reader had in mind, I'll share a couple of ways to do this.

The easiest way (assuming the Web page didn't require any input) is to schedule a task in Windows to run your browser with the URL as part of the command line (assuming your browser has this ability, which it should). The Windows Task Scheduler will give you a number of scheduling options, including the once-a-month option that our reader requested. You can also do this from the server side, but in that case, it's probably easier to use a stored procedure scheduled through SQL Server. Finally, you can use a client running on the server (instead of the Web page) to do the task.

horizontal rule

SCRIPTLESS ASP FILES

In IIS 4.0, it is more efficient to name all static content files (with no ASP code in them) using an .HTM or .HTML extension. This way, the server doesn't have to process them through the ASP engine. However, IIS 5.0 is much smarter about processing these so-called scriptless ASP files, and the server processes these files much more quickly. This means IIS 5.0 users can give all files the .ASP extensions, just in case it's necessary to add ASP code in the future.

horizontal rule

SEARCHING LONG TEXT FIELDS IN SQL SERVER

One thing currently done on the ASP Techniques  Web site is store all the content in a SQL Server database. Because of some long text articles, these are stored  in ntext fields. The problem is that in SQL Server, ntext fields are not searchable using the LIKE keyword. This makes performing keyword searches impossible.

However, using the Full-Text Indexing feature of SQL Server, it can support keyword searches. IT will specify the table(s) and field(s) to index, and SQL Server automatically creates a full-text index of those fields. The best part is that the SQL query still uses the same LIKE keyword. It's basically transparent at the SQL level, and since the indexing runs automatically when the system isn't busy, it doesn't put extra work on a busy server.

horizontal rule

SHOWING GRAPHS AND CHARTS ON A WEB PAGE

A user asked about the best way to show a graph or chart on a Web page. For this, you basically have three options. First, if the chart isn't really complicated (for example, a simple bar chart), you could draw a graphic and stretch its width or height to a proportional size. The graphic might only be 2 pixels high and 10 pixels wide, for instance--but you could expand it to 60 pixels high and 10 pixels wide to show 30 percent or 30 units.

A second option is to use a Java applet, which can be controlled from your ASP file. There are a number of applets available, both commercial and freeware, to do this. One good source for Java applets is Gamelan:

http://gamelan.earthweb.com/

A third option, if you have the ability to do so, is to use one of many ActiveX controls to show your graph or chart. Like Java applets, there are a number of commercial and freeware controls available. You can get these controls at a number of Web sites, including

ComponentSource

VBxtras

horizontal rule

SITE SERVER'S DIRECTMAIL FUNCTIONALITY

A recent article at ASP Today shows you how to use the DirectMail feature of Site Server 3.0 to keep your customers and visitors updated about changes to your site. Here's the URL:

"Keep in Touch with DirectMail"

horizontal rule

UPDATING AN ACCESS DATABASE

A user asked me why, when he attempted to upload an Access database in place of an existing one, he got errors indicating that the file was in use by another process. Access is a file-system database, which means that everything dealing with the database is in one file. The problem is that if someone is using a Web page that uses the database, the server locks the database file open. The only safe time you can replace it is when no one is using the database. This generally means stopping the server long enough to replace the database.

Instead of this method, I prefer to create a user interface for updating/modifying/deleting data in the database, no matter which database I'm using. This completely prevents the problem with Access since, thanks to the user interface, I don't need to fix the database directly. The exception would be a database structure change (new tables, queries, etc.). In this case, I stop the Web server, make the changes, and then start the server again. I try to avoid making structural changes on the fly, but on occasion, you have to.

horizontal rule

UPDATING COMPONENTS AND MICROSOFT TRANSACTION SERVER

One of the nice benefits of Microsoft Transaction Server  is that you can remove and add components to MTS packages without any rebooting at all. Simply remove the component from the package and add the component to the package again. MTS may at times take 30-60 seconds to release the component, so if it doesn't work right away, try it again later.

horizontal rule

USE SERVER.TRANSFER INSTEAD OF RESPONSE.REDIRECT

I do a lot of redirection in my Web applications. A user logs into a page, and an ASP file processes the input. When the user login is validated, Response.Redirect sends the user to the next page. However, in IIS 5.0, the Server.Transfer method can be used for better results. Response.Redirect actually causes a roundtrip from the user's browser to the server. It puts a code in the HTTP header that tells the browser to request the next page. Server.Transfer simply moves from one page to the next without that roundtrip. If you're using the Redirect method of coding and you're on IIS 5.0 (Windows 2000), start changing your code to make it more efficient by using Server.Transfer. Your users will get a better experience with less roundtrips to your server.

horizontal rule

USING ACCESS DATABASES WITH ASP

Recently, a few questions about Access databases--and their relation to ASP--have come to my attention. When working with Access databases, one of the first things you have to do is to make sure your database is in a directory that is writeable by the Web server. You can't typically put your database in your Web directory because your Web directory is often marked as read only. Typically, I'll make a separate directory outside the Web site hierarchy and mark it as writeable for my Access databases. Of course, I personally prefer SQL Server, but your mileage and capabilities may vary.

The other question is in relation to which provider to use for hitting Access databases. If you have Access 97 databases, you can use either the Jet 3.51 or Jet 4.0 providers. However, if you have Access 2000 databases, you have to use the Jet 4.0 provider. If you don't control your Web server (such as in a virtual hosting situation), you'll need to check with your provider to see which ADO providers are available on the server.

horizontal rule

USING CLASSES IN VBSCRIPT 5.0

One of VBScript's newest features is the ability to use classes, just like in VB or VC++. Here's an article at ASP Today about this new feature, currently available in IIS 5.0 and Internet Explorer 5.0:

http://www.asptoday.com/articles/20000216.htm

horizontal rule

USING MTS COMPONENTS WITH ASP

In a previous tip, I mentioned that components you use with Microsoft Transaction Server (MTS) have to first be registered on the server before you can add them to a package. Actually, this is not exactly correct. Granted, it's true that when you use the Import Component feature and select Add Component, MTS lists only the components that are registered. However, the Import Files feature will let you pick a DLL that isn't registered and use it within an MTS package. You can also drag and drop components from Windows Explorer into an MTS package. What's more, MTS automatically registers the components when you add them in either of the latter two methods.

CORRECTION: Previously, we sent this tip with a slight error. The fourth line erroneously read Request(item.Name) instead of Request(item.Value). 

.Here, then, is the tip as it should have appeared:

In an application I'm writing, I have a form that shows a large number of check boxes. These check boxes each become a record in a database table related to the primary entity. To make it easy to insert the appropriate records for the main record, I created a naming structure for each box based on the primary key of the value shown by the check box. Prefixing the name with dbchk then made it easier to find when looping through the Request collection. Once I determine if the box is checked, I call a stored procedure to insert the record into the table. Here's an example of how to check the value, assuming the name is dbchkValue##, with ## being the number of the category.

Dim item ' As Variant
For Each item in Request.Form
If Left(item.Name, 5) = "dbchk" Then
If Request(item.Value) = "Y" Then
dcnDB.Execute("sp_AddRecordToTable " & Mid(item.Name, 11))
End If
End If
Next ' item

This code will automatically insert a row into the table for each check box that is marked. It also saves you from having to write lots of redundant code to insert particular rows into the table.

horizontal rule

USING SQL SERVER FOR DATE PROCESSING

As you learned in a previous tip, ASP is slow when it comes to formatting text. In addition, it has too few functions for manipulating dates. For this reason, I decided to let SQL Server handle some of my date work in a page I built listing books I've written. Here's how the final output looks:

http://www.northcomp.com/res_bookstore.asp

and here's the stored procedure I used:


CREATE procedure sp_RetrieveBookList
As
SELECT B.pkBookID, B.Name, B.Description, B.ISBN,
'Publication Date: ' + DateName(month, B.PubDate)
+ ' ' + Cast(Year(B.PubDate) As varchar(4))
As DatePublished,
'/pics/book_' + B.ISBN + '.gif' As BookGraphic,
'<a href="' + RTrim(S.URL) + '">' +
RTrim(S.Name) + '</a>' As WebSite
FROM tblBooks B, tblSites S
WHERE b.fkSiteID = S.pkSiteID
Order By B.PubDate Desc
In this case, I used SQL Server's built-in functions for extracting the month name and year of the publication date. Instead of returning those values, I put them together with the appropriate text and returned the whole thing as a single field. I also stitched the ISBN number with a directory and a file extension to create the local URL to point to the book cover graphic. Finally, I returned the support Web site name and URL together as a single field.

Note that I used a Cast function around the result of the Year function. This is because SQL Server assumes that since you're adding a string (the month name and space) to a number, you must want to convert the whole thing to a number. This causes an error, but using the Cast function eliminates the problem.

If you're working with an affiliate program, such as one run by online bookstores, you can easily create multiple URLs using the book's ISBN number and the affiliate URL provided by your bookstore. Again, leave the string manipulation on the server, where it will run faster.

horizontal rule

USING SQL SERVER FOR STRING PROCESSING

As you're probably well aware, VBScript in ASP is relatively slow when it comes to string manipulation. However, if you're doing a lot of string "stitching" using data from a database like SQL Server, you can let the server do more of the work for you. Here's a quick example of this in action: This stored procedure is designed to retrieve the name and URL of a bunch of Web sites that are stored in a database table. Instead of having ASP put the URL together with the name, I let SQL Server do it in the stored procedure. In fact, the only thing that ASP has to do is loop through the records and print out the value of the WebSite field. Add a UL tag to the top and bottom, and you've got a bulleted list of Web sites. Here's the stored procedure code:


CREATE Procedure sp_RetrieveClientSites As
SELECT
'<li><a href="http://' +
RTrim(URL) + '">' + RTrim(Name) + '</a>' As WebSite
FROM tblClientSites
WHERE IsActive = 1
Order By Name
You can see this code in action at

http://www.northcomp.com/res_clients.asp

horizontal rule

USING STYLE SHEETS AND SQL FOR OUTPUT

As I've mentioned in previous tips, it's much quicker to manipulate strings within either SQL Server or compiled components. However, if you're generating HTML from one of these sources, you would then have to embed colors, fonts, and such in the HTML you're generating. Accordingly, to change the look of your page, you'd have to go back to your compiled code or your stored procedures and change the code there.

The alternative I use is to generate style sheet tags from the compiled components and stored procedures. This allows me to change the colors, fonts, and other attributes outside the code. In addition, I can use the same code for multiple sites, since the style sheet can be redefined for each Web site for which it is used.

horizontal rule

USING THE BILL OF MATERIALS STRUCTURE

One of the most useful things about relational databases is the ability to create parent-child relationships in a single table. You'll find an example of this on the ASP Techniques  Web site, where each category is either a root-level category or a subcategory of another. This is all done with a single table, where each record has a foreign key to its parent.

The Bill of Materials Structure refers to this type of setup. Part 1 is composed of parts 2 and 3, each of which is composed of other components. In this article at ASP Today, you can learn how to build this structure and make it work in your application:

http://www.asptoday.com/articles/20000516.htm

horizontal rule

USING THE EVAL FUNCTION

A new function available in VBScript 5.0 (IIS 5.0, IE 5.0) is the Eval function. If you've ever wanted to create a conditional expression in a string and have it tested, this is the function for you. Here's an example:

Dim X, Y
X = 3
Y = 4
If Eval("X = Y") Then
Response.Write "Values are equal"
Else
Response.Write "Values are not equal"
End If

The Eval function will accept any valid comparison expression. Be sure that any variables are declared before using them in your Eval expressions.

horizontal rule

USING THE JET 4.0 PROVIDER WITH ACCESS 97

The Jet 4.0 OLE DB provider is able to read Access 97 and Access 2000 databases. However, there have been a number of problems reported with this method. In certain cases, the driver will stop serving ASP pages and will on occasion cause 100 percent CPU usage on servers. The solution to this problem is to upgrade your Access 97 database to Access 2000. Microsoft has promised a Knowledge Base article on this problem, but none exists as of yet. 

horizontal rule

USING THE METADATA TAG

In a previous tip, you learned how to reference the ADO library in your ASP file. This lets you use the documented constants along with the ADO library. Again, here's the code you'll need at the top of your ASP file. (This should all go on one line.)

<!-- METADATA TYPE="typelib" FILE="c:\program files\common
files\system\ado\msado15.dll"-->

You can use this tag for any DLL you happen to be using. For instance, if you're using the FileSystemObject and related objects, you can reference the Microsoft Scripting Runtime file, or scrrun.dll. In Windows 2000, this file is located in the \WINNT\System32 directory, so the tag would be

<!-- METADATA TYPE="typelib" FILE="c:\winnt\system32\scrrun.dll"-->

Keep in mind that you may have to search your system to find the precise location of this file within your setup.

horizontal rule

VIEWING A LIST BOX'S DATA

If you have a SELECT list on your ASP page that allows multiple selections (using the MULTIPLE keyword in the SELECT tag), those selections will come into the ASP code as a comma-separated list of values. An easy way to break them into an array is with the Split function. The Split function will break a line of text into an array of elements based on a delimiter character you specify. Here's an example:


Dim a_strStrings ' As Array of Strings
a_strStrings = Split(Request("ListBoxData"), ",")
This will break the contents of the ListBoxData field in the Request collection into an array. You can use the Lbound and UBound functions to determine the lower and upper limits of the array that's created. Looping through those items will let you process each of those items. If you need to put them in a database, you can create a SQL statement for each item in turn.

horizontal rule

VISUAL BASIC DIRECTORY AT ABOUT.COM

If you ask me, About.com is one of the better sites for content these days. (And no, I'm not getting a kickback!) Every topic within About.com has a live person picking which content will be displayed, and this keeps the content current and fresh. Here's About.com's ASP site:

http://html.about.com/msubasp.htm

horizontal rule

WHEN A SESSION EXPIRES

A user asked me to clarify when a session actually expires. According to Microsoft's documentation, a session will expire after a certain amount of inactivity by that particular user. The session doesn't time out when you move from one page to another. What's more, any temporary session cookies are removed when the session times out, but permanent cookies are not affected by a session timeout.

The expiration time can be changed in the Timeout property of the Session object, and you can expire a session immediately with the Abandon method. However, in my experience with IIS 4.0, this method doesn't always work properly, so use it with caution.

horizontal rule

WORKING WITH MULTIPLE CHECK BOXES

In an application I'm writing, I have a form that shows the user a large number of check boxes. These check boxes each become a record in a database table related to the primary entity. In order to make it easy to insert the appropriate records for the main record, I created a naming structure for each box based on the primary key of the value shown by the check box. Prefixing the name with "dbchk" makes it easier to find when looping through the Request collection. Once I determine whether the box is checked, I call a stored procedure to insert the record into the table. Here's an example of how to check the value, assuming the name is dbchkValue##, with ## being the number of the category:


Dim item ' As Variant
For Each item in Request.Form
If Left(item.Name, 5) = "dbchk" Then
If Request(item.Name) = "Y" Then
dcnDB.Execute("sp_AddRecordToTable " & Mid(item.Name, 11))
End If
End If
Next ' item
This will automatically insert into the table a row for each check box that is marked. It also saves you from having to write lots of redundant code to insert individual rows into the table.

horizontal rule

BUFFERING AND DEBUG STATEMENTS

One of the things I do frequently while I'm programming is dump values to indicate where I'm at as the page executes. However, if an error occurs, I may or may not see the lines created with Response.Write. The property that controls this is the Response.Buffer property, and if buffering is turned on (which it is by default in Windows 2000), I'll see the error message but no other text. If buffering is turned off (as in Windows NT 4.0), I'll see all the text generated up to the point that the error occurred.

If you're building your pages and anticipate errors, you can turn off buffering, either at a site-wide level or on a per-page basis, with this code:

Response.Buffer = False

horizontal rule

INTEGRATION WITH QUICKBOOKS

A user recently asked me if it was possible to integrate ASP with QuickBooks. The short answer is, unfortunately, no. QuickBooks uses a proprietary format for storage of data that is not accessible through OLE DB or any other common method. However, you can export data from QuickBooks (as can you import data into it), so you can at least work with that exported data. Here's a URL at the QuickBooks site that documents this more completely:

http://www.intuit.com/support/quickbooks/faqs/win/1208.html

horizontal rule

PROTECTING YOURSELF FROM SCRIPTING ATTACKS

In this article at ASP Today, James Brannan describes how to prevent cross-site scripting attacks on your site. It's worth checking out:

"Protecting Yourself, Your Site, and Your Clients from Cross-Site Scripting Attacks"

horizontal rule

VISUAL STUDIO SERVICE PACK 4 AVAILABLE

If you're using any part of Visual Studio, be aware that Service Pack 4 is now available. A list of fixes and features is available at

Microsoft Visual Studio 

horizontal rule

ALWAYS PROVIDE A CASE ELSE

When using the Select Case statement, always have a Case Else that will pick up any cases not matched in your list. Even if you're sure that extraneous values can't be processed by your code, it's a good idea to include a Case Else, as shown here:

Select Case intTest
Case 1:
' do something
Case 2:
' do something else
Case Else:
' this is probably an error, so
' display an appropriate message
End Select

horizontal rule

ASP CRASH COURSE WEB SITE NOW AVAILABLE

In advance of the new book, a site has been created the ASP Crash Course site. The book, which is an introduction to Active Server Pages, teaches you ASP and shows you how to build a complete application that is an online organizer, similar to Microsoft Outlook or ACT! You're invited to visit the Web site, listed below, to get a taste of what's in store.

ASP Crash Course

horizontal rule

ASP FILE NOT PROCESSING

A common mistake made by new developers is not running their ASP pages through the Web server. Depending on how the server is configured, putting an ASP page in the URL box in the Web browser can cause the browser to open the file locally. The key is to make sure that the URL always has

http://

in front of it. If you see a drive letter as the start of the URL, you're not viewing the page through the Web server--you're looking at a local copy of the file.

horizontal rule

ASP NOT LOADING IN NETSCAPE

A number of users have complained that their ASP pages are not loading properly in Netscape. If this happens to you, it's not the ASP server-side code that is at issue. Typically, the problem is in the HTML that you're generating. One problem I frequently run into deals with tables. Internet Explorer is much more lax about enforcing table definitions than is Netscape. If you're having problems with a page not displaying, double-check to make sure that each table is properly terminated with a closing tag. In addition, make sure that all the attributes in your tags are quoted, like this:

<table cellspacing="0" cellpadding="0">

The most important step, however, is to make sure that your tags all match up. I prefer to indent the tags, as follows, so I can easily find the beginning and end of each table:

<table>
<tr>
<td>Text</td>
<td>Text 2</td>
</tr>
</table>

horizontal rule

ASP+ RESOURCE DIRECTORY

Microsoft's latest technology, ASP+, is available in a VERY early release. Already, though, there are a number of sites that index various resources for ASP+. DevX.com hosts one such site that's worth the visit:

Microsoft .NET & ASP+ Developer Resources and Information

horizontal rule

CALLING SUBROUTINES

In VBScript, you can call a subroutine simply by using the name of the subroutine, as shown here:

<%
DoSomethingSubroutine arg1, arg2
%>

However, for subroutines without arguments, you may want to make your code easier to find by using the optional Call statement, as shown here:

<%
Call DoSomethingSubroutine
%>

If you have arguments, those need to follow the name of the subroutine, within parentheses. Note that the Call statement can't be used with functions, since functions are always called the same way.

horizontal rule

CAN'T CLONE RECORDSET

A user recently complained that he couldn't use the Clone method on a recordset. This method is available only for recordsets that aren't of the forward-only type. The same thing goes for the various Move methods, as well as the RecordCount, PageSize, and other similar properties.

If you run into difficulties, make sure that you're using a static, dynamic, or keyset recordset before you attempt to clone the recordset.

horizontal rule

CASE SENSITIVITY IN THE REPLACE FUNCTION--PART 1 OF 2

One of the newer VBScript functions, Replace, allows you to replace text within one string with other text. The simplest method for using this function looks like this:

Response.Write Replace("This is a test", "test", "question")

This code will replace the word

test

with the word

question

It will find as many instances of the word test as exist in the first string. However, this version will match case exactly. In the next tip, I'll show you how to ignore case when matching text.

horizontal rule

CASE SENSITIVITY IN THE REPLACE FUNCTION--PART 2 OF 2

As discussed in our previous tip, one of the newer VBScript functions, Replace, allows you to replace text within one string with other text. The simplest method for using this function looks like this:

Response.Write Replace("This is a test", "test", "question")

If you want to ignore case when you are matching text, you have to use a longer version of the function:

Response.Write Replace("This is a test", "test", "question", 1, -1, vbTextCompare)

The fourth argument in this example specifies the start character; the -1 indicates how many instances of test to match. A -1 is the default value that indicates the function should match all the instances in the string. The last argument, vbTextCompare, indicates that comparisons should be done without regard to case. If you want to do exact matching, use the vbBinaryCompare value in place of vbTextCompare.

horizontal rule

CDO LIBRARY AVAILABLE FOR DOWNLOAD

In several previous tips, I showed how you could send email from your Web page using the NewMail object in the CDONTS library. This component has always been available for free from Microsoft. At this point, it's available for download at

http://www.microsoft.com/exchange/downloads/CDO.htm

This page contains the latest version of the component, which is currently 1.21. You can also get this component for IIS 4.0 in the IIS 4.0 Resource Kit. If you're using Windows 2000, the component is already installed on your system.

horizontal rule

CHECKING CHECK BOXES

If you have a form with check boxes on it, remember that if the box isn't checked, you won't get a value back in the Request object. This has caused confusion among my students lately, so I came up with an alternate approach that always provides a value: Use a radio button. Instead of having a check box, I show two radio buttons: one for yes, one for no. In addition, I preselect one of the choices so that I will always get a value back. This has the additional effect of being somewhat clearer to new users who aren't familiar with check boxes. Having a simple yes/no response can be easier to understand.

horizontal rule

CLASSES IN VBSCRIPT

In a previous tip, I told you about the "new" feature of being able to build classes in VBScript to better manage your data. It turns out that if you have Internet Explorer 5.x installed on your server, it replaces the server scripting engine, which gives you VBScript 5.0 and all its features on either NT 4.0 or Windows 2000. The same thing goes for JScript 5.0. 

horizontal rule

CLIENT VERSUS SERVER VALIDATION

In previous tips, I've talked about client- versus server-side validation, and a user recently asked why, if you have client-side validation, do you need server-side validation?

There are several reasons to use server-side validation. The biggest is that JavaScript (the engine behind nearly all client-side validation) can be turned off in the Web browser. Similarly, a client of mine recently decided that client-side scripting was a security risk and was therefore not allowed; without server-side validation in these cases, bad data can get to the database.

Server-side validation may also be necessary for validation that requires a database. For instance, it might make sense to send a list of states from which the user can pick, but it doesn't make sense to send all the US zip codes for the user to choose just one. That's something the server can do better, since it won't have to send all the data to the client. If there are 100,000 US zip codes (5 digit ones only), that's a minimum of 500,000 bytes of data you have to send to the client, and that doesn't even include the city and state name. Other validation, such as determining if a user ID already exists or the password is good, doesn't make sense to be client-side, either.

Another reason is to keep the code in one place. While this is pooh-poohed by some people, it's a major reason in my book. If you have two or more different blocks of validation code to maintain, that's more files to edit than if you have just one COM/COM+ component on the server, for instance, or even in an ASP page as a common routine. While you can use ASP to generate your client-side scripting, client-side scripting simply can't do all the validation you might need. That's one reason some developers choose to do all validation on the server. When this is done, however, you have to minimize the number of trips to the server that the user has to make. If I can, I attempt to validate all input fields when they are submitted to the server, and I send back a single error message with everything that I can find that's wrong. Obviously, if I'm validating a user ID against the database, the user ID has to be entered. That's what I would call "two-step validation", and you can't do all that in one error, but it's a nice goal. That helps eliminate the problem with round-trips to the server taking too long.

horizontal rule

CONNECTING TO NON-MICROSOFT DATABASES

If you're building ASP files to connect to databases other than SQL Server or Access, you'll need either an ODBC driver or an OLE DB provider. For a master list of all available OLE DB providers, check out the page listed below. Nearly every database on the market has a third-party OLE DB provider available for it, and all the products of which Microsoft is aware are listed on this Web site.

Microsoft: OLE DB Products on the Market Today

horizontal rule

CREATING FORWARD-ONLY RECORDSETS

In previous tips, you've learned that when you use the ADO Connection object's Execute method to create a recordset, that recordset is read-only, forward-only. Here's an example:

Dim cnDB ' As ADODB.Connection
Dim rsData ' As ADODB.Recordset
Set cnDB = Server.CreateObject("ADODB.Connection")
cnDB.ConnectionString = "Provider=SQLOLEDB;" _
& "Data Source=(local);" _
& "Initial Catalog=Northwind;" _
& "User ID=sa;" _
& "Password=;"
cnDB.Open
Set rsData = cnDB.Execute("SELECT * FROM Customers")

The forward-only recordset is the most efficient type of recordset when you simply need to read data from the database. It doesn't include all the overhead of a static recordset, but neither does it allow you to manipulate the records with methods by means other than MoveNext.

If you are using other types of recordsets and want to be consistent with how you open your recordsets, you can open a forward-only recordset using the Open method, as shown here:

Set rsData = Server.CreateObject("ADODB.Recordset")
rsData.Open "SELECT * FROM Customers", cnDB, adOpenForwardOnly

This constant is available as long as you've either included adovbs.inc in your file or you've referenced the ADO library using a METADATA tag, as discussed previously.

horizontal rule

DATABASE FIELD DUMP

Ever forget what the fields are in the recordset you just queried? You can write them out as comments to your page just by looping through the Fields collection. Here's how you can do it, assuming you have a valid recordset object:

Dim i ' As Integer
For i = 0 To rsData.Fields.Count - 1
Response.Write "<!-- " & rsData.Fields.Name & " -->" & vbCrLf
Next ' i

This will list the fields as comments that you can view in the HTML output. Remember that you can also use the WriteComment function, as described in a previous tip, which allows you to suppress debug messages when you go to production mode.

horizontal rule

DELETING A COOKIE

Got a cookie that you no longer need? The easiest way to remove it is with the following code, which manipulates the Response.Cookies collection:

Response.Cookies("cookiename") = ""

This will clear the cookie value. Another option is to set the Expires property to the current date and time. The browser will then take care of removing the cookie for you.

horizontal rule

DETECTING INTERNET EXPLORER

If you're building a Web site that is customized based on the user's choice of browser, it's helpful to be able to determine the browser type. In general, you need to use the HTTP_USER_AGENT variable in the Request.ServerVariables collection. If the user is using Internet Explorer 5.0, the value will look something like the following:

Mozilla/4.0 (compatible; MSIE 5.0; Windows 98; DigExt)

IE has been fairly consistent about always including the code "MSIE" in the HTTP_USER_AGENT field. A quick way to determine whether the user has IE, for instance, is as follows:

Dim blnIsIE ' As Boolean blnIsIE = InStr(1, Request.ServerVariables("HTTP_USER_AGENT"), "MSIE", vbTextCompare) > 0

This will give you a true/false value indicating whether the user's browser is a version of Internet Explorer.

horizontal rule

DEVELOPERSITES.COM

A new site for developers has recently come online: DeveloperSites.com. When I visited, the site appeared to be in its infancy--most of the pages were empty. However, it shows a lot of potential; it combines most of the current languages from Microsoft and non-Microsoft sources. By the time you read this, I expect that it will have more content, so stop by.

DeveloperSites

horizontal rule

ERROR WHEN CREATING COOKIES

If you're creating cookies to be sent back to the user's browser, use the Response.Cookies collection. However, you need to do this before you send any HTML to the page. The reason for this is that the cookie commands go into the page header, which has to be created before any HTML is sent.

The exception to this rule is if your Web page is being buffered, either on a per-page basis (using Response.Buffer = True) or on a site-wide basis (by configuring the option in the IIS manager). If the page is buffered, the page is completely constructed before anything is sent to the user's browser.

horizontal rule

FILESYSTEMOBJECT CONSTANTS

If you want to use the constants used with the FileSystemObject family, you can reference the DLL as a METADATA tag at the top of your file:

<!-- METADATA TYPE="typelib" FILE="c:\winnt\system32\scrrun.dll"-->

Remember that you can do this with any DLL you create. In general, scrrun.dll will be located in this directory on your machine. However, you may have to search your machine to find its precise location on your drive.

horizontal rule

FILTERING BY MULTIPLE FIELDS

A user asked how to use the Filter property of the recordset to filter a recordset by more than one field. The answer is to build a more complex WHERE clause to put into the Filter property. Here's an example, assuming the use of two boxes named Request("txtOne") and Request("txtTwo"):

rs.Filter = "Field1 = '" & Request("txtOne") _
& "' AND Field2 = '" & Request("txtTwo") & "'"

You have to concatenate the fields, but you first have to put the right punctuation and keywords between the fields.

horizontal rule

FINDING A PLACE TO BUILD ASP PAGES

I do a lot of ASP training, and many of the people I teach don't have machines where they are allowed to build their pages. Typically, their employers restrict access and/or they don't have machines at home that could have Personal Web Server installed.

Fortunately, there are some solutions for this problem: Brinkster, for one, allows you to create ASP-powered Web sites on its server, for free. If you want to register a domain name, you have to pay $10.95/month, which is comparable to what other services (including my own, Northcomp) charge. The free service supports Microsoft Access databases and doesn't even make you put ads on your site, the way some other free sites do.

Brinkster

Northstar Computer Systems

horizontal rule

FORMATTING PHONE NUMBERS

VBScript includes a few functions to format data, such as FormatDateTime, FormatCurrency, and so on. However, it doesn't have functions to format more specialized data. For instance, in my personal organizer Web application, I show phone numbers in a consistent format: (nnn) nnn-nnnn xnnnn. International numbers beginning with a plus sign don't follow the format, but all North American numbers do. Here's the function that I use to do the formatting:

Function FormatPhone(ByVal strNumber)
Dim strTemp ' As String
Dim strOutput ' As String
Dim i ' As Integer

If Len(strNumber & "") = 0 Then Exit Function
'
' Any phone numbers starting with a plus sign are ignored and
' returned. This takes care of any international numbers
' that might be in the system.
'
If Left(strNumber, 1) = "+" Then
FormatPhone = strNumber
Exit Function
End If

strNumber = LCase(strNumber)
For i = 1 To Len(strNumber)
If IsNumeric(Mid(strNumber, i, 1)) Then
strTemp = strTemp & Mid(strNumber, i, 1)
End If
Next ' i

strOutput = "(" & Left(strTemp, 3) & ") " _
& Mid(strTemp, 4, 3) & "-" & Mid(strTemp, 7, 4)
If Len(strTemp) > 10 Then
strOutput = strOutput & " x" & Mid(strTemp, 11)
End If

FormatPhone = strOutput

End Function

The first line takes care of any empty strings or null values that might be passed to this function (it feeds off database data fairly often). The code then looks for a plus sign, which is often used to indicate an international number. If one is found, the string is returned unchanged.

Next, all non-numeric characters are removed from the string. This takes care of parentheses, periods, dashes, and so on. After that, the remaining characters are broken into the (nnn) nnn-nnnn format, with everything after the first ten digits being added on as an extension.

If you're used to entering a one as the first digit of your phone numbers, you'll need to accommodate it in this function, since I don't prefix numbers with a one. This function lets me enter numbers quickly and not worry about formatting.

horizontal rule

GETTING DATA FROM TWO (OR MORE) DATABASES

In a previous tip, we talked about getting data from two separate data connections and how it wasn't possible to run a query against both. The only way to do this would be to link one database to another within the database itself.

While this won't solve the problem, it is suggested that if you create a manual recordset (see previous tips for the instructions) you could add data from one database and the other, and then use the sorting and filtering capabilities of the recordset to manipulate the data.

horizontal rule

GLOBAL.ASA NOT REQUIRED

If you're building ASP files and not using any Application or Session events, you don't need to create a global.asa file in your directory. As was stated in a previous tip, you shouldn't include empty event handlers for the Application and Session events. The only time you need global.asa is if you want to create those event handlers or create objects at the session or application level.

horizontal rule

HIGH TRAFFIC CRASHES WEB SITE

A user emailed me about his Web site, built using ASP and Microsoft Access, that crashes when too many users visit. Some of the pages are just doing selections, but others are doing database changes. The basic problem with this architecture is that Access can handle only a limited number of simultaneous changes. It does fairly well when it's only handling selects, but when you start making lots of changes to the database, it can run into problems.

In addition, there are bugs with the OLE DB provider used for accessing Access 97 databases. If you use the OLE DB 4.0 provider with an Access 97 database, it can run into problems that cause the system to crash or hang up. The best option is to upgrade the database to Access 2000 before using the OLE DB 4.0 provider. If you don't want to do that, use the OLE DB 3.51 provider with Access 97 databases.

Finally, the best architecture for a busy site that uses a database is to replace Access with SQL Server or another database that can better handle higher levels of traffic. Access does okay, but it's just not designed for high-traffic applications.

horizontal rule

IIS FAQ

Got questions about Internet Information Server or any of the related technologies? You can see an unofficial FAQ about IIS at this site:

IIS FAQ 

It's well organized and has lots of useful information.

horizontal rule

MANUALLY CREATING A RECORDSET--PART 1 OF 3

In previous tips, I mentioned the fact that ADO recordsets don't necessarily have to be created directly from database tables. In fact, you can build a recordset just by defining the fields that should be in the recordset. In this tip, you'll see how to create the recordset. In the next few tips, you'll see how to add data to it, manipulate it, and print the data.

To create a recordset yourself, the first few steps are the same as with a regular database-driven recordset. However, you never have to make a database connection, as shown here:

<!-- METADATA TYPE="typelib" FILE="C:\Program files\Common files\System\ado\msado15.dll" -->
<%
Option Explicit

Dim rsData ' As ADODB.Recordset

Set rsData = Server.CreateObject("ADODB.Recordset")
With rsData.Fields
.Append "Filename", adVarChar, 40, adFldUpdatable
.Append "Size", adInteger, , adFldUpdatable
End With

%>

Once you've created the object, you add to it the necessary fields. In this example, the recordset is going to show a list of files in a particular directory, so I've added some relevant fields. The constants used here for the field types are identical to those used in the Command object. As long as you've referenced the msado15.dll file (as shown at the top), you'll be able to use those constants in your code.

Once the fields are added, you're ready to load data into the recordset.

horizontal rule

MANUALLY CREATING A RECORDSET--PART 2 OF 3

In our previous tip, I showed you how to create a recordset without a live database connection. In this tip, you'll see how to add data to that recordset. Here's the new code, which builds on the core code shown in the previous tip:

<!-- METADATA TYPE="typelib" FILE="C:\Program files\Common files\System\ado\msado15.dll" -->
<%
Option Explicit

Dim objFSO ' As Scripting.FileSystemObject
Dim objFolder ' As Scripting.Folder
Dim objFile ' As Scripting.File
Dim rsData ' As ADODB.Recordset

Set rsData = Server.CreateObject("ADODB.Recordset")
With rsData.Fields
.Append "Filename", adVarChar, 40, adFldUpdatable
.Append "Size", adInteger, , adFldUpdatable
End With
rsData.Open , , adOpenDynamic

Set objFSO = Server.CreateObject("Scripting.FileSystemObject")
Set objFolder = objFSO.GetFolder(Server.MapPath("/"))
For Each objFile in objFolder.Files
rsData.AddNew
rsData("Filename") = objFile.Name
rsData("Size") = objFile.Size
rsData.Update
Next ' objFile
%>

Once you've created the recordset and added all the fields, you have to open it to add records. The Open method doesn't need the typical source (SQL) and data connection arguments, so those are omitted. This particular routine is going to read all the filenames in the root Web directory and add each to the recordset. FileSystemObject is used to loop through the files in the directory. Each one is added to the recordset by way of the AddNew and Update methods.

In our next tip, I'll discuss some things you can do with this recordset once it's created.

horizontal rule

MANUALLY CREATING A RECORDSET--PART 3 OF 3

In the previous two tips, I showed you how to create a recordset without the use of a database connection. In this tip, you'll learn what you can do with this recordset once it's created. Note that the code shown here--especially the Sort property--works fine regardless of how the recordset is created.

<!-- METADATA TYPE="typelib" FILE="C:\Program files\Common files\System\ado\msado15.dll" -->
<%
Option Explicit

Dim objFSO ' As Scripting.FileSystemObject
Dim objFolder ' As Scripting.Folder
Dim objFile ' As Scripting.File
Dim rsData ' As ADODB.Recordset

Set rsData = Server.CreateObject("ADODB.Recordset")
With rsData.Fields
.Append "Filename", adVarChar, 40, adFldUpdatable
.Append "Size", adInteger, , adFldUpdatable
End With
rsData.Open , , adOpenDynamic

Set objFSO = Server.CreateObject("Scripting.FileSystemObject")
Set objFolder = objFSO.GetFolder(Server.MapPath("/"))
For Each objFile in objFolder.Files
rsData.AddNew
rsData("Filename") = objFile.Name
rsData("Size") = objFile.Size
rsData.Update
Next ' objFile

rsData.Sort = "Filename"
rsData.MoveFirst
Do Until rsData.EOF
Response.Write rsData("Filename") _
& " (" & rsData("Size") & " bytes)<br>"
rsData.MoveNext
Loop

rsData.Close
%>

By setting the Sort property to one of the fields of data, you automatically sort the list of files before you print it. If, for instance, you wanted to sort the files by size instead of by name, you would use this line instead:

rsData.Sort = "Size"

horizontal rule

MANUALLY INCLUDING A FILE

In previous tips, I've discussed the power of server-side include files and how they can simplify your programming. Unfortunately, the filenames used in server-side includes can't be dynamic. There's an easy way around this problem, however: FileSystemObject can be used to open a selected file and output it to the user's browser. Note that any ASP code in the file won't be executed, but this generally isn't an issue. Here's the code:

Sub IncludeFile(strFilename)
If strFilename = "" Then Exit Sub

On Error Resume Next
Dim objFSO, objFile, strContents
Set objFSO = CreateObject("Scripting.FileSystemObject")
Set objFile = objFSO.OpenTextFile(Server.MapPath(strFilename), ForReading, False)
strContents = objFile.ReadAll
Response.Write strContents & vbCrLf
objFile.Close
Set objFile = Nothing
Set objFSO = Nothing

This code reads the file in one fell swoop and outputs it to the browser. Note that if you don't have the SCRRUN.DLL file referenced in your ASP code, you'll need to change 'ForReading' to the value 1.

horizontal rule

METHOD=POST VS. METHOD=GET

A frequent question I get deals with the METHOD parameter that is part of the FORM tag. If you use POST, the form data is sent via the request header and is not visible in the URL. If you use GET, the data is put into the URL, and any "dangerous" characters are translated into their numeric equivalents (similar to what Server.URLEncode does). One benefit of using GET is that if you are building a page dynamically based on form input, the GET will allow all that data to be saved on the URL. This lets you send or save the URL for later use.

horizontal rule

MICROSOFT .NET FRAMEWORK SDK AVAILABLE

If you're feeling brave and have a spare Windows 2000 machine, you might want to take a look at the Next Generation Web Services now available from Microsoft. This is a preview release, which means if anything goes wrong, you're on your own. However, if you want to get a jump on ASP+ and some of the new technologies, you might want to take a look at it. You can download the software (about 80 MB worth) here:

http://msdn.microsoft.com/downloads/

horizontal rule

MIGRATING FROM IIS 4 TO IIS 5

In this online chat at the Microsoft Web site, you can read a chat transcript that discusses migrating from IIS 4.0 to IIS 5.0 on Windows 2000. Here's the link:

http://www.microsoft.com/technet/chats/trans/iis0209.asp?a=printable

horizontal rule

MODULARIZING HTML RENDERING

In previous tips, I've talked about the benefits of generating HTML using ASP code, like this:

Response.Write "<html><head>"

Under Windows NT 4.0 (IIS 4.0), this method runs faster than creating a mix of HTML and ASP blocks within the same page.

Along the same lines, there's no reason you can't create utility functions to build some of the HTML for you. For instance, when I'm building input forms, I often need to create text boxes. Instead of duplicating all the Response.Write statements, I've created a series of functions that generate each type of control. (Incidentally, this is similar to how ASP+ works.)

Here's my HTMLTextBox function:

Sub HTMLTextBox(blnInTable, strName, strSize, strMaxLength, strValue)

If blnInTable = CTRL_IN_TABLE Then WriteLine "<td>"

WriteLine "<input type=""text"" name=" & DQ & strName & DQ _
& " size=" & DQ & strSize & DQ _
& " maxlength=" & DQ & strMaxLength & DQ _
& " value=" & DQ & strValue & DQ & ">"

If blnInTable = CTRL_IN_TABLE Then WriteLine "</td>"

End Sub

I also have a couple of constants defined to indicate whether to put the text box into a table cell (which I often do):

Const CTRL_IN_TABLE = True
Const CTRL_NO_TABLE = False

In addition, I use this WriteLine routine (which we've covered previously):

Sub WriteLine(strText)
Response.Write strText & vbCrLf
End Sub

This type of code lets me focus on the function of the page, not how I render it. What's more, if you're using JavaScript to verify that text has been entered in a field, there's no reason you can't expand the function to force the field to be required. In this case, having a routine build the code also serves to keep the code consistent throughout the application.

horizontal rule

MORE ASP TIPS AT ASPTIPS.COM

asptips.com is a resource hosted and written by Aaron Bertrand and Jay McVinney for ASP developers seeking tips and answers to frequently asked questions. There are lots of good tips here, but it doesn't look like the site has been updated for a while (the copyright is still showing 1999).

ASPtips 

horizontal rule

MOVEPREVIOUS NOT WORKING

A user recently sent me a question about why the MovePrevious method was not working in his recordset. The explanation is that the recordset can't be created as a ForwardOnly recordset if you want the MovePrevious (or MoveLast or MoveFirst) methods to work. Any other type of recordset will make these methods available.

horizontal rule

OPENING THE LOCAL SQL SERVER

Often move code back and forth between my development and production machines, and I've always had to change the server's name in the process. However, I've recently discovered that, by changing the Data Source a bit, I can always point to the SQL Server installation on the current machine. Here's an example:

Set cnDB = Server.CreateObject("ADODB.Connection")
cnDB.ConnectionString = "Provider=SQLOLEDB;" _
& "Data Source=(local);" _
& "Initial Catalog=Northwind;" _
& "User ID=sa;" _
& "Password=;"
cnDB.Open

In this case, the Data Source value (local) points to the local installation. This is similar to how the SQL Server Query Analyzer works--it always gives you the choice of (local) to point to the local machine.

horizontal rule

OPTIONAL FEATURE NOT IMPLEMENTED

A user recently sent me this error message (without a lot of extra explanation, mind you) and was trying to figure out why his input/output parameters weren't working with his stored procedures:

Microsoft OLE DB Provider for ODBC Drivers (0x80040E21)
[Microsoft][ODBC SQL Server Driver]Optional feature not implemented

Without knowing the rest of the story, I see a couple of problems:

The user is using ODBC to connect to his SQL Server database. This is not required under ADO and can be bypassed with a DSN-less connection (covered numerous times at ASPTechniques.com).
The driver he is using for ODBC does not support input/output parameters (or something else related to the transaction).

The solution I would try first, if possible, is to connect directly to SQL Server via OLE DB instead of ODBC. That would probably clear up the problem immediately, since the OLE DB provider supports a much richer set of functions for SQL Server.

horizontal rule

PERFORMANCE IMPROVEMENTS IN IIS 5.0

"Microsoft did some tests on ASPs vs COM DLLs in IIS5 and IIS4 (there's an article on MSDN with the details). Basically, it seems that the ASP engine in IIS5 has been improved so much that code in ASPs actually runs faster than the corresponding code in DLLs. DLLs have other advantages, such as security and so on, but the issue of speed is not so clear anymore. People using IIS5 will find better performance using plain ASPs.

"Obviously, if performance is really an issue, then DLLs written in C++ would be much faster still. Then there's ISAPI which is even faster, but that's serious stuff and not nearly as easy to write as ASP is."

horizontal rule

PROBLEMS WITH CDONTS.NEWMAIL

A user was recently having problems with the CDONTS.NewMail component, which is available to NT 4.0 and Windows 2000 developers for sending email. The user was attempting to use the AttachFile method to include an attachment. The problem is that when a file is attached, you have to specify the full, physical pathname for the file. The user was attempting to use a virtual pathname.

The solution was to use Server.MapPath to change a virtual path into a physical path. For instance, if you had a pics directory in your root directory, you could find its physical path with this:

Response.Write Server.MapPath("/pics")

The server, depending on where the directory was located, might return this:

D:\Web\mysite.com\www\pics

What you get back is certainly not guaranteed because it's based on the server's configuration.

horizontal rule

RECORDCOUNT = -1

A user recently asked me why he was getting RecordCount values equal to -1. The reason is that he had created a ForwardOnly recordset. ForwardOnly recordsets don't contain the navigation information that includes the number of records in the recordset. When the user opened a static, dynamic, or keyset recordset, the RecordCount property was correct.

horizontal rule

RETRIEVING XML DATA INTO ASP

In a recent article at ASPToday.com, James Stansfield shows how to retrieve XML-formatted data into your ASP pages. The article describes how an XML file of headlines from a particular Web site can be used within an ASP file.

Using XMLHTTP to Gather and Display News Headlines from the Web

horizontal rule

SENDING DATA TO EXCEL

When you retrieve data using an ASP page, you typically generate HTML output. However, you have the option to generate data into any application, including Excel. Instead of printing HTML, you can generate plain text output using tabs to separate each field. To do this, you have to change the ContentType property so that the data is passed to Excel automatically (using Internet Explorer). Here's an example of how to do this:

Dim dcnDB ' As ADODB.Connection
Dim rsData ' As ADODB.Recordset
Set dcnDB = Server.CreateObject("ADODB.Connection")
dcnDB.ConnectionString = "your connection string"
dcnDB.Open

Set rsData = _
dcnDB.Execute("SELECT * FROM Products ORDER BY ProductName")

Response.ContentType = "application/vnd.ms-excel"
Do Until rsData.EOF
Response.Write rsData("ProductName") & vbTab
Response.Write rsData("UnitPrice") & vbTab
Response.Write rsData("QuantityPerUnit") & vbCrLf
rsData.MoveNext
Loop
rsData.Close
dcnDB.Close

This code will feed the data into Excel, which will interpret the tabs as column breaks. Each carriage return will create a new row. This works well in Internet Explorer, but if you're using Netscape, its success hinges on how you've configured your plug-ins. Generally, it should work fine, but you may have to add the content type entry given above and have it point to your Microsoft Excel installation.

horizontal rule

SENDING DATA TO MICROSOFT WORD

If you want to send your Web page content to a Microsoft Word file, you can use a different content type value. Here's the ContentType change you should use:

Response.ContentType = "application/msword"

This will cause your Web page's output to be read by Microsoft Word. You may get a dialog box asking you to open or save the ASP page. Even though the extension is .asp on the file you're prompted to save, it will open correctly in Word.

horizontal rule

SENDING EMAIL WITHOUT A COMPONENT

A user asked recently if there was any way to send email without using a component to do so. Unfortunately, the answer to this is no. The problem is, you would have to make your own socket connection to the other server and talk the SMTP protocol. However, ASP doesn't include the ability to call the network connection APIs to do this. You could use a socket component to create a socket to the other server and then send the email that way, but if you're using a component to do that, you may as well just use the email component that's provided.

horizontal rule

SERVER.CREATEOBJECT FAILED

A user wrote in with a Server.CreateObject Failed error and asked me to help debug it. Unfortunately, that isn't much to go on. However, there are a few things you can immediately check in a situation like this:

First, make sure that the object you're attempting to create is properly installed and registered (using RegSvr32.exe) on the server. Next, make sure you can create the object by trying to create it in a separate file apart from the rest of your code. If this is successful, it should tell you that the problem is elsewhere. If you can't create the object, then you have to trace the code inside the object, which is a more tedious and specific problem. However, if you have a well-coded object, you will probably find that registering and installing the component properly will take care of most of these problems.

horizontal rule

SERVER-SIDE INCLUDES FOR REMOTE FILES

We've published a number of tips about server-side includes, which allow you to bring one file (or files) from the server into another file. A user asked recently if it was possible to include a file from another server using a server-side include directive. Currently, this is not available. However, ASP 3.0 (on Windows 2000) introduced Server.Execute, which lets you execute either a local or remote file and have the content put into the current page--which is about as close as you're going to get.

horizontal rule

SHOWING VALUES IN FORM FIELDS

In a previous tip, we talked about how to show a value within a form field, such as when you're updating a record. The tip included this code:

<input type=text name=txtInput value="<% = strValue %>">

This code surrounds the value of your variable (strValue) with double quote characters so that the value shows up properly. An additional check suggested by one of my readers is to call the Server.HTMLEncode function to "sanitize" any potentially harmful HTML within the string. The new version would be

<input type=text name=txtInput value="<% =
Server.HTMLEncode(strValue) %>">

This will switch all "less-than" characters to the less harmful version using the &lt; code.

horizontal rule

SINGLE QUOTES AND SQL

In previous tips, you've learned that single quotes can wreak havoc for your SQL statements. Changing the single quotes into two single quotes normally will take care of the problem. Another way to eliminate the problem is to use parameters with a Command object. If you're creating parameters for your stored procedure, there's no need to change the data before submitting it to the server.

horizontal rule

STANDALONE ASP DEVELOPMENT

One problem with ASP is that you have to have a server of some sort to use your pages. If you don't have a machine with a Web server, you can't test your ASP code. ASP code, to run properly, must run through an IIS-based Web server, which includes Personal Web Server. Personally, my laptop is a Windows 2000 Server, which lets me do everything I need to without having to be connected to a server somewhere on the Internet.

If you can't do any of these things, you might want to look into a hosting service that will allow you to do ASP coding on their servers. The prices for this service have come down considerably of late. Some providers I've used include:

Virtual Servers

Data Return

Interland

horizontal rule

STRUCTURING YOUR INCLUDE FILES

One of the most longstanding features included in ASP is the ability to include one file within another. The way many people use include files, however, hampers their ability to write modular code. For instance, I've seen an include file look like this:

Dim cnDB
Set cnDB = Server.CreateObject("ADODB.Connection")
cnDB.ConnectionString = "Provider=SQLOLEDB;" _
& "Data Source=(local);" _
& "Initial Catalog=Northwind;" _
& "User ID=sa;" _
& "Password=;"
cnDB.Open

This is a typical database connection sequence. However, it's set up to be put in a file by itself and then included where the user wants to make a database connection, like this:

<%
Option Explicit

Dim rsData ' As ADODB.Recordset

%>
<!--#include file="opendb.inc" -->
<%
Set rsData = cnDB.Execute("SELECT * FROM Customers")

Response.Write "<ul>"
Do Until rsData.EOF
Response.Write "<li>" & rsData("CompanyName") & "</li>"
rsData.MoveNext
Loop
Response.Write "</ul>"
rsData.Close
cnDB.Close

%>

In this example, the code calling the include file has to know that cnDB is the name of the connection and that the cnDB variable is then declared within the calling code.

Personally, I prefer to build include files as a series of functions and subroutines. I then include the file at the top of each of my other files, since the first line of my include file is ALWAYS Option Explicit. The calling code can then simply invoke a function or a subroutine, and I don't have to worry about keeping variables straight between files. In contrast, the technique described at the beginning of this tip is more difficult to track as the number of include files increases.

horizontal rule

SYSTEM LIBRARY LOCATIONS

In previous tips, I told you how to use the METADATA tag to refer to DLLs on the Web server. These DLLs give you access to constants, such as those used in ADO or the FileSystemObject. A user asked how to find these DLL names and locations. The simple answer is that the ADO library is located in the same directory, no matter how the machine is configured. During the installation procedure for the IIS server, the DLLs for ADO are placed in a special directory under Program Files. Unless the server owner has specifically moved them and changed all the references to the library in the system registry, the DLL will be located there.

As far as other DLLs, including those typically found in \WinNT, those locations can vary if the system owner has picked a different NT directory. The best solution is to simply find out the directory name for the DLL and refer to that in your ASP page.

horizontal rule

TIMER FUNCTION FIXES

In a previous tip, I showed you how to time the execution of a function within ASP. However, that code didn't take into account the fact that a script might execute over the change from one day to the next. A reader sent in this corrected version of the code:

Dim StartTime, EndTime
StartTime = Timer

' whatever code you want to time

EndTime = Timer
If StartTime > EndTime Then
EndTime = EndTime + 86400
End If
TimeIt = EndTime - StartTime

horizontal rule

TIMING OUT A LOGIN

A common feature on financial sites (among others) is to automatically log out a user after a certain period of time. The easiest way to do this is with the Session object. The Session object can be configured to expire after a certain number of minutes. Start by putting a value into the Session object, like so:

Session("LoggedIn") = "Yes"

After the session has timed out, the value of the Session variable will be empty (compare against two double quotes). This indicates that the session has timed out, and you can redirect the user to a login page, or any other appropriate page.

horizontal rule

USING THE ADO FIELD ATTRIBUTES PROPERTY

Every time you create a recordset, ADO sends you back lots of information about the data you selected. The complete list of attributes is available in your MSDN Library or online at

http://msdn.microsoft.com

However, one of the easiest ones you can use will tell you whether the field is nullable.

Here's an example that determines whether each field in the Northwind Traders Orders table is nullable. (This code assumes that you've opened a database connection to the Northwind Traders database.)

Set rsData = cnDB.Execute("SELECT * FROM Orders")
For i = 0 To rsData.Fields.Count - 1
Response.Write rsData.Fields(i).Name & " is "
If (rsData.Fields(i).Attributes And adFldIsNullable) Then
Response.Write "nullable."
Else
Response.Write "required."
End If
Response.Write "<br>" & vbCrLf
Next 'i

For the Orders table, the response to this code is

OrderID is required.
CustomerID is nullable.
EmployeeID is nullable.
OrderDate is nullable.
RequiredDate is nullable.
ShippedDate is nullable.
ShipVia is nullable.
Freight is nullable.
ShipName is nullable.
ShipAddress is nullable.
ShipCity is nullable.
ShipRegion is nullable.
ShipPostalCode is nullable.
ShipCountry is nullable.

This provides an easy way to perform validation or to generate client-side validation code. In future tips, we'll discuss additional attributes available to you.

horizontal rule

USING THE RECORDSET SORT PROPERTY

Once you've created an ADO recordset, you have the option of re-sorting the data by any of the fields available to you in the recordset. For this to work, the CursorLocation property has to be set to adUseClient. This eliminates the ability to use this feature with ForwardOnly recordsets, as well.

To sort a recordset by a field, just set the Sort property, as shown here:

rsData.Sort = "CompanyName"

The sorting happens immediately. If you want to sort in reverse (descending) order, you can add the keyword DESC following the field name, as shown here:

rsData.Sort = "CompanyName DESC"

You can also list multiple columns for sorting, like so:

rsData.Sort = "CompanyName, ContactTitle DESC"

horizontal rule

VBSCRIPT IN MSGBOX TITLE

A user recently noted that when he created a MsgBox in client-side VBScript, the title of the message box was VBSCRIPT. You can change this by adding a third argument to your MsgBox call, as shown here:

MsgBox "This is the message", vbOK, "This is the title."

horizontal rule

WHAT'S WRONG WITH RENDER BLOCKS

Remember all those tips I've given you about not just dropping blocks of HTML into your ASP pages? I'm not alone in giving this advice... In fact, on the CoverYourASP site, you can read an article that covers some additional techniques you can use to generate HTML without putting blocks of HTML in your ASP:

What's Wrong with Render Blocks

horizontal rule

WHERE TO PUT COOKIE CODE

Cookies are always a popular tip topic, and recently a user asked me where code to manipulate cookies should go. For instance, let's use the following code:

Response.Cookies("LastVisit") = Time & " " & Date
Response.Cookies("LastVisit").Expires = DateAdd("d", Date, 30)

All cookies have to be written to the page header before any other HTML content is sent to the browser. If page buffering is turned on for the Web site or the page, you can configure your cookies at any time. If cookies are turned off for the site or the page, you have to create/modify/delete cookies before you send any HTML.

The short answer is that this code, in its current form, is strictly server-side code. You can manipulate cookies using JavaScript in client-side code, as well, but that's a topic for another day.

horizontal rule

WRITECOMMENT FUNCTION

In a previous tip, I talked about how you can make debugging easier by generating HTML comments into the output generated by your ASP files. Here's the function that does it:

Sub WriteComment(strText)
Response.Write "<!-- " & strText & " -->" & vbCrLf
End Sub

Another benefit of using this function is that you can very easily turn debugging messages on and off by creating a constant at the top of your page, called DEBUG, as shown here:

Const DEBUG = True

You then modify the WriteComment function to work as follows:

Sub WriteComment(strText) If Not DEBUG Then Exit Sub

Response.Write "<!-- " & strText & " -->" & vbCrLf
End Sub

The comments will print in the HTML only if the debugging constant is set to True at the top of the page.

horizontal rule

A QUICK BACK LINK

On a search results page I recently did for the ASP Techniques Web site, I wanted to have a quick way for the user to back up to the search results page and to the search criteria page without rerunning the query. I used the following JavaScript code to do it:

<a href="javascript:history.go(-1)">Back to Search Results</a>

This uses the browser's history object to back up one step, which has the same effect as clicking the browser's Back button. The reason I used this instead of rerunning the query is for performance reasons. There's no sense rerunning a long query when all you need to do is back up in the history and make use of the browser's cache. This won't always be the appropriate solution, but it works nicely in this case.

horizontal rule

ADDING RECORDS TO TABLES WITH AUTOINCREMENT FIELDS

Ever have a table that has an autoincrement (AutoNumber in Access, for instance) field and you're not sure how to add a record to the field? If you attempt to put a value into the field, you'll get an error. The solution? Don't put a value into it. If you're using an ADO Recordset inserting into a table, you can store the rest of the fields as you normally do and then do an Update. The database will add your autoincremented number, and you'll be able to get the value immediately after you call the Update method on the ADO Recordset.

The same thing goes for SQL statements. Don't list the automatically supplied field in the list of fields you supply in the INSERT statement, and the database will automatically plug in the value.

horizontal rule

ASP CERTIFICATION TESTS

A question that comes up frequently is whether there are certification tests for Active Server Pages. Microsoft has a test on Visual InterDev, but it focuses primarily on the design-time controls and other GUI features. If you want a test specifically on the ASP language, you can take one at Brainbench. These tests, which are currently free, are fairly comprehensive, given online, and allow you to compare your scores with other developers. If you pass the test, you'll even receive a snazzy certificate.

Brainbench

horizontal rule

ASP CODE NOT EXECUTING

In a previous tip, I talked about how, if you are loading an ASP page locally into your browser, the ASP code won't run. Another reason ASP might not execute: The file is not suffixed with .asp. You can use IIS's console to configure additional file extensions to use for ASP applications; however, it's a common mistake to put ASP into HTML files and forget to change the file extension.

horizontal rule

ASP COMMENT BLOCKS

As with any programming language, you're strongly urged to comment your ASP code. Case in point: I wrote some complex logic for a calendar I built last year--and when I needed to revisit the code (which I hadn't commented heavily) and make some modifications, I wasted a fair amount of time figuring out why I did things the way I did. Had I taken a few moments to properly comment this code, I could have saved myself a lot of time and effort down the road.

Now, one thing I always do is add a comment block for each subroutine in my ASP files. Here's a sample one:


''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
'
' Sub IncludeFile
'
' This routine reads a file and dumps it to the screen. It
' allows for variable names to be included instead of the
' hardcoded names required by the SSI directives.
'
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
This provides a visual break in long code files and provides some useful information about the routine. You can add whatever information you need here. Some people like listing the input and output parameters, assumptions, and so forth.

horizontal rule

ASP MAGIC EIGHT BALL

If you have questions about how to do random events, take a look at the ASP Eightball article at CodeAve.com. This article shows how to create the classic magic eight ball, which randomizes through 20 different sayings. The key to making it work is using the Randomize statement, which causes the Rnd function to work on a completely random sequence of numbers.

ASP Eight Ball

horizontal rule

ASP+ NEWSGROUPS

If you have Outlook Express or any other NNTP-compliant newsreader, you can connect to Microsoft's .NET support newsgroups. Here's all you need to know:

Use msnews.microsoft.com as the news server name.
The .NET groups are all prefixed with microsoft.public.dotnet.

There is already quite a bit of information from people using the software. In addition, you'll often find Microsoft developers answering questions in the newsgroups. Unlike Microsoft's other support offerings, this one is free and is currently the only source of support for NGWS and Visual Studio .NET.

horizontal rule

ASPERROR OBJECT

One of the few minor improvements in ASP 3.0 was the introduction of the new ASPError object. This object is available only if you're running ASP 3.0, which comes with Windows 2000. The built-in error messages for ASP always had access to the line number and additional information about where the error occurred, but that information was never exposed. The new ASPError object corrects this problem by adding these properties:

ASPCode: IIS error code number
Number: error number
Source: source code text of the line that generated the error
Category: more description about the source of the error
File: ASP file that generated the error
Line: Line number where error occurred
Column: Character position where error occurred
Description: Short description of error
ASPDescription: Long description of error, if available

If you have Windows 2000/ASP 3.0 available to you, this is a nice addition to the weak Err object that was previously available.

horizontal rule

BUILDING ARRAYS DYNAMICALLY

In some of my applications, I want to loop through a list of text items that are not stored in a database. These lists do tend to change over time, so I used the Array function to hold them, like so:

a_strFields = Array("Name", "Description", "Keyword", "ContentText", "URL")

Since I don't know how many elements there are in the array, I use the LBound and UBound functions to loop through the array when necessary, as shown here:

For x = LBound(a_strFields) To UBound(a_strFields)

This makes it so the code that appears later in the page need not be concerned about the contents, or size, of the array.

horizontal rule

CONDITIONAL SERVER-SIDE INCLUDES

A user asked recently if it was possible to do conditional includes based on the values in his ASP code. The problem is that server-side includes are evaluated before the ASP code is run. This means that by the time you have values in ASP, you can't execute an include statement. The best thing I can suggest is to have a subroutine that does different things based on the value in question. In this case, every page will simply include the routine, and it will do the correct thing, based on input.

horizontal rule

COOKIE LIMITS

In previous tips, we talked about the need to economize cookie usage. Some projects I've seen overuse cookies, using lots of values all going back and forth to the user's browser. There are two basic problems with using cookies too heavily. Problem No. 1 is that Netscape supports only 20 cookies per domain. Problem No. 2 is that Netscape limits cookies to 4k or less. Internet Explorer supports a slightly higher size of cookie, but if you are coding for multiple browser support, you have to use the lower values.

The best solution is to store minimal information--such as a user ID or user name--in a cookie and store the rest in a profile table of some sort in your database. I have used this method successfully on several applications, and it cuts down the back and forth traffic that you would otherwise get with lots of cookies.

horizontal rule

CREATEOBJECT FAILED

In previous tips, we talked about problems dealing with CreateObject and how sometimes this error is due to the fact that the DLL is not registered correctly on the machine.

This error can also be caused by incorrect permissions on the library. For a library to be available to the Web server, the library has to be available to the user ID associated with the Web server. Typically, this user ID is IUSR_machinename, but it depends on how your machine is configured.

Make sure that the libraries you are attempting to use are available to the Web server user ID with both the Read and Execute permissions in Windows NT or it won't work properly.

horizontal rule

CREATING WINDOWS SCRIPT COMPONENTS

IIS contains a relatively new feature that allows it to use Windows Script Components, which are basically blocks of script on your server that perform various functions. They are sort of a cross between a COM object and a block of ASP code. Here's an article that explains them in more detail:

Understanding Windows Script Components

horizontal rule

DETECTING A SECURE CONNECTION

Do you want the user to hit a particular page only by way of a secured HTTPS connection. As the page is loaded, you can use the SERVER_PORT variable to see whether the user is on the secured server, which has a port number of 443. If the user was on port 80, the non-secure server was being used, but a quick Response.Redirect then sends the user to the correct Web site.

A number of additional variables provide information about the security on the server, such as the number of bits in the security key, the issuer, and so on. 

horizontal rule

DISABLING SESSION COOKIES

If you have a simple Web site and aren't using any Session variables, you can disable them using this simple directive at the top of the page:

<%@ ENABLESESSIONSSTATE = False %>

This prevents the Web server from sending the ASPSESSION cookie that it automatically sends by default. This is a good thing to do if there's no need to maintain state per user.

horizontal rule

DISPLAYING A MESSAGE BOX

During debugging, it helps to be able to print values as the page is executing. I frequently do this with Response.Write statements; however, you can also do it with a client-side JavaScript that creates a message box. Here's the code you'll need to add to your ASP to pop open a message box:

' rest of ASP code goes here
%>
<SCRIPT LANGUAGE="Javascript">
alert("<% = strMessageToShow %>")
</SCRIPT>
<%
' rest of ASP code goes here

However, remember that you can't use the VBScript MsgBox function in server-side code--it won't even show the message box on the server.

horizontal rule

DON'T INSTALL WEB SERVER PATCH

Warning: Microsoft's recently released patch for the Web Server Folder Traversal may break ASP. Postings from newsgroups and email lists for IIS administrators have reports from the field indicating that applying this patch can result in a breakdown of ASP and/or FTP services.

For more information on this patch:
http://www.iisanswers.com/newsletters/bulletin_10192000.htm

Microsoft Security Bulletin:
http://www.microsoft.com/technet/security/bulletin/MS00-078.asp

horizontal rule

DYNAMIC COPYRIGHT LINE

If you have a copyright date on your Web site, it can be an indicator of how often you update your site. I visited a site the other day that had a 1999 copyright date on it. More than likely, the user is updating the site but just didn't update the copyright date--but inadvertent or not, it indicated a stale site.

To avoid this problem, I have created a "dynamic" copyright date at the bottom of my pages, using this code:

Response.Write "Copyright &copy;" & Year(Now) & " by Eric A. Smith"

This ensures that the Web site's copyright date is always current and saves me from having to modify the pages each year.

horizontal rule

DYNAMIC SERVER-SIDE INCLUDES, REVISITED

I've received a fair bit of email asking for clarification of a tip in which we discussed the fact you cannot dynamically include a file in your ASP file, so let's delve a bit deeper into this issue. For starters, note that the standard server-side include directive looks something like this:

<!--#include virtual="/includes/header.asp" -->

This type of directive is processed before any ASP code is run, which means you cannot dynamically build this statement and therefore cannot dynamically choose an ASP file to run. The ability to wrap a block of code or an include with an If/Then statement doesn't change the fact that both files are loaded into memory.

The alternate option, if you're just loading client-side HTML/JavaScript code, is to read the file using the FileSystemObject and a TextStream object and print them to the console. Here's a routine I use to do this:

Sub IncludeFile(strFilename)
If strFilename = "" Then Exit Sub

On Error Resume Next
Dim objFSO, objFile, strContents
Set objFSO = CreateObject("Scripting.FileSystemObject")
Set objFile = objFSO.OpenTextFile(Server.MapPath(strFilename), ForReading, False)
strContents = objFile.ReadAll
Response.Write strContents & vbCrLf
objFile.Close
Set objFile = Nothing
Set objFSO = Nothing
End Sub

This code assumes the Scripting Runtime is referenced using a METADATA tag (as discussed in previous tips). Note that this code simply reads a file and immediately prints it to the output window. This means that you can't have ASP code in the files read this way. I typically use this only for plain HTML files or JavaScript code when I need to dynamically specify a filename.

horizontal rule

EMBEDDING NEW LINES IN EMAIL

Whenever you're using an email component like CDONTS.NewMail, you have to add your own line breaks where necessary. Otherwise, you're relying on the user's email program to wrap the text for you--which may not work properly in all cases. The easiest way to do this is to simply concatenate the vbCrLf constant, which embeds a carriage return/line feed sequence. This will help control how the text output appears in the user's email program.

horizontal rule

FINDING INFINITE LOOPS

If you ever have a page that just seems to hang, it's possible that it contains an infinite loop. This often comes up when dealing with databases, where you might have code like this:

Set rsData = cnDB.Execute("SELECT * FROM SomeTable")
Do Until rsData.EOF
do something with the data
Loop

Assuming there are records in the recordset, this loop will never exit. Why? The loop doesn't go past the first record. The code is missing a call to MoveNext, which will select the next record.

A practice I try to follow is to immediately type the MoveNext call after I write the Do statement. In addition, I will typically put in the Loop keyword so I don't forget.

horizontal rule

FORM SUBMISSION LIMITS

On more than one occasion, I've received questions about the limit on the amount of data that can be submitted via a form. Inevitably, the answer depends on the method used to submit the data. If you're using METHOD=GET, the limit is the length of the URL, which is typically 4 kilobytes. However, a form sent via METHOD=POST can accept uploaded files, which gives you a much larger capacity for submitting data.

horizontal rule

GENERATING STATIC HTML FROM ASP

In some cases, you may want to generate static HTML pages from your ASP pages. In cases where you're not frequently updating pages, creating a static HTML page makes a lot of sense. To do this, you can use the FileSystemObject to open a text file (OpenTextFile method) and write the HTML directly to the file. The key requirement is that the directory where you're writing the file be available--and most important, writeable--to the Web server. Normally, this option is not available for security purposes. However, you could make a subdirectory of your Web server writeable and then put your file there.

horizontal rule

GETSTRING METHOD

I often have need for a bit of code that will take data from a recordset and put it into a table. I used to do this manually, but the ADO Recordset has an interesting method that will do it for me: GetString. This method accepts a column and row delimiter (as well as what to show for Null fields) and returns a string containing all the data therein. With a bit of manipulation, you can use this to build a table of your data, as shown here:

<%
Dim cnDB ' As ADODB.Connection
Dim rsData ' As ADODB.Recordset
Dim strTable ' As String
Dim strColumn
Dim strRow
strColumn = "</td>" & vbCrLf & " <td>"
strRow = "</td>" & vbCrLf & "</tr>" & vbCrLf & "<tr>" &
vbCrLf & " <td>"

Set cnDB = Server.CreateObject("ADODB.Connection")
cnDB.Open "Provider=SQLOLEDB;Data Source=(local);" _
& "Initial Catalog=Northwind;User ID=sa;Password=;"
Set rsData = cnDB.Execute("SELECT * FROM Customers " _
& "ORDER BY CompanyName")
strTable = rsData.GetString(2, , strColumn, strRow, "")
Response.Write "<table>" & vbCrLf
Response.Write "<tr>" & vbCrLf
Response.Write " <td>" _
& Left(strTable, InStrRev(strTable, "</tr>") + 4) & vbCrLf &
"</table>"

%>

The spacing in this code, by the way, is simply for clarity.

The first argument to the GetString method is always 2, or adClipString, if the ADO Library is referenced in the page. The second argument specifies how many rows to convert. (Leaving the argument blank tells the function to convert all rows.) The third argument is the value to use between column values, and the fourth argument is the value to use between rows. With a minor bit of manipulation at the end, we wrap the whole thing with a table tag and a beginning TR and TD tag, since the column delimiter doesn't show up in front of the first field. Experiment with this function and you'll come to like it. It saves a fair bit of code, even for complex table formatting.

horizontal rule

GETTING SECURITY INFORMATION

Want to give  users to view the site via an HTTPS connection only. If the user wasn't connected to a secure port, I needed to send them to that port before they could access the site. The SERVER_PORT value in the ServerVariables collection will tell your ASP file the port on which the user is connected. In my case, the default port of 80 was not secured, so I simply used Response.Redirect to send the user to the secured site, which uses port 443 (the default value).

horizontal rule

HANDLING MULTIPLE CHECK BOXES

If you have a form that includes multiple check boxes, you have two options: Name them each individually and provide each one with a value that can be read through the Request object, or name them all the same and get a comma-separated list of values through the Request object. This latter option is a nice feature if you have a large number of values. You can then use the Split routine to break up the long string into an array, through which you can then loop.

horizontal rule

HANDLING MULTISELECT HTML LISTS

If you've created a SELECT list that is able to have more than one item selected, those items will show up comma-separated in the Request.Form collection. You can use the Split function to break the string anywhere there is a comma, and then use the Trim function to remove any extra spaces at the front or back of the resulting string. The LBound and UBound functions will allow you to determine how many items are in the array that the Split function returns, and you can loop through them and do what you need to with them.

horizontal rule

HIGHLIGHTING SEARCH RESULTS

Do you want the ability to highlight the text for which a user searched, but don't want to create a second page to show content. Instead, you can modify the content.asp page--which is responsible for showing all the content in the system--to highlight keywords and phrases when those fields were provided in the query string.

Using the Replace function, I was able to search for a key phrase in my large text field and "replace" the word with a reformatted version of itself, like so:

strText = Replace(strText, Request("keywords"), _
"<b><font color=Red>" _
& Request("keywords") & "</font></b>", 1, -1, vbTextCompare)

This line of code replaces a phrase or word (stored in strText) with a formatted version of the same word. (In this case, the formatting simply colors the text as red.) This makes the keywords stand out when the user is viewing one of the pages that matched the criteria.

horizontal rule

HTTPS SERVER VARIABLE

In previous tips, I showed you how you could use the SERVER_PORT variable to determine whether a user is viewing your site on a secured port. However, an easier way to do it is to use the HTTPS variable, which returns an "on" if the page is viewed via a secured port. This takes care of cases in which you might be using a nonstandard port.

horizontal rule

ILLEGAL OPERATION ERRORS IN INTERNET EXPLORER

I occasionally receive email about illegal operation errors in Internet Explorer. These errors are related to the Internet Explorer software, typically, and are not caused by the content in your Web pages. The best solution to this type of problem is to upgrade your browser. The latest version of Internet Explorer is 5.5, and there are several patches available for Internet Explorer 4. If you have a way to download the product, that's the best way to get rid of these errors. Another option is to try rebooting the machine and hitting the page again. Unfortunately, most of the errors are difficult to reproduce, making them hard to track down.

horizontal rule

INCLUDING REMOTE FILES

The #include directive will allow you to include a file from anywhere on your server. Unfortunately, this feature does not allow you to cross server boundaries. You can't, for instance, read a file's source code from my server and bring it into your own. This isn't really a bug--it's a feature. Without it, you could see my code without me even knowing it.

horizontal rule

INPUT BOXES FOR NUMBERS

I recently received a question asking what sort of form control one should use for accepting numeric data. The writer was confused by the fact that the HTML tag uses INPUT TYPE=TEXT. For an HTML form, the only way to allow freeform entry of information is to use either a text box (TYPE=TEXT) or a text area (TYPE=TEXTAREA). When ASP reads the data, the Request object will return everything as text. Accordingly, you need to use the various numeric conversion functions, such as CInt or CDbl, to convert the text field to a numeric variable.

CORRECTION: MSDE WHITE PAPER In a previous tip, I referenced a Microsoft Data Engine white paper that was available on Microsoft's Web page. That white paper is actually available at this URL:

http://www.microsoft.com/sql/techinfo/Access2000Jet&MSDE.doc

horizontal rule

INSTALLING ASP+

If you've checked Microsoft's Web sites lately, you've probably heard about the new .NET software that should be released next year. Currently, you can download the NGWS (Next Generation Web Services) Framework and install it on Windows 2000. However, the software is really picky about what is installed on the machine. Here's a recipe I followed that seems to have produced good results:

First, build a brand-new installation of Windows 2000 Server. Make sure that you include Internet Information Server during the installation. Next, install Internet Explorer 5.5. This is required for the NGWS Framework to install.

At this point, install the NGWS Framework. If you want to use SQL Server for the database examples, you can install it next. There are samples in the Samples directory that can be configured automatically or manually; there are instructions for both methods.

As all of the documentation for the NGWS Framework states that this is preview software and should NEVER be put on a production machine. Find another machine to put it on... one that you can afford to rebuild if necessary.

Microsoft .NET

horizontal rule

LIMITING SEARCH RESULTS

If you have a query that you know will return a lot of records, you can use the SQL TOP keyword to limit the number of records that are returned. I will often do this when I want a small sample of data from a table. Here's a sample query:

SELECT TOP 10 * FROM Customers

This returns the top ten rows from the Customers table, with all their fields. Unfortunately, you are not guaranteed to get a consistent return. I'd suggest adding a sort (ORDER BY) to improve the results. For instance, if I wanted the last five records added to a table, I might do this:

SELECT TOP 5 * FROM Content ORDER BY CreationDate DESC

horizontal rule

MACROMEDIA ULTRADEV REVIEWED

Macromedia has a new tool out called UltraDev that is able to edit ASP code. This tool is a replacement for the older Drumbeat product that has since been discontinued. In his recent article at ASP 101, John Peterson does a fairly complete review of this new tool. If you're interested in a new ASP tool, check it out.

A Scripter's View of Dreamweaver UltraDev 1.0

horizontal rule

MANAGING SAVED RECORDSETS

In previous tips, I talked about the ADO Recordset's ability to save to a file and be reloaded from the file into memory. This prompted an astute reader to ask how to manage multiple recordsets and remove them when needed. The solution to the first question is simply a matter of keeping track of the filenames you use. For instance, if you're allowing users to write queries and then save their results, you might want to keep track of the recordsets you created by using another database. The database would link the users to their recordsets, and then you could name the recordsets using the database's primary key, for instance, or name them using a date, user ID, and so on. The combinations are endless.

The second question can be easily solved using the FileSystemObject, which can delete files from the server--assuming you have permissions to do so. Of course, if you have permission to write the recordset in the first place, you also likely have permission to delete that file.

horizontal rule

MICROSOFT ACCESS AND WEB SERVERS

If you're using Microsoft Access for your Web database, remember that the database has to be in a directory that is writeable by the user ID used by the Web server. Otherwise, the database won't operate properly. The directory used for the database doesn't have to be in the Web server's directories--just make sure the directory is writeable.

horizontal rule

NEW FEATURES AT ASP TECHNIQUES

If you haven't been to ASP Techniques lately, you're missing lots of new features. The best feature is an ASP/SQL Server discussion forum where you can ask questions and discuss ASP and SQL techniques. There's also a new and easier-to-use interface for viewing old tips and other content.

ASP Techniques

horizontal rule

OPTION EXPLICIT IN ASP+

One of the hard-to-find language features in ASP+ was how to force variable declaration, as Option Explicit does in ASP. Instead of adding the statement Option Explicit, ASP+ requires use of the Explicit statement in the Page directive at the top of the file, like this:

<%@ Page Language="VB" Explicit="On" %>

horizontal rule

PERSONAL WEB SERVER AND WINDOWS ME

If you're one of the people who've had problems installing Personal Web Server on Windows Me, Microsoft has a technical support document that explains how to do it. The problem arises if the registry is large when you attempt to install PWS or MTS, but you can fix the problem by downloading the updated version of the Mtssetup.dll file and reinstalling PWS or MTS. You'll find step-by-step instructions at the URL below.

http://support.microsoft.com/support/kb/articles/Q246/0/81.ASP

horizontal rule

PERSONAL WEB SERVER WORKSHOP

If you've had problems running Personal Web Server on Windows 98, you might be interested in this free workshop listed below. In the workshop, Edward Tanguay explains how to install and configure PWS within Windows 98 so that you can build your ASP files locally.

Personal Web Server Workshop

horizontal rule

PUTTING IIS AND WINDOWS 2000 ON A LAPTOP

One of the nice things about having a laptop is that, if you have the right tools, you have a self-contained development environment. I'm on the road frequently, and it's nice to have all the servers I need on my laptop. I currently use Windows 2000 Server, IIS 5.0, and SQL Server 7.0 on my machine.

There are a couple of things you need to check before deploying all this software to your machine. First, determine whether the hardware vendor supports Windows 2000 and, more specifically, the version of Windows 2000 you intend to install. If the vendor doesn't support it, you may have a hard time finding certain drivers for your machine (sound, modem, etc.). Most mainstream vendors have support for Windows 2000, and many of the drivers are included with the Windows 2000 CD itself.

The other and somewhat more important question is to make sure you have sufficient memory and hard drive resources. In my particular case, my machine had a Pentium 300 processor, but only 128 MB of memory. Once I bumped the memory up, things ran much better. I also keep quite a bit of empty space on my drive. If you follow these steps and any advice your hardware vendor can provide, you'll be able to create a production server on a portable machine to use for development and testing.

horizontal rule

REGISTER YOUR DLLS

If you're building applications that use either custom-built or third-party DLLs, remember that you have to register them on the Web server to use them. If you don't, you're likely to see the common error message

Server.CreateObject failed

without any further details. If you get one of these messages, make sure that all your DLLs are registered using REGSVR32.EXE.

I also recommend you associate your DLL files with the RegSvr32 utility. Using RegSvr32, you simply double-click a DLL file to register it (once you've created the association, that is).

horizontal rule

REGISTERING A DOMAIN

Contrary to what Network Solutions wants you to think, it isn't the only game in town when it comes to registering a domain. If you're building a site (ASP enabled or not), the best way to promote it is to get a domain name that doesn't change, even if you change ISPs. The Internet Corporation on Assigned Names and Numbers (ICANN) is in charge of accrediting domain registrars around the world. To find alternative providers for domain-registration services, you can visit ICANN's list of accredited registrars at this URL:

http://www.icann.org/registrars/accredited-list.html

I've found registrars on the list whose registration fees per domain are less than $10/year. It sure beats the $35 that other providers are charging.

horizontal rule

REMOTE SERVER-SIDE INCLUDES

We've published several tips on server-side includes, but a reader recently asked whether you could include a file from another server. Unfortunately, the answer is no. For example, you CANNOT do the following:

<!-- #include virtual="http://wolfsburgii.com/common.asp" -->

This is primarily for security purposes, because it keeps others from reading your code. You can, however, include files from your Web site, using either the file or virtual attributes in the #include directive.

horizontal rule

REMOVING YOUR SITE'S COOKIES

In cases where you're using permanent cookies, you should always include a feature to sign out of your Web site. At that point, you should remove any cookies you've created. Here's a quick method to remove all your site's cookies from a user's machine browser:

Dim varItem
For Each varItem in Request.Cookies
Response.Cookies(varItem) = ""
Next ' varItem

I generally do something like this when the user hits "Sign Out." It also makes it easier to test security features that require the user to be logged in.

horizontal rule

RUNNING ASP SCRIPTS

This question comes up frequently: Where can you run your ASP scripts? The answer is short and to the point: on a server that supports ASP.

You can't simply open an ASP file and have it run properly--it has to run through a Web server that can run the ASP engine. The primary choices for this are Personal Web Server running on Windows 95 and 98, or Internet Information Server running on NT/2000 platforms.

If you can't get Personal Web Server running, you might want to look into a site like Brinkster.com, which will host (and run) your ASP scripts for free. This is a good way to test your scripts without having to mess with running a server yourself. Because of some known bugs with Personal Web Server, I prefer to have an IIS server on hand as I build my scripts.

Brinkster

horizontal rule

SERVER.EXECUTE WORKS LOCALLY

Similar to server-side include directives, the Server.Execute routine can execute ASP files located on the current Web server only. It is not allowed to run files located on remote servers, or even files located on the same server in a different virtual directory.

horizontal rule

SERVER.TRANSFER VS. RESPONSE.REDIRECT

A user sent me this informative excerpt from Wrox's "ASP 3.0 Programmer's Reference," regarding the differences between Server.Transfer and Response.Redirect:

"The current page's context is also passed to the target page or resource. This includes the values of all the variables in all the intrinsic ASP objects, such as the collections of the Request, Response, and Session objects, and all their properties. The Application object context is also transferred, even if the page is within a different virtual application. The current transaction context is also passed to the new page, allowing it to take part seamlessly in any current transaction.

"Meanwhile, the browser's address bar still shows the original URL, and the Back, Forward, and Refresh buttons work normally. When we use client-side redirection, especially with an HTML meta tag, this usually isn't the case.

"However, the values of any script variables or object references that were created or set within the first page are not available within the new page.

"One other major difference is that because Server.Transfer doesn't require the client to request another page, it can be faster in some cases, depending on what you're doing."

horizontal rule

SIMPLE EMAIL VALIDATION

I'm often asked how, when accepting input data, does one validate an email address. There are a couple of steps in the validation. First, you have to verify that the format of the email address is correct. This is strictly a text checking issue. For starters, email addresses cannot have spaces in them. The second check is to ensure that at least one period character exists in the string. This check may need to be skipped if your email addresses are in the form of address@server, instead of address@server.com. The final check is to make sure that an at symbol (@) is in the address.

The second type of check involves actually attempting delivery of the email by checking the DNS records involved in sending email. A number of components are available that will do this for you and help eliminate dummy email addresses that people might enter. For a list of these components, check the ASP 101 page listed below.

ASP 101 Components

horizontal rule

SITEEXPERTS.COM

I recently discovered SiteExperts.com, which has lots of resources for all types of Web development, including ASP, CSS, JavaScript, and more. Here, you'll find easy access to a wide range of news, articles, tools, user groups, and much more--so much more, in fact, that you'd better set aside a few minutes to explore all the material when you first visit.

SiteExperts

horizontal rule

SPECIFYING NETWORK LIBRARY FOR SQL SERVER

The typical connection string I use for SQL Server looks something like this:

cnDB.Open "Provider=SQLOLEDB;" _
& "Data Source=(local);" _
& "Initial Catalog=Intranet;" _
& "User ID=sa;" _
& "Password=sa!;"

In some cases where I need to point to another server, I also need to specify the network library. Here's how:

cnDB.Open "Provider=SQLOLEDB;" _
& "Data Source=(local);" _
& "Initial Catalog=Intranet;" _
& "Network Library=DBMSSOCN;" _
& "User ID=sa;" _
& "Password=sa!;"

This specifies that the socket library is to be used for this connection. It's redundant for the same server, but if you need to point from one server to another, it can come in handy. The network libraries that are available are listed in the SQL Client Configuration Utility or the Server Configuration Utility.

horizontal rule

STORING PICTURES IN A DATABASE

While some databases support it and others are even designed especially for it, I would strongly avoid storing pictures in databases. Your databases will bloat and require a significantly larger amount of space to do backups. Instead, I suggest storing in the database a filename reference for use when you are showing the record. Instead of having to get the file from the database, you just put up a URL and the picture will show up without a lot of extra work.

horizontal rule

TEXT BOX DATA TRUNCATED

A user asked me recently why, when he put the words "New York" into the VALUE parameter of a text box, they didn't show up. The simple answer: He forgot his double quote characters. In previous tips, we talked about how HTML deals with double quote characters. If you have a parameter without spaces, HTML will handle the value without double quotes, as shown here:

<font color=#FF0000>

However, if the value with which you're working contains a space (such as the one between New and York), the space marks the end of the value, as far as HTML is concerned. In that case, you have to wrap the value in double quote characters.

In addition, XML requires that all HTML tags have all their parameters wrapped in double quote characters, so it's probably a good habit to get into anyway.

horizontal rule

TRACKING IP ADDRESSES

One of the server variables that you have available to you through the Request object is the IP address, stored in the REMOTE_ADDR variable. However, this won't always be a unique value. If you have visitors hitting your site through a firewall or proxy server, you'll see the IP address of the proxy server only. This also means that multiple users from the same site will have the same numeric address. This makes it a bit more difficult to use IP address for validation, so I typically will ignore this value and use other values to validate a user's identity.

horizontal rule

USING PARAMETERIZED STORED PROCEDURES

If you're calling a stored procedure (or query, for the Access folks), you don't always have to create a Command object to do it. Instead, you can pass the parameters as part of the command you're executing. Here's an example, which calls the fictional GetRecord stored procedure of a particular database:

Dim dcnDB ' As ADODB.Connection
Dim rsData ' As ADODB.Recordset
Set dcnDB = Server.CreateObject("ADODB.Connection")
dcnDB.Open "some connection string"
Set rsData = dcnDB.Execute("GetRecord 123")

This code calls the GetRecord stored procedure and passes it the argument '123'. You can also use a variable concatenated to your Execute line, as shown here:

Set rsData = dcnDB.Execute("GetRecord " & lngRecordID)

Any text arguments should be surrounded by single quote characters, as shown here:

Set rsData = dcnDB.Execute("GetRecord 'Joe Smith'")

horizontal rule

USING SESSION VARIABLES

One of the features provided by ASP that I almost never use is the Session object. While it looks like it will solve all your problems in sharing data between pages, it has a number of downsides to it. Listed below is an article at the 4GuysFromRolla site, where you'll see some additional problems with Session variables:

Are Session Variables Really Evil?

horizontal rule

VALIDATING ADDRESSES

A reader who works at United Parcel Service sent me a link for their address-validation tools. These tools are similar to those used by the US Postal Service to ensure that an address is correct. You can learn more about these tools at this URL:

UPS Address Validation

horizontal rule

VALIDATING EMAIL ADDRESSES, REVISITED

In a previous tip, I told you that an easy way to validate email addresses is to make sure that at least one period and an at symbol (@) exist in the email address. However, here is another  suggested the following change:

"You want to verify that at least one period exists *after* the position of the @ symbol, as several companies and ISPs allow periods in the username of email addresses. Checking for the existence of only one period without verifying its position would let something like John.Doe@server slip by, potentially missing part of the hostname."

horizontal rule

VISUAL SOURCESAFE AND ASP

Contrary to popular belief, ASP files are real code and need to be treated as any other code file. This means that when you've finished with a build of your code, the code should be put in a source code control utility like Visual SourceSafe. You can use VSS by itself, even if you're not using Visual InterDev in its native project mode (which does support VSS, by the way). I typically use text editors such as TextPad and HomeSite to write my code, but I can check the files in and out using VSS' console. This protects me from myself--if I delete a file accidentally, I always have a way to go back and retrieve a fresh copy.

horizontal rule

DETERMINING AND CHANGING THE DEFAULT DATABASE

In ADO, you can make a connection to a database like SQL Server without specifying the database in the connection string. The DefaultDatabase property will return and set the database you want to read. This lets you maintain a connection object and switch to different databases within the same Connection object. Here's an example:

cnDB.Open "Provider=SQLOLEDB;Data Source=(local);User ID=sa;Password=;"
Response.Write cnDB.DefaultDatabase
cnDB.DefaultDatabase = "Northwind"

When I print out the default database, it displays "master", which is the default for the system administrator. Once I change the DefaultDatabase property to Northwind (for example), I'm then able to access all the parts of that database.

horizontal rule

DETERMINING IF A FIELD CAN BE NULL

When you're writing validation code for your ASP files, it's often helpful to know what the database will allow you to do with a particular field. Fortunately, the database will tell you whether it will accept a null value in a field: All you have to do is to look at the Attributes property of the field and do a little bit of binary math. Here's an example that will return a True/False if the field can be null:

Response.Write CBool(rsData("Description").Attributes And adFldIsNullable)

The adFldIsNullable is equal to 0x20 (decimal 32) if you're not using the METADATA tag to reference the library. This will check the Description field and return a True or False if this field can be null. You can use this code in your validation routine to automatically check fields before attempting to save data to the recordset. This code will work with any type of recordset, including the efficient forward-only recordset type.

horizontal rule

GETTING A LIST OF TABLES

One of ADO's handy features is its ability to read the database schema. Using the OpenSchema method of the Connection object, you can request any information about a database, from views to users to tables. Here's an example that returns all the tables in the system:

cnDB.Open "ConnectionString"
Set rsData = cnDB.OpenSchema(adSchemaTables)

adSchemaTables is equal to 20, if you're not using the METADATA tag. The fields in the recordset are defined as follows:

TABLE_CATALOG - Database name
TABLE_SCHEMA - Owner name, like dbo
TABLE_NAME - Name of table
TABLE_TYPE - "ALIAS", "TABLE", "SYNONYM", "SYSTEM TABLE", "VIEW", "GLOBAL TEMPORARY", "LOCAL
TEMPORARY", "SYSTEM VIEW"
TABLE_GUID - Not used in SQL Server
DESCRIPTION - Not used in SQL Server
TABLE_PROPID - Not used in SQL Server
DATE_CREATED
DATE_MODIFIED

This will bring back every table in the system, including the normally hidden system tables. You can restrict the tables that will be returned by using the Criteria argument to the OpenSchema method, as shown here:

Set rsData = cnDB.OpenSchema(adSchemaTables, _
Array(Empty, Empty, Empty, "TABLE"))

This method requires an array of the criteria used to restrict what is returned. I'll cover more of the options in later tips, but if you're interested, you can look up the OpenSchema method at the MSDN library:

http://msdn.microsoft.com/library

horizontal rule

GREEKING TEXT

When you're designing a Web page, it's often helpful to have realistically sized text to place on the page to test how the page will look. You could just randomly type characters, but a better way is to use "greeked" text, which is text that is approximately the correct size for normal paragraphs. Here's some greeked text you can use on your pages:

Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo consequat. Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit augue duis dolore te feugait nulla facilisi.

As you can see, this text contains a reasonable number of words of varying length, so you can simply duplicate this paragraph to fill up the text areas on your page. Many graphical programs have an option that will insert greeked text for you, but I keep this text on my PC (in a text file) for when I need it.

horizontal rule

USING SERVER.EXECUTE

"I needed a method of executing ASP files that were under a different virtual directory. To accomplish this, I used the file structure's directory name instead of the virtual directory name. The ASP is executed in the current application's context when this is utilized."

horizontal rule

ASP PAGES CAN'T CONTROL GRAPHICAL APPLICATIONS

A user wanted to know if he could control an application like Word by sending Windows messages from an ASP application. The short answer to this is no. The only way you can send Windows messages from one application to another is to have a visual interface and a message queue, which ASP applications inherently don't have.

As an experiment, I came up with a way to work around this problem. The Winamp application has available to it a broadcast server that can automatically broadcast your music over a standard network connection. However, the playlist is controlled from the Winamp GUI, which you can't touch from an ASP page. My solution was to create a GUI application (called the Winamp Monitor) that watches for a particular file to be dropped into a directory on the server. My ASP page writes that file, which contains commands to be performed, and the monitor program sends the appropriate messages to the Winamp application. It's a bit convoluted, but I now have a Web page that can control a GUI application on the server.

For more information on Winamp, visit the site listed below. The broadcast software is called Shoutcast and is available at the same site.

Winamp

horizontal rule

DELETING DEPENDENT RECORDS

A user recently asked me how to delete records that are involved in relationships. For instance, a customer has orders, and each order has line items. In this case, you have to work from the bottom up if you want to permanently remove this information. You have to delete the line items from each of the customer's orders, then delete all the orders for the customer, then delete the customer.

Before you do anything as drastic as this, I recommend you be cautious about deleting anything in a database, unless you're absolutely sure that the data you're deleting is not used elsewhere and does not affect anything else. As an alternative, you might to consider an "inactive" or "deleted" state for a record, instead of physically deleting it. Deleting data can cause serious side effects, not to mention the complete loss of an audit trail for the customer and/or sales activity.

horizontal rule

SCRIPT TIMEOUTS

A user recently asked me about this error message:

Error 'ASP 0113'
Script timed out

The reason for the error message appears to be simple, but it might not be: The basic reason for the error was that the script ran longer than the server would allow. This limit is set either at the server level or through the ScriptTimeout property of the Server object. The value is in seconds, and the default value is 30 seconds.

Now, the underlying cause behind this timeout could be one of many. For instance, it could be that an infinite loop was found in the code and the script is simply not being completed. It could also be that the code in question simply takes a long time to run. In cases like this, I suggest using some status statements (either print them out to the page or as comments) to make sure that you aren't running into an infinite loop.

horizontal rule

USING SERVER.HTMLENCODE

If you're allowing free-form entry of text into your Web pages (especially public pages, such as the forums at the ASP Techniques site), it's a good idea to use the Server.HTMLEncode routine to make any HTML tags non-functional. This eliminates the possibility of a user typing in the HTML that would otherwise cause a Java or Active X object to load into the page, and also eliminates any issues with JavaScript. The routine should change all the special characters, such as angle brackets and quotes, to their non-functional equivalents, such as &gt; and &lt;. It's a nice safety feature I always include.

horizontal rule

WRITING AN XML FILE

A number of questions recently have focused on the use of XML with ASP, which is a great way to move data from one program to another. There is some confusion, however, on how to create an XML file from ASP. Remember that XML files are just plain text files, which means you can write them using the FileSystemObject. It's not necessary to build the document using the XML document objects; however, you can if you wish.

Here's an example that creates on the server an XML file that another server application will read:

Dim objFSO
Dim objStream
Set objFSO = Server.CreateObject("Scripting.FileSystemObject")
Set objStream = objFSO.OpenTextFile("C:\Commands.XML", ForWriting, True)
objStream.WriteLine "<scm>"
objStream.WriteLine " <commands>"
objStream.WriteLine " <command>stop</command>"
objStream.WriteLine " </commands>"
objStream.WriteLine "</scm>"
objStream.Close

This produces a well-formed XML document without a lot of hassle. Once this is accomplished, another application can read the XML from the predetermined location and process the commands.

horizontal rule

CACHING OBJECT DATA

If you're using data from a database or data from one of the built-in objects (Request object, for instance) for lookups, keep it in local variables or an array instead of continually checking the recordset. This will make your application run faster and reduce database accesses while processing your page's information. Retrieving data from an object is more "expensive" (in terms of system resources) than retrieving data from a local variable declared in a subroutine.

horizontal rule

LIMIT GLOBAL VARIABLES

Variables declared outside subroutines/functions take a bit more resources than those declared within subroutines/functions. The server has to keep more overhead for these variables than for locals, so limit your use of global variables. For busy sites, this can squeak a bit more performance out of your server. If you're not on a busy site, you won't see much of a difference, but it's a good habit to develop.

horizontal rule

READING USER'S EMAIL ADDRESS

A user asked recently if there was a good way to automatically read a user's email address. The short answer is no. Since the email address is stored in the user's machine registry (or elsewhere on other platforms), the browser doesn't have access to it without using an ActiveX control installed on that machine. For those applications where you need an email address (such as discussion forums or a "mail this page" applet), you'll have to prompt the user for the address. Once you've requested the address, however, you can put it in a permanent cookie for later use.

horizontal rule

TESTING ASP APPLICATIONS

One of the problems with testing ASP applications is that you have to replicate the server directory structure to perform valid tests. However, if you're working on the same server that will run your finished code, you can't just put your files in the same places, because they'll overwrite the production copies.

You can, however, create a new Web site in IIS, using the same directory structure and configuration, but using a different access port to hit the server. For instance, instead of using the default port 80, which is the live server, use an obscure port like 7654. You can then set up your development area just like the final production section and not have to worry about people straying in. If necessary, use IIS's security features to restrict hits from domains outside your own.

horizontal rule

USE CONSTANTS FOR FILENAMES

In my code, I often reference other files from within an application, usually for links and form inputs. Since the filenames change periodically, I create constants for each filename and then use the constants exclusively throughout other pages. This makes it much easier to change or migrate the code, since no page directly refers to another. These constants are placed in an include file read in each of the ASP files on the site, so they are consistently used.

horizontal rule

MULTI-LINE COMMENTS

A reader recently asked if there is an ASP tag that can mark more than one line as a comment. Unfortunately, there is no such tag. In VBScript, the most common way to mark multiple lines as comments is to start each one with either a single quote or the REM keyword.

However, if you want the comment to show up in the output HTML (but not in the browser), you can use an HTML comment tag--which does accommodate multiple lines of text. Some older browsers may not properly interpret the multi-line HTML comment, but that problem is restricted to browsers prior to version 2.0.

horizontal rule

OMIT EMPTY GLOBAL.ASA FILE

It isn't necessary to always provide a global.asa file and all four event handlers. If you're not using any of the Application or Session events, for example, there's no need to include them in global.asa. In fact, your performance will suffer if you include an empty routine because the system will have to process the empty event handler each time. When you're not using any of the events, go ahead and omit the entire file.

horizontal rule

PAGE SIZE ISSUES

When we were learning how to create good Web sites, one of the rules of thumb was that a page should be less than 30kb, which will take approximately 15 seconds to download on a 28.8 Kb modem. While bandwidths have slowly increased, this is still a good rule of thumb. For your ASP applications, not only do you have to worry about the graphics, but you also have to worry about how much data is being sent to the user's browser. You can find out the download size by saving the resulting HTML locally and getting the disk size of the file. Combine the size of the graphics with the size of the text and you have your whole download size.

If your file is too large, try to incorporate some paging logic to reduce the download time. Keep in mind, too, that text data takes just as long to download as graphic data.

horizontal rule

STACK RECORDSET RETURNS

When you're retrieving a large amount of data for an ASP page, you can get all that data through a single stored procedure and a single call. Here's what your stored procedure might look like:

CREATE PROCEDURE sp_GetAllTheData AS
SELECT * FROM tblStates ORDER BY StateCode
SELECT * FROM tblCountries ORDER BY CountryName
SELECT * FROM tblTitles ORDER BY TitleName

This code will return three recordsets at the same time. Simply open the query as a static recordset, and then use the NextRecordset method to assign each recordset to a different variable, as shown here:

Dim rsStates, rsCountries, rsTitles
rsStates.Open "sp_GetAllTheData", dcnDB, adOpenStatic
Set rsCountries = rsStates.NextRecordset
Set rsTitles = rsCountries.NextRecordset

Since it's more time consuming to do another COM operation than it is to just pass more data, this technique offers the more efficient solution.

horizontal rule

ENCRYPTING COOKIE INFORMATION

We've talked about the benefits and problems of using cookies in your Web site. One of these problems is that the information in the cookie is sent and stored in clear-text format; that is, unencrypted. Typically, it's not a big deal if the information is not encrypted. However, if you want to store user IDs, passwords, and other sensitive data, encryption is essential.

Microsoft's Crypto API has a number of functions available for use with languages like Visual Basic so that you can create your own encryption library. If you don't have the time to do that, Persits Software has a product called ASPEncrypt that will do the job for you.

AspEncrypt

http://www.aspencrypt.com/

horizontal rule

IN-PAGE LINKS AND QUERYSTRING PARAMETERS

A reader asked how to use a relative link in combination with a query string variable. He wanted to create a URL similar to this:

page.asp?id=5#midpage

The problem with his attempt was that the order in which he created the URL was incorrect. The relative address (also known as the hash) has to be at the very end of the URL. The version shown above uses the correct sequence: all query string parameters, and then the pound sign and relative address.

horizontal rule

LONG-RUNNING ASP PAGES

A user asked how to handle an ASP page with a long run time. The page was timing out well before the task was done. The easy answer is to change the Server.ScriptTimeout property, which is set in seconds.

Before I would make this change, though, I'd ask why the page took so long to run in the first place. Is there work that is being done in the ASP page that would be better done by a component or a stored procedure? Is there an error or incorrect loop on the page?

The ScriptTimeout property exists to help prevent runaway pages. Before you change it, be sure that your code is clean and efficient.

horizontal rule

REQUEST OBJECT COLLECTIONS ARE OPTIONAL

When you're retrieving information from the Request collection, you probably do it like this:

strTemp = Request.Form("txtName")

However, you don't have to use the full name of the collection, and you could easily rewrite the line like this:

strTemp = Request("txtName")

ASP will automatically search all of the data collections for the key you selected. The collections will be searched in the following order:

QueryString
Form
Cookies
ClientCertificate
ServerVariables

The downside to using this method is that it takes longer to retrieve the information since the ASP engine has to search all the collections. One other thing to remember is that if you're going to use the information more than once, be sure to put it in a local variable. Accessing information in any of the built-in objects (Request, Response, etc.) takes longer than accessing a local variable.

horizontal rule

RESERVED WORDS AS VARIABLES

A user was having a problem with this code and couldn't figure out why:

Dim date
date = Now()

The problem here is that "date," in lowercase or uppercase, is a reserved word. The Date function returns the current date (according to the server). Since it's a built-in function, you can't use it as a variable.

horizontal rule

ACCESSING OBJECT PROPERTIES 

When you're using properties of objects that you'll be using multiple times, such as recordsets or any of the ASP objects, be sure to store the value in a variable. It is much faster to access a local variable than it is to read the property of an object. (This has to do with how the object is stored in memory.) As a rule of thumb, if I'm using a property more than once, I create a variable for it. 

horizontal rule

ADDING DEBUGGING STATEMENTS 

When building an ASP application, you often have to use statements to dump values at various points during the run of the page. Unfortunately, printing values in random places tends to cause HTML structures (especially tables) to not format correctly. That's why I recommend you print your debug values out as comments within the HTML. The output format of the page won't be corrupted, but you'll still be able to see the information you need in the source code for the page. 

horizontal rule

ADDING PERMANENT DEBUGGING CODE 

If you've built a lot of complex ASP code, you've probably added plenty of Response.Write statements to print out values during the run of a page. Because I hate having to re-enter all that data any time I want to debug the application, I created a handy function that is added "permanently" to the code. Based on a constant value defined in a server-side include file, the function will add comments to the output HTML with values that I need to see along the way. Here's the code: 

<pre>
Sub WriteDebugValue(strText)
If DEBUG Then
Response.Write "<!-- " & strText & " -->" & vbCrLf
End If
End Sub
</pre> 

The DEBUG constant is a simple constant defined like this: 

<pre>
Const DEBUG = True
</pre> 

If you want to disable the debugging code, just set the value to False.

horizontal rule

CLOSING RECORDSETS 

As I've mentioned in previous tips, it's always a good idea to explicitly set your object variables to Nothing when you're done with them. In addition, database objects, such as Connections or Recordsets, should also be closed before setting them to Nothing. Tired of typing the same code over and over again, I created a little method, called CloseRS, to close and destroy my recordsets: 

Sub CloseRS(rsInput)
rsInput.Close
Set rsInput = Nothing
End Sub 

I also created a similar routine, called CloseDB, to close the database: 

Sub CloseDB(cnInput)
cnInput.Close
Set cnInput = Nothing
End Sub


You could combine these two routines into one since both are calling the close method, but I prefer to keep the functions separated. 

horizontal rule

CREATING A QUICK ROLLOVER 

One feature I like to include on my Web sites is the link rollover. When you move your mouse over a link, the link becomes highlighted and the color is changed. While you can do this with JavaScript, there's a quicker way to do it with Cascading Style Sheets (CSS). 

First, you need to define a style for your links that does not underline them. Here's an example--the key property is the text-underline attribute set to none: 

.headinglink {
color : White;
text-decoration : none;
font-family : Tahoma, Arial, sans-serif;
font-size : 8pt;


The next thing to do is to add a style to your style sheet indicating that links should be underlined and the color changed, like this: 

A:hover {
color:#FF0000; 
text-decoration:underline;


This particular style indicates that links should be turned red when the user hovers over them. 

The last step is to format the link itself: 

<a href="http://wolfsburgii.com" class=headinglink>Visit Techsinfo today!</a> 

The one downside is that this feature does not work properly in Netscape 4.7. However, not having rollovers is not a critical feature to using my sites, so I don't worry about it. This method of coding is called (among other things) graceful degradation. For people with fewer features in their browser, not having the advanced features won't really make a difference and the site will still be usable. 

horizontal rule

CREATING A REGISTRATION COOKIE 

Many Web sites I visit allow me to register and login once and not have to login again from the same computer. This is typically done with a cookie that the site stores on my machine. The problem is that if the cookie is deleted, the server doesn't know who I am. A solution to the problem is to provide your users a username and password when they register. If they ever lose their cookie, they simply login to the system and a new cookie is written to their computer. 

If your site employs a user ID/password system, be sure to give the user the option to receive his or her password via email. (This will, of course, require you to collect an email address upon registration--you don't want anyone else to be able to pose as the person, request the password, and have it sent to his or her own email address.) 

horizontal rule

CREATING A TOP QUERY 

A user asked how to limit the results from a database query to say, 100 records. There are a couple of ways to do this. The first is to use the SELECT COUNT feature of SQL to determine the total number of records that will be returned based on a set of criteria. If the result is over 100, you could inform the user that the query can't be run. If it's under 100, you show the results. 

SQL also has the TOP keyword, which allows you to retrieve the first n records from a query. Here's an example of how to use this: 

SELECT TOP 10 * FROM Customers 

You generally should use this with an ORDER BY clause to sort the data appropriately. For instance, if you wanted the top 10 most expensive products from the database, your query might look like this: 

SELECT TOP 10 * FROM Products ORDER BY ProductPrice DESC 

horizontal rule

CREATING HIDDEN INPUT FIELDS 

Hidden input fields are useful when you're passing data from a form to another ASP file. However, if you're printing your HTML using Response.Write statements, you can end up with some fairly funny looking code: 

Response.Write "<input type=hidden name=ReplyToMessageID value=" _
& lngReplyToMessageID & ">" & vbCrLf 

Instead of dealing with these complicated lines of code, I created a subroutine to generate hidden input fields. This helps keep these statements consistent and correct. Here's the routine: 

Const DQ = """"
Sub HiddenInput(strName, strValue)
Response.Write "<input type=hidden name=" & DQ & strName & DQ _
& " value=" & DQ & strValue & DQ & ">" & vbCrLf
End Sub 

You call it like this: 

HiddenInput ReplyToMessageID, lngReplyToMessageID 

This makes your code easier to read, since you no longer have to read through and generate lots of messy lines of code. 

horizontal rule

DEJA.COM IS NOW GOOGLE.COM 

In previous tips, I've talked about the valuable Usenet newsgroup resources that Deja.com had at its site. Recently, Google.com acquired Deja.com's newsgroup archives. While some of the features that were available at Deja.com are not yet available at Google.com, Google.com has indicated that it is making a commitment to keeping this resource available. If Google.com does as good a job with its new Usenet resources as it has with its search service, we'll have one more valuable tool on hand. 

http://groups.google.com

horizontal rule

DELETING RECORDS, REVISITED 

In a previous tip, I talked about deleting records from database tables and some of the dangers inherent in not deleting records in the proper order. A reader from Denmark reminded me that SQL Server, and most databases, has the ability to cascade deletes through a series of tables, if the relationships are set up properly. If you delete the master record, a "delete trigger" would automatically delete the child records. 

While this is correct and it will work properly, it can pose an even bigger danger. If you have one of these triggers on your master customer file and accidentally allow a customer to be deleted, this could potentially wipe out data in any number of tables. You then have to rely on your backups (which, of course, you make religiously) to return the database to its original state. 

My original tip about being careful with, and possibly disallowing, deletes in your database is still the best approach. Only delete information that 1) is not linked to anything else, and 2) has no possible historical significance. Very little information that we store in databases falls into these two categories, but your situation may vary. 

horizontal rule

BROWSER-SPECIFIC CODE 

We all know how tricky it is to write code that works in both major browsers (IE and Netscape). There are some cases in which you need to determine which browser the user is using. Looking at the HTTP_USER_AGENT variable in the Request.ServerVariables collection can easily give you this information. This can get a bit tricky, however, since there are many variations of this tag, even when the browser is basically the same as another. For instance, if you use IE 5.5 on Windows 98 and Windows 2000, you'll get two different agent tags, even though the browser is the same. Check out the following examples and you'll get an idea of what I'm talking about: 

Mozilla/4.0+(compatible;+MSIE+5.5;+Windows+98;+The+Free+Internet)
Mozilla/4.0+(compatible;+MSIE+5.5;+Windows+NT+5.0)
Mozilla/4.7+[en]+(WinNT;+U) 

In this case, if I wanted to code specifically for IE 5.5, I would look for "MSIE 5.5" in the agent string. If I didn't find it, I might look for an earlier version or a compatible browser, like Mozilla 4.0. 

horizontal rule

DISABLING COOKIES 

We've talked frequently about how users can choose to disable cookies on their machine. You, as the Web site manager, can choose to not use cookies on a per-page basis, as well. Even if you're not explicitly setting cookie values, ASP often uses them to maintain session state. If you don't need session state, you can add this directive at the top of your page: 

<%@ ENABLESESSIONSSTATE = False %> 

This will prevent the server from sending any cookies to the user for that page. If you need to do this on a site-wide basis, you can add the directive into a common file that is included in all your other source files. Since many Web sites are simply providing information without requiring any state to be maintained, this is a good option to consider. 

horizontal rule

DON'T USE ID FOR SORTING 

It's common for programmers to add a bunch of data to a table, in a specific order, and then expect to get the data back in exactly that order every time. Depending on the database, this may or may not happen. Another common thing that some programmers do is sort the output data by the unique ID generated by the system. While this may work for a little while, once you start adding and dropping rows, the ID becomes less useful. In cases where I need to sort data in nonalphabetic order, I will typically add an extra field that I call "Ordinal." Its number is supplied by the person entering data and serves as the sort field. While you may end up with a duplicate ordinal number, this particular field is not tied to anything in the database directly so you don't have to worry about it changing on its own, so to speak. 

horizontal rule

ERRORS OPENING ACCESS DATABASES 

Here's a quick tip if you're using an Access 97 or 2000 database with Active Server Pages: You have to make sure that the directory in which the database lives is marked as writeable for the user ID used by the IIS process. Otherwise, the database won't operate properly from your ASP applications. Generally, I set up a separate directory outside the Web root directory. This way, I don't run the risk of someone attempting to download the database. For sites where I give FTP access, I will typically use this layout: 

www.website.com
databases
logs
www 

The FTP user will come into the top-level directory and can navigate from there. 

horizontal rule

MULTI-LINE COMMENTS IN ASP 

I previously discussed ways to deal with multi-line comments, allowing for the fact that VBScript doesn't support multiple lines of comments (each line has to start with a single quote to mark the line as a comment). Recently, however, a reader reminded me that not everyone writes server-side ASP using VBScript. If you're using JScript, you can use the /* and */ to mark multiple lines as comments.

horizontal rule

REGISTERING DLLS 

There are a number of services that offer free or inexpensive ASP hosting. A common question is whether you can create a DLL, move it to the server, and use it without any further work. The basic roadblock here is that the library has to be registered on the server for it to function and that involves calling the RegSvr32 utility. If the provider doesn't want you to use DLLs, there's no way you can register the DLL without administrator access to the server. (This is to protect the server and the other sites on the server from a potentially destructive or problematic library.) Some of these services will allow you to register libraries if you give the service access to your source code first. If you're interested in this service, be sure to check with your provider. 

horizontal rule

REMEMBERING A USER'S INPUT 

With most large forms, there are many possibilities for errors on the user's part. One thing that absolutely drives me nuts is to have filled out a huge form, just to receive an error message and have to re-enter all the data. For this reason, I don't subject my users to the same problem. When I validate data, I will do it within the same ASP page, which means I can call the routine to show the form again. When I do this, I show all the input data as values within the form. Here's one input box example: 

<%
Call Main 

Sub Main()
If Request("action") = "validate" Then
ValidateData
Else
ShowForm ""
End If
End Sub 

Sub ShowForm(strError)
If strError <> "" Then
Response.Write "<font color=#FF0000><b>" & strError &
"</b></font><br>" & vbCrLf
End If 

Response.Write "<form action=""" & Request.ServerVariables("SCRIPT_NAME") _
& "?action=validate"" method=post>" & vbCrLf
Response.Write "<input type=text name=txtInput value=""" & Request("txtInput") & """>" & vbCrLf
Response.Write "<input type=submit name=cmdSubmit value=""Submit"">" & vbCrLf
End Sub


Sub ValidateData() If Len(Request("txtInput")) < 5 Then
ShowForm "ERROR: Data must be at least 5 characters."
Response.End
Else
Response.Redirect "nextpage.asp"
End If
End Sub
%> 

In this case, whatever the user puts in the form will be redisplayed the second time the form is shown. This is a trivial example, but you can apply it to any size of form.

horizontal rule

SAFELY SHOWING VALUES IN FORM FIELDS 

Remember to surround your form field VALUE parameters with double quotes when you are showing a value, as shown here: 

<input type=text name=txtInput value="<% = strValue %>"> 

If your data has spaces or punctuation, those will be shown as part of the HTML and could cause errors. In addition, if there is a potential for HTML codes to be in the value (held in strValue in this case), you should use the Server.HTMLEncode routine, like this: 

<input type=text name=txtInput value="<% = Server.HTMLEncode(strValue) %>"> 

I frequently do this when I allow user input into a Web site. It prevents someone from writing troublesome script code. 

horizontal rule

SAVING SEARCHES 

One interesting thing about a search feature is that you can see what people want to know. For a site that thrives on new content, this is essential. By looking at what people are looking for on the site, I can tell where I need to focus my new content. Considering the fact that most searches will take a bit of time to run, adding another quick INSERT query to save the search doesn't slow it down much at all. 

In my particular system, here's the information I store for later reference: 

Date/time of search 
The keywords used in the search 
The type of keyword search performed (all keywords, any keywords, exact phrase) 
The sites/sections searched 
The discussion forums that were searched 
I am also revising the page to store the number of results that were returned so that I can tell if the search was successful. This feature is designed to make the content I have more relevant to what people want. If I'm not providing the right information, people are going to go elsewhere for their content. 

horizontal rule


STACK RECORDSET RETURNS 

If you're getting a bunch of data for an ASP page, you can retrieve all the data through a single stored procedure and through a single call. Here's what your stored procedure might look like: 

CREATE PROCEDURE sp_GetAllTheData AS
SELECT * FROM tblStates ORDER BY StateCode
SELECT * FROM tblCountries ORDER BY CountryName
SELECT * FROM tblTitles ORDER BY TitleName 

When you retrieve this, you'll get three recordsets back at the same time. Simply open the query as a static recordset, and then use the NextRecordset method to assign each recordset to a different variable, as shown here: 

Dim rsStates, rsCountries, rsTitles
rsStates.Open "sp_GetAllTheData", dcnDB, adOpenStatic
Set rsCountries = rsStates.NextRecordset
Set rsTitles = rsCountries.NextRecordset 

Because it's more time consuming to do another COM operation than it is to just pass more data, this is a more efficient way to retrieve a large batch of data. 

horizontal rule

PREVENTING A PAGE FROM CACHING

In a previous tip, you learned about the Expires property of the Response object and how it can be used to "expire" your page. This would, in theory, prevent a browser or proxy server from caching the page. However, it doesn't always work. A more reliable way to do it involves sending additional headers with the HTML page, using the following code:

<%
Response.Expires = 0
Response.ExpiresAbsolute = Now() - 1
Response.AddHeader "pragma","no-cache"
Response.AddHeader "cache-control","private"
Response.CacheControl = "no-cache"
%>

While this is also not guaranteed to work, it will work on more systems than Response.Expires will by itself.

horizontal rule

COUNTING RECORDS IN A RECORDSET

There are several ways to get a record count from a recordset; however, the most efficient way is to let the database do the work for you, as shown here:

<%
Dim dcnDB ' As ADODB.Connection
Dim rsData ' As ADODB.Recordset
Set dcnDB = Server.CreateObject("ADODB.Connection")
dcnDB.Open "connection string goes here"
Set rsData = dcnDB.Execute("SELECT COUNT(*) FROM tblCustomers")
Response.Write "Record count is " & rsData(0) & "."
rsData.Close
dcnDB.Close
%>

If you need to loop through the records afterward, it is better to close the recordset and then reopen it using the appropriate type of cursor for the situation.

horizontal rule

WORKING WITH MULTIPLE SUBMIT BUTTONS

In a previous tip, you learned how multiple submit buttons are handled by ASP. An alternative method uses the same control name with different values, as shown here:

<form action="submit.asp" method="post">
<input type=submit name=cmdSubmit value="A">
<input type=submit name=cmdSubmit value="B">
</form>

The value of Request("cmdSubmit") will be either A or B, depending on which button the user pressed.

horizontal rule

BUILDING A LIST AUTOMATICALLY

Here's a tip  on building either a drop-down list or a multirow list box by using a database query. While using the Select (drop-down or list) in a form with options populated from a database, you would normally like to display a descriptive field on the form but store the corresponding ID of the selection in the database. This can be accomplished with a simple operation:

<Form action=process.asp method=post>
<select name=Country>
<%
Set MyDB = Server.CreateObject("ADODB.Connection")
MyDB.Open "MyDSN"
Sql="Select Country_Code, Country_Name from Countries"
Set MyCountry = MyDB.Execute (Sql)
Do While not MyCountry.EOF
Response.Write("<option value=" & MyCountry("Country_Code")
_
& ">" & MyCountry("Country_Name") & "</option>")
MyCountry.MoveNext
Loop
MyCountry.Close
MyDB.Close
%>
</select>
. . . .
</Form>

In this example, the full names of all countries are displayed in the drop-down list, and on submission, you can obtain the code of the country chosen simply by doing a Request ("Country"), since we're already storing the code values within the <Option> tags corresponding to each country.

horizontal rule

ASP CODE DOESN'T GO ACROSS THE WEB--PART 1 OF 2

Here is an old bug in Internet Information Server (IIS) that can allow your ASP code to be retrieved across the Web. This was discovered a while back; however, many users are probably not aware of it. To see if you have the bug on your server, simply append

::$DATA

to the end of an URL using an ASP page. If you see the code, you've got the bug on your system. For more information and solutions for the bug, visit this URL on Microsoft's support site:

http://support.microsoft.com/support/kb/articles/Q188/8/06.ASP

horizontal rule

ASP CODE DOESN'T GO ACROSS THE WEB--PART 2 OF 2

Here is some more information on ASP code not going over the Web and some ways to prevent it: This is a very real concern at some sites. Oftentimes it's because of poor coding practice (placing clear-text passwords for database or file access inside ASP code). In the past, more than one exploit has been discovered in IIS that could be used to retrieve unprocessed ASP code. Also, there is no guarantee that components used by ASP code cannot be exploited to retrieve file data from a server. To resolve these issues, several people have come up with ISAPI DLLs that allow you to store your ASP files on the hard drive in encrypted format. The ISAPI DLL grabs the encrypted ASP file from disk, decrypts it in memory, and passes the results to asp.dll for final processing. The memory image is then zeroed by the OS before it is returned to the free memory pool. While this won't stop exploits that might be discovered in asp.dll, it does limit exploits that work either directly or through components on the file system. Look for links to ASP encrypting tools in the ISAPI section at

http://www.15seconds.com/

horizontal rule

SUBSCRIBE TO ASPWIRE

For the latest information about new products, reviews, and articles about Active Server Pages technology, visit the ASPWire site. Besides the Web-based news interface, you can also sign up for a weekly newsletter with all the latest content. If you have a Web site that covers ASP technology, you can submit your own news and have it broadcast to hundreds, if not thousands, of readers. Chris Duke, the editor of the site, does an excellent job of filtering out the noise from the signal and lets you get just the good content you're looking for. 
Check out
http://www.aspwire.com

horizontal rule

CALLING ANOTHER PAGE

Several readers have asked if it is possible to "call" another ASP page in the way you might call a subroutine in another language. At this time, the only options you have are to use Response.Redirect to transfer control to the page, or to include the code you want to call as part of the same ASP page and put it in a subroutine or function. However, IIS 5.0 (which ships with Windows 2000) has several new methods that allow you to execute another ASP page and return control to the original page when the code is complete. The Execute method of the Server object will run the code in another ASP page. Besides breaking up your code, this method can be used to do conditional includes of other files, which the standard server-side include directives can't. The Server object also has a new Transfer method, which passes the contents of all server-level objects, such as the Response object, to the next page. This method will make it much easier to have pages working together and will save you some time in having to code all the data values into the URL, a Session variable, or some other mechanism.

horizontal rule

INDEXING ROBOTS AND YOUR SITE

Most search engines perform "spidering" when they visit your site. They read a page, retrieve all the links from the page, and follow all those links. Eventually, they will hit all the pages on your site. Depending on how your site is set up, there are directories you might not want to have indexed, such as a utility library of include files that you use. For the most part, you can create a file called "robots.txt" and place it in the root of your Web site with instructions that look like this:

User-agent: *
Disallow: /includes
Disallow: /cgi-bin
Disallow: /pics
Disallow: /images

In theory, this file will prevent search engines from looking in the includes, cgi-bin, pics, and images directories. While the major search engines (and most of the smaller ones) will read and follow these instructions, remember that it is not a requirement. You should assume that any file on your Web server can be found by a search engine or a user intent on finding it.

horizontal rule

FINDING OUT WHERE THE USER CAME FROM

In Web traffic analysis, it's helpful to find out how users found your site, especially if the user came from a link on another page. A reader asked how to get this information, and it's really easy to do. In the page headers, there is an HTTP variable called HTTP_REFERER, which contains the URL that a user hits immediately before coming to your site. You can access this information through the ServerVariables collection, as shown in this example:

<a href="<% = Request.ServerVariables("HTTP_REFERER")%>">Go back to
where you came from</a>

If you have another page linking to this one, the HTTP_REFERER variable will show that as the previous page. Unfortunately, this method is not always reliable. In my own testing, putting this code on a page and then typing in its URL caused the variable to be blank. If you need a better way to track user movement through your site, you can add a URL parameter or session variable indicating the page you're on. In page #1, you set the value to some constant or code. In page #2, you first record the current value of the variable and then change the value to refer to the current page. As you work through the site, you'll have a "linked list" of how the user navigated the site.

horizontal rule

SHOWING HTML EFFICIENTLY

In a previous tip, I showed that you can "dump" HTML to the user by simply adding it outside the ASP delimiter tags. As several users have reminded me, ASP takes a performance hit when you do this. According to Bob Housedorf, the ASP.DLL engine has to parse out the HTML to send it to the user's browser. This takes more time than building a series of Response.Write statements. It will work both ways, but if you're on a busy site, the less time you waste, the better, even if the ASP code is somewhat harder to read.

horizontal rule

GETTING THE PAGE NAME

I try to avoid hard-coding page names in my ASP code as much as I can. Files get merged and renamed, and suddenly you've got a bunch of code that doesn't match up any longer. On a recent project, I inherited some code that had this construct to let users report bugs:

<a href="bug.asp?pageid=<% = strThisPage %>">Report a Bug on this
Page</A>

The strThisPage variable was being declared and set at the top of every page to be the name of the ASP file without pathnames or extensions. For instance, archive_top.asp would be shown as archive_top in the URL. To get rid of this redundant code, I made use of the SCRIPT_NAME variable in the ServerVariables collection. Here's how you would do it:

Dim strPageID ' As String
strPageID = Request.ServerVariables("SCRIPT_NAME")
strPageID = Left(strPageID, Instr(strPageID, ".") - 1)
strPageID = Mid(strPageID, InstrRev(strPageID, "/") + 1)
Response.Write "<a href=""bug.asp?pageid=" & strPageID & """>Report
a Bug on this Page</a>"

This code was added to a function and included in a common footer file for the site.

horizontal rule

GETTING BROWSER CAPABILITIES

MSWC.BrowserType object provides quite a bit of information about the user's browser.
Here's an example of how to use it:

<%
Set objBC = Server.CreateObject("MSWC.BrowserType")
%>
Browser: <%= objBC.browser %><br>
Version: <%= objBC.version %><br>
Supports background sounds? <% = objBC.BackgroundSounds %><br>
Supports frames? <% = objBC.Frames %><br>
Supports JavaScript? <% = objBC.javascript %><br>
Supports tables? <% = objBC.tables %><br>
Supports VBScript? <% = objBC.vbscript %><br>
<%
Set objBC = Nothing
%>

For Internet Explorer 5.0, I got this result:

Browser: IE
Version: 5.0
Supports frames? True
Supports tables? True
Supports background sounds? True
Supports VBScript? True
Supports JavaScript? True

The properties of this object are based on the values stored in the BROWSCAP.INI file, which is located on your Web server. Get a copy of the file and then try getting the values through the MSWC.BrowserType object.

horizontal rule

VALIDATING AND CLEANING TEXT

The 15seconds.com site has an excellent article with some helpful functions for cleaning and checking data in your Web data entry forms. It shows some quick ways to validate e-mail addresses, get data ready to be added to a SQL INSERT statement, and more. Read the article by going to

http://www.15seconds.com/issue/991014.htm

horizontal rule

ENVIRONMENT VARIABLE DUMP

Here's a quick snippet of code that will dump all the ServerVariables coming into a page. This is helpful for debugging pages that use these variables frequently:

<%
Dim objItem ' As Variant
For Each objItem in Request.ServerVariables
Response.Write objItem & ": " & Request.ServerVariables(objItem)
& "<br>"
Next ' objItem
%>

This is also helpful if you're looking for a piece of information and can't remember which server variable holds it.

horizontal rule

CREATING A QUICK SEARCH BOX

Many Web sites offer search capabilities to make it easier to find the data you need. Here is a quick and compact way to build a search box:

<form action="whatever.asp" method=post>
<input type="text" name="txtQuery" size=15>
</form>

When the user presses the Enter key, the form will automatically submit in both major browsers. For older browsers, you'll have to add a Submit button, since some browsers don't automatically submit data. If you have a more complex search form, provide a link near the quick search box (ala Deja.com).

horizontal rule

ACCESSING CLIENT MACHINE INFORMATION

Several readers raised this question: How can I get information about a user's login ID or machine name? The answer is that ASP, by itself, can't get it. Unless the data is passed through the ServerVariables collection, such as the IP address, you can't get it. You can get it, however, if you add an ActiveX control to your page. The ActiveX control, since it has to be installed on the user's machine (manually or automatically), has access to the whole machine and can retrieve information normally accessible through the Windows API. Obviously, if your users didn't know that you were retrieving information from their machines like this, they might be a bit upset. Be very careful how you use this capability, or users will simply stop downloading your applets or stop visiting your site entirely.

horizontal rule

UPDATING A DATE/TIME FIELD IN SQL SERVER

A user sent in a question asking why, when he builds an Update statement in ASP to update a date/time field, he always get a date with the time he wants to store. The user only needs to store a time value (such as 15:43) and not the date. The reason this happens is that in SQL Server, as in other database systems, a date/time value is not stored as text. Instead, the value is stored, for example, as the number of seconds that has passed since some date, such as December 31, 1899. If you just want to store the time, you have a few options:

* Store a dummy date with your time, such as January 1, 1900. When you retrieve the information, ignore the date and use the time information by itself.
* Store the time value as a text string and convert it to a time using
a built-in VBScript or database function.

Other options are possible, but these should get you started if you have the same situation.

horizontal rule

ASP AND DATABASE SUPPORT

A reader noticed that many of the examples that he sees use Access as the back-end database. His question was whether ASP supported other databases. The simple answer is yes, ASP supports many databases. If the database has OLE DB support, such as SQL Server or Oracle, you can skip any interfaces with ODBC. If there isn't an OLE DB provider for your database, Microsoft has an OLE DB Provider for ODBC, which can then interface with your (presumably) ODBC-compliant database.

horizontal rule

EXPORTING DATA FROM ASP PAGES

David Schultz has written an excellent article explaining how to export data directly into Excel by way of an ASP page. Because ASP pages have the ability to change the content type, you can cause Excel to open with your data. The content type determines how your browser handles the incoming data, whether that involves opening a browser window, a movie player, or any other application on your system. Read the article at this URL:

http://www.asptoday.com/articles/19991103.htm

horizontal rule

TUTORIAL ON COOKIES

The 4GuysFromRolla.com site has an excellent introduction explaining how and why cookies are used in Web pages. Cookies are covered often here in the daily ASP tips, so if you're not quite sure what we're talking about, this page will give you some help. Read the article at this URL:

http://www.4guysfromrolla.com/webtech/110299-1.shtml

horizontal rule

DATA ACCESS CONSTANTS AVAILABLE

Find yourself hard-coding a lot of the data access constants in your applications? If you weren't aware, there is a file called ADOVBS.INC on your server that contains all the data access constants that are used throughout the documentation on MSDN. While there are quite a few constants and including them all could degrade performance on some machines, I find that not having to look up and hard-code constants makes a performance hit worth it. You can find the file by doing a find from Windows or Windows NT Explorer. I found seven instances of the file on my server--you'll probably find the same.

horizontal rule

VISIT ACTIVE SERVER CORNER

The Active Server Corner site provides reviews, tips, and excellent articles for ASP programmers. Many of the articles are targeted at beginners, so no matter what level you're at, you should find something useful there. Right now, there's a good article explaining the differences between writing ASP code using VBScript and JScript. Go to
http://www.kamath.com

horizontal rule

DON'T USE OBJECTS IN SESSION VARIABLES

One of the major performance problems in ASP comes if you are storing objects within the Session object. Here's an excellent article explaining why this is such a bad thing:

http://www.activeserverpages.com/learn/nosessionobjects.asp

A better solution is to work within the MTS framework and allow it to manage your objects/instances. This greatly improves performance, especially on a large system with many objects.

horizontal rule

READ PROPERTIES SPARINGLY

If you're looking at property values of objects, such as the Request or Server objects, or any COM components that you might create, store the values in variables so that you don't have to read them more than once. Each property value read is expensive in computing resources. If you're doing it frequently, you're eating CPU cycles that could be better used elsewhere. A temporary variable allows you to reuse the property values without having to reread the object.

horizontal rule

DEALING WITH SINGLE QUOTES

In previous tips, you learned that when inserting single quotes into databases like SQL Server, you have to replace them with two single quotes for the insert to work properly. Here's an expanded version of this tip, including a detailed example of when you might use it:
http://www.swynk.com/friends/schofield/asp/startpage.asp?id=38

horizontal rule

BUILDING MULTIPAGE FORMS

A reader asked for some advice on multipage forms, in which a large form (like an insurance application) requires more than one screen of information. As we've discussed here, using Session variables eats system resources rapidly. For an application like this, I would put some sort of database behind the scenes to capture data from each page. When the user reaches the end of the application, you can tag the user's record with a Completed flag so that it can be exported or processed further. Any records that are not marked as completed and where the last update was more than 24 hours can be assumed to be incomplete and can be deleted. You could also allow the user to come back later to finish, in which case you'll need to write a cookie or store some sort of user information with the record in your database for later retrieval.

horizontal rule

USING SESSION VARIABLES FOR SECURITY

While using Session variables for everything is not a good idea, you can use them sparingly for instances such as login security. A basic security scheme you can implement involves two features: 
* A login page on which you validate the user, by whatever method you wish.
* Each page that needs to be secured checks a Session variable that is set after a successful login. If the user isn't logged in, redirect him or her to the first page.
The bonus with this method is that if the user leaves his/her browser open, the session will time out and will require another login. There are other methods of handling security, but this is one you can do without having to get to the IIS console (for those of you on virtual servers that you don't control).

horizontal rule

REBOOTING THE WEB SERVER

If you're doing much development using server-side components, you've found that once the DLL has been used by IIS, you have to reboot the Web services to recompile the DLL with any changes. This gets really tedious, especially if you have to do it through Control Panel. Instead of doing it that way, you can write a script to stop and restart the relevant services. Somewhere in the system path (I like the System32 directory), create a batch file with these lines in it:
@echo off
net stop iisadmin /y
net start iisadmin
net start w3svc
net start "FTP Publishing Service"
This stops the IIS Admin service, which also stops all related services (Web, FTP, etc.). It then restarts the IIS Admin service and the Web service, and I like to restart the FTP service, as well. Running this batch file can be done from a menu choice or from the Run prompt and is much faster than having to use the Services applet.

horizontal rule

GETTING BROWSER CAPABILITIES 2

Here's a tip about getting browser capabilities: The Browscap.ini file must be updated on the server as new browser
versions are developed. The latest file can be obtained from cyScape:

http://www.cyScape.com/browscap/

To ensure automatically that the browscap.ini file is up to date, users may want to check out cyScape's BrowserHawk, which continually checks the file for currency.

horizontal rule

GETTING THE PREVIOUS PAGE WITH HTTP_REFERER

Several people have reminded me that there is a bug in Internet Explorer that causes the HTTP_REFERER variable not to fill properly in certain cases. This means that if you post results from one page to another, HTTP_REFERER will not always point to the correct location. If you're looking to do a back button, you can use a little JavaScript to manipulate the user's browser history. Here's a link that will cause the browser to go back two entries in the history:
<a href="javascript:history.go(-2)">Return to the first page</a>
This JavaScript works fine in IE 5.0--your results may vary in other browsers.
If you do need the page name as part of the form input data, just add a hidden input field with the value of
Request.ServerVariables("SCRIPT_NAME"). That way, you guarantee that the filename is sent along with the rest of the form data.

horizontal rule

USING ASP WITH ODBC DATABASES

In many tips, we've referred to finding your OLE DB provider. Unfortunately, many databases do not yet have OLE DB providers. If this is the case with your favorite database, don't worry. OLE DB has a provider for ODBC. You can simply specify that provider and use a DSN to hit your database.

horizontal rule

ADDING DEBUGGING STATEMENTS

If you're building an ASP application, it's often the case that you have to use statements to dump out values at various points during the run of the page. Unfortunately, printing out values in random places tends to cause HTML structures (especially tables) to format incorrectly. A handy tip is to print your debug values out as comments within the HTML. The output format of the page won't be corrupted, but you'll still be able to see the information you need in the source
code for the page.

horizontal rule

SEARCHING TEXT FILES

4GuysFromRolla.com has published "Searching Through the Text of Each File on a WebSite," an article that demonstrates how to build a paged search engine that will search through a selected set of folders on a Web site, returning a list of files that contain the text entered by the searcher.
http://www.4guysfromrolla.com/webtech/120499-1.shtml

horizontal rule

HOW TO USE SSL

Wondering about security on your Web site? Read the article at ASPToday.com that discusses how and when to use SSL. In the first of a two-part series at ASP Today, Byron Hynes analyzes reasons for choosing SSL and some of the basics behind the encryption involved. Part I is geared more toward beginners or those who have not played with SSL.
http://www.asptoday.com/articles/19991206.htm

horizontal rule

CREATING OBJECTS

A user asked what the difference is between using an OBJECT tag and Server.CreateObject. The difference occurs when the object is created. Server.CreateObject makes an object whenever the code is executed. Using an OBJECT tag causes the object to be created only when the object is accessed.

horizontal rule

LIMITING RESULTS

A user asked how to limit the results from a database query to, say, 100 records. There are a couple of ways to do this. The first is to use the SELECT COUNT feature of SQL to determine the total number of records that will be returned based on a set of criteria. If the result is more than 100, you could inform the user that the query can't be run. If it's fewer than 100, you show the results. Another alternative is to get all the records and allow the user to see only the first 100. As you're looping through the recordset, keep a counter going and exit your loop if you pass 100. ADO is smart enough to get data only as it needs it, especially in forward-only recordsets, so you're not really getting all the data. My favorite way is not to limit the results, but to provide a paging mechanism for the user that allows him or her to see all the results that came back. Limiting the results to 100 doesn't really help the user, especially if it takes a while to download those 100 results. It would be more user-friendly to show 20 results on a page but let the

horizontal rule

MAINTAINING STATE BETWEEN WINDOWS

Several users have asked how to share information between multiple windows that may have been opened via JScript/JavaScript. There are a couple techniques you can use. The first involves passing data from the "parent" to the "child" through the URL. This will get the secondary window enough information to get going. At that point, the secondary window can get data from a database or somewhere else in the same way that the first window can. One point to remember when using multiple windows is that they can get confusing for the user, especially if you keep opening new windows for each record, for instance. If you need independent pages, you may want to consider using a framed page instead.

horizontal rule

USING THE LIKE KEYWORD

If you've ever done a search page, you've probably used the LIKE keyword in your SQL statement. This keyword allows you to match values based on a partial keyword, as in this example: 
SELECT * FROM tblCustomers WHERE LastName LIKE '%Smi%'
If you're building a query in Access, you need to use asterisks instead of percent signs to delimit the keywords. However, if you're sending the data in through ADO, the provider will translate percent signs to the appropriate character for the database. If you try using asterisks, the database will look for a field with asterisks in it. Consult your database documentation if you're not using a Microsoft database.

horizontal rule

BUILDING A SORTING QUERY

In many of my tables, I provide the option to sort by a column, as is used in the ASP Techniques Tip Archive. To make this work, I build a SQL statement that adds on a sort field based on the column selected, as shown here:
strSQL = "SELECT * FROM tblTips ORDER BY " & strSortField
Since we're not working with a data value, we don't need single quotes around the name of the sort field.

horizontal rule

NO CONTROL ARRAYS IN VBSCRIPT

If you've used Visual Basic, you're probably familiar with control arrays. Control arrays allow you to group all your option buttons, for instance, under a single name but with different numeric indexes. Unfortunately, VBScript does not support this feature. Each field has to have a different name. One reason for this is that HTML does not understand arrays in conjunction with data fields. You can just give the field a name and that's it.

horizontal rule

CREATING A REGISTRATION COOKIE

Many Web sites I visit allow me to register and then log in once and not have to log in again from the same computer. This is typically done by storing a cookie on my machine that is checked when I next visit. The problem is that if the cookie is deleted, the server doesn't know who I am. A solution to the problem is to provide your users with a username and password when they register. If they ever nuke their cookie, they simply log into the system and a new cookie is

horizontal rule

CREATING A WRITELINE FUNCTION

In several previous tips, you learned that any code printed using Response.Write is simply streamed into the output file without any white space or newline characters. To make this easier to do in my own applications, I've created a simple function called WriteLine that looks like this:
<pre>
Sub WriteLine(strText)
Response.Write strText & vbCrLf
End Sub
</pre>
This function saves me from having to always remember to add the vbCrLf character at the end of every line of code.

horizontal rule

ADDING PERMANENT DEBUGGING CODE

If you've built a lot of complex ASP code, you've probably added lots of Response.Write statements to print out values during the run of a page. As I hate having to reenter all that data any time I have to debug the application, I created a handy function that is added "permanently" to the code. Based on a constant value defined in a server-side include file, the function will add comments to the output HTML with values that I need to see along the way. Here's the code:
<pre>
Sub WriteDebugValue(strText)
If DEBUG Then
Response.Write "<!-- " & strText & " -->" & vbCrLf
End If
End Sub
</pre>
The DEBUG constant is a simple constant defined like this:
<pre>
Const DEBUG = True
</pre>
Best of all, when you want to disable the debugging code, just set the value to False.

horizontal rule

ACCESSING SQL SERVER THROUGH AN ASP PAGE

At some of my client sites, the SQL Enterprise Manager TCP/IP port (typically 1203) is blocked by a firewall. Since getting a firewall port opened nearly requires an act of Congress, I created a simple interface to provide access to an external SQL Server database that gives me a Web page to enter my SQL and run queries. Here's the code:

&ltpre&gt
Const ACTION = "a"
Const ACTION_VALIDATE = "v"
Const ACTION_EXECUTE = "e"
Const ACTION_QUERY = "q"

Call Main

Function BuildValidateURL()
BuildValidateURL = "&ltform action=""" &
Request.ServerVariables("SCRIPT_NAME") _
& "?" & ACTION & "=" & ACTION_VALIDATE
& """ method=POST&gt"
End Function

Sub WriteLine(strText)
Response.Write strText & vbCrLf
End Sub

Function OpenDatabase()
Dim dcnDB ' As ADODB.Connection
Set dcnDB = Server.CreateObject
("ADODB.Connection")
dcnDB.Open "Provider=SQLOLEDB.1;" _
& "Data Source=DBSource;" _
& "Initial Catalog=DBName;" _
& "User ID=userid;" _
& "Password=password;"
Set OpenDatabase = dcnDB
End Function

Sub Main
If Request(ACTION) = ACTION_VALIDATE Then
Dim dcnDB
Set dcnDB = OpenDatabase()
If Request("optAction") = ACTION_EXECUTE Then
dcnDB.Execute Request("query")
dcnDB.Close
Set dcnDB = Nothing
Response.Redirect Request.ServerVariables
("SCRIPT_NAME")
Else
Dim rsData
Dim rsField
Set rsData = dcnDB.Execute(Request("query"))
WriteLine "&lttable&gt&lttr&gt"
For Each rsField in rsData.Fields
WriteLine "&ltth&gt" & rsField.Name
& "&lt/th&gt"
Next
WriteLine "&lt/tr&gt"

Do Until rsData.EOF
WriteLine "&lttr&gt"
For Each rsField in rsData.Fields
WriteLine "&lttd&gt" & rsField.Value
& "&lt/td&gt"
Next
rsData.MoveNext
WriteLine "&lt/tr&gt"
Loop
WriteLine "&lt/table&gt"
rsData.Close
Set rsData = Nothing
dcnDB.Close
Set dcnDB = Nothing
End If
Else
WriteLine BuildValidateURL()
WriteLine "&ltinput type=radio name=optAction
value=" _
& ACTION_EXECUTE & "
CHECKED&gtExecute&ltbr&gt"
WriteLine "&ltinput type=radio
name=optAction value=" _
& ACTION_QUERY & "&gtQuery&ltbr&gt"
WriteLine "&lttextarea name=query rows=10
cols=50 wrap=virtual&gt&lt/textarea&gt&ltbr&gt"
WriteLine "&ltinput type=submit name=cmdSubmit
value=Submit&gt&ltbr&gt"
WriteLine "&lt/form&gt"
End If
End Sub
&lt/pre&gt

The form created with this code will have two option buttons, a text area, and a command button. Based on the option you pick, your SQL statement will either be executed or you'll get the results back from the query. Some of the functions at the top of the file are accessory functions that I use frequently--feel free to combine them into the code or to use the functions yourself.

horizontal rule

DATABASE PERFORMANCE TESTING

Ever wonder how ADO stacks up with all the other database technologies out there? Take a look at this article for a complete set of test results on the various database access layers:
http://www.pstruh.cz/tips/detpg_Perfdata.htm

horizontal rule

ADDING NEW TEMPLATES FOR VISUAL INTERDEV

A few weeks ago, I noticed that my Visual InterDev installation no longer had a New File option to create an ASP page. Somehow the template had been deleted, so I needed to create a new one. Here's how you do it:
Start by creating the ASP page you wish to use as a template (use either InterDev or another text editor). Then, save the ASP page to \VIntDev\Templates\NewFileItems and give it an appropriate name. That's it!

horizontal rule

PERMISSION DENIED FOR E-MAIL

A previous tip suggested that if you were unable to send e-mail from your Web page, it might be that your Web user ID didn't have permission for the e-mail objects. Clearing the appropriate check box to allow the Web site to run in the same process eliminated the error. In both cases, the Web user ID shown in the Directory Security tab stayed the same.

horizontal rule

WHERE TO VALIDATE DATA

A number of readers have written to describe how they do data validation in their ASP applications. Some use completely server-side validation, some use a mix of client- and server-side, and some use client-side alone. If you are able to do client-side validation using JavaScript, it will save you time in that each validation does not require a roundtrip to the server. However, some clients I've worked at have decided that client-side JavaScript (as well as Java applets
and ActiveX controls) poses a security risk. This means that all validation has to be done on the server in the ASP pages. The point is that there are lots of routes to the same result--and the one you choose is not always completely your choice.

horizontal rule

TRACKING CLICKTHROUGHS TO AN EXTERNAL SITE

Here's an interesting article at the Developers' Domain site about tracking clickthroughs to a site:
http://www.developersdomain.com/asp/articles/clickthru.htm

horizontal rule

VALIDATING DATA

Here's a tip about data validation in ASP applications: "I've used a combination of two different validation methods in the past to solve the problem of displaying form data and errors back to the user. All datatype and field length checks are done using JavaScript. This is quick and painless and saves a roundtrip to the server. All other business rule checks are done in a COM object for performance reasons. The Web site and the COM object must be running under MTS control for this to work and the page must post back to itself.
"First, I execute my 'save' routine. This routine returns a disconnected recordset of errors. If the recordset is not empty, I know I have to display errors, and I need all of my user's form data back. To do this I get the current ASP Request object related to the MTS object context for my component. Then, I can snatch the original posted form data from the request object, pump it into a separate disconnected ADO recordset, and display it back to the user with all of my error messages.
"Here's an example:
<pre>
<%
Set marsErrors = moForm.SetData(CLng(mlFirmId),
CStr(msFormType), _
CStr(msCallingAction),
mlFormNbRet, _
mdtReqDtRet, mdtExpDtRet, _
miDaysGrRet, msRsnDndRet, _
msFinalFlag, mbIsSubsequent)
Call CheckError()

If marsErrors.EOF = False Then
mlErrorCount = marsErrors.RecordCount
marsErrors.Sort = "ENumber"
mbShowErrors = True
msAction = msCallingAction
Set marsFormData = moForm.GetPostedData()
Call CheckError(
End If
%>
</pre>
"The thing that makes this work nicely is my routine (not shown) to create the page layout uses the same marsFormData recordset whether it is coming from a new form, a form in edit mode, or a form in error status."

horizontal rule

REMEMBERING A USER'S INPUT part 2

Note: This tip was posted last month, but the "method=post" was left out of the FORM tag. The code below takes care of the problem. Also, make sure that there is no HTML outside of the ASP delimiters, or you'll get an error when the Response.Redirect is attempted. In many large forms, there are many possibilities for errors on the user's part. One thing that absolutely drives me nuts is to have filled out a huge form, receive an error, and have to reenter all the data. For this reason, I don't subject my users to the same problem. When I validate data, I will do it within the same ASP page, which means I can call the routine to show the form again. When I do this, I show all the input data as values within the form. Here's a one input box example:
<%
Call Main
Sub Main()
If Request("action") = "validate" Then
ValidateData
Else
ShowForm ""
End If
End Sub
Sub ShowForm(strError)
If strError <> "" Then
Response.Write "<font
color=#FF0000><b>" &
strError & "</b></font><br>" & vbCrLf
End If
Response.Write "<form action=""" &
Request.ServerVariables("SCRIPT_NAME") _
& "?action=validate"" method=post>" & vbCrLf
Response.Write "<input type=text name=txtInput value=""" &
Request("txtInput") & """>" & vbCrLf
Response.Write "<input type=submit
name=cmdSubmit value=""Submit"">" & vbCrLf
End Sub
Sub ValidateData()
If Len(Request("txtInput")) < 5 Then
ShowForm "ERROR: Data must be at least 5 characters."
Response.End
Else
Response.Redirect "nextpage.asp"
End If
End Sub
%>
In this case, whatever the user put in the form will be redisplayed the second time the form is shown. This is a trivial example, but you can apply it to any size of form.

horizontal rule

WORKING WITH THE BACK BUTTON

A reader recently asked me how to pass all the user's data when the user presses the back button. Unfortunately, the back button is simply using the browser's caching capabilities. The only data that will be available when the user "backs" up will be the Session variables that may have been set, cookie values that were written to the user's computer, and anything in the page to which the user returns. Anything that was posted to the "next" page will have to be resubmitted and will not be available automatically in the Request collection. Basically, the user is starting the connection over with what is in the page and in Session variables and cookies.

horizontal rule

TIMING THE EXECUTION OF SCRIPTS

There's an interesting article at the 4GuysFromRolla.com site, covering how to time the execution of your ASP script code. View the article by going to
http://www.4guysfromrolla.com/Webtech/122799-1.shtml

horizontal rule

STATE PRESERVATION AND THE SESSION OBJECT

A reader wrote asking what the purpose of the Session object is in preserving state. He also wondered how the server determines what data goes with each user if multiple pages are submitted simultaneously. In most cases, you move from one page to the next by way of either a link or a form submission. Submitting form data is not really a function of ASP--ASP simply lets you get to the data through the Request object. The Session object is not directly related to this basic feature, either. You can code an entire application without ever using a Session variable--in fact, for performance reasons, you should avoid using lots of Session variables. The Session object has a property called SessionID, which is a unique value generated by the server for each distinct user visiting the Web server. This value is stored automatically in a cookie on the user's machine and is passed each time data is submitted to the server. The value allows the server to store Session-level variables for that user. This feature is useful for many different purposes, as has been demonstrated in previous tips on how to create logins that time out, and so on. The short answer is that the Session object does not directly affect normal data submission through HTML forms. It can be used to track a particular user's actions through the use of the SessionID property. That feature can allow you to determine how a user moves through your site during a particular visit. Note that the SessionID value can repeat if the server is rebooted, so don't use it for unique values in databases--stick to the AutoNumber or Identity feature of your database.

horizontal rule

DIFFERENT TYPES OF COOKIES

A reader noted that in an article on MSDN two types of cookies were mentioned: Session variable cookies and Data cookies. Session variable cookies are automatically generated by the Web server (unless you're using stateless pages) and are used to maintain Session variables for each user on the page. Data cookies are created explicitly by using the Response.Cookies collection (as demonstrated in previous tips). It's perfectly normal to have one, both, or none of these types of cookies in your Web application.

horizontal rule

WRITING A WEB PAGE COUNTER

Here's an interesting article at askASP.com, concerning writing a Web page counter using ASP:
http://www.askasp.com/articles.asp?ArtID=5

horizontal rule

CREATING STATELESS PAGES

By default, ASP applications make use of the Session object to maintain state. This will place a cookie on the user's computer. However, many sites (including my own VB Techniques and ASP Techniques sites) have many pages where maintaining state isn't really important. In these cases, you can add this directive to the top of the page:
<pre>
<%@ EnableSessionState=False %>
</pre>
You should place this script as the first line in your .asp file, before any other scripts.
Here's some additional information from MSDN:
"Sessionless ASP pages can often improve the responsiveness of your server by eliminating potentially time-consuming session activity. For example, consider the case of an ASP page containing two HTML frames: frames 1 and 2, both within one frameset. Frame 1 contains an .asp file that executes a complex script, while frame 2 contains a simple .html file. Because ASP executes session requests in sequential order, or serially, you will not be able to see the contents of frame 2 until the script in frame 1 has executed. However, if you make the .asp file for frame 1 sessionless, then ASP requests will no longer be serialized and the browser will render the contents of frame 2 before the contents of frame 1 have finished executing. "Unfortunately, the way in which multiple requests for different frames are processed ultimately depends on the configuration of the user's Web browser. Certain Web browsers may serialize requests despite the sessionless configuration of your .asp files."

horizontal rule

LINKING TO EXTERNAL SITES

One of the hardest things for Web site owners to do is to put up links to other sites. It's not that creating the links is hard; rather, putting up external links is inviting people to leave your site. Most people, once they leave a site, don't come back. To give people the option to return to both of my sites, I created a page wrapper that lets users browse the external site but allows them to click a link in a top frame to return to my site. Here's the code for the browsing page, external.asp:
<pre>
<html>
<head>
<title>Techsinfo: Browsing toExternal Site</title>
</head>
<frameset rows="60,*">
<frame name="fraTop" src="/external_top.asp"
marginwidth="10" marginheight="10" scrolling="no"
frameborder="no" noresize>
<frame name="fraContent" src="<% = Request
("url") %>" marginwidth="10" marginheight="10"
scrolling="auto" frameborder="no">
</frameset>
</html>
</pre>
The second part of the page is external_top.asp, shown here:
<pre>
<html>
<head>
<title>Techsinfo: Browsing to External
Site</title>
</head>
<body bgcolor=#990000>
<table cellpadding=5 cellspacing=0>
<tr>
<td valign=middle>
<a href="/" target=_top><img src="/pics/logo.gif"
width=168 height=38 alt="ASP Techniques - Return to
Home Page" border=0 valign=middle></a>
</td>
<td valign=middle>
<font color=#FFFFFF Face="Tahoma, Arial Black,
Arial, Helvetica" Size=4><b>Remember to come back when you're done surfing!</b></font>
</td>
</tr>
</table>
</body>
</html>
</pre>
Here's how an external link on my site would show up:
<pre>
<a href="external.asp?url=http://techsinfo.halocomputertech.com">
</pre>

horizontal rule

USING MOVE METHODS WITH RECORDSETS

Some readers have had various problems using the Move methods with their Recordset objects. The basic rule is that the recordset must support bookmarks or backward cursor movement to allow use of all the methods. If you have a forward-only recordset, the only method that is available is MoveNext. Anything else will cause a runtime error. All other types of recordsets (static, dynamic, keyset) will allow the use of MovePrevious, MoveNext, MoveFirst, and MoveLast. Disconnected
recordsets will also work with all these methods.

horizontal rule

COMBINING ASP, EXCEL, XML, AND XSL

Here's an excellent article at ASP Today on how to combine ASP, Excel, and XML/XSL to create dynamic sites:
http://www.asptoday.com/articles/19991229.htm

horizontal rule

VIEWING ASP PAGES IN INTERNET EXPLORER

A reader recently asked me why, after he created an ASP page on his local computer, it wouldn't work when he loaded it into Internet Explorer. He knew two of the three steps: create the file and view it in a Web browser. But he left out a key part: You have to put the file on an ASP-enabled Web server, such as Internet Information Server or Personal Web Server. If you look at an ASP page directly in IE, none of your server-side script code (within the ASP delimiter tags) will work.

horizontal rule

WORKING WITH MULTIPLE FORMS

A reader asked how he can capture the data from two different forms on the same ASP page at the same time. Because of the way form data is submitted, you can access only the data that is within the form delimiter tags. Here's an example:
<pre>
<% If Request("a") = "v" Then
Response.Write Request("txtBox1") & "<br>"
Response.Write Request("txtBox2") & "<br>"
Response.Write Request("txtBox3") & "<br>"
Else
%>
<form action="test.asp?a=v" method=post>
<input type=text name=txtBox1 size=20>
<input type=text name=txtBox2 size=20>
<input type=submit name=cmdSubmit value=Submit>
</form>
<form action="test2.asp?a=v" method=post>
<input type=text name=txtBox3 size=20>
<input type=submit name=cmdSubmit value=Submit>
</form>
<%
End If
%>
</pre>
When you run this, you can see two forms. If you put data in all three boxes and then click the submit button, you'll see only the values in txtBox1 and txtBox2 printed. If you need the value of txtBox3 as well, it should be part of the first form and not the second.

horizontal rule

DEPLOYING AN ASP APPLICATION

I've gotten several questions lately about deploying an ASP application to a Web server. Not that this is necessarily the best practice, but here's how I work on my own ASP sites:
* On my home server, I set up a Web site on a different port, like 7878 or some other random number. I then set up the appropriate directory structure. I give the site its own port number so that I can use absolute page references (like /include/common.asp) and I don't have to worry about what else is on the site. I do my development on this test server, including any testing. If I'm developing COM components for the site, they are registered on the test server.
* When the application is ready to go live, I copy all the files from the test server to the production server. If I'm using any COM components, those have to be registered on the production server. That's really all there is to it. You can use as many development/test servers as you need. For instance, you may want to set up a separate server for a testing team. If you're not working with that big of an application, you could just set up another Web site on a different port number. The only conflict would be if you were using COM components--in which case, you should probably set up your environments on different physical machines. That will allow one team's components to be separate from any others on the machine. 

horizontal rule

CLIENT-SIDE SCRIPTING VS. SERVER-SIDE SCRIPTING

A user asked about the differences between client and server-side scripting. The main, and most obvious, difference is whether the user can see your code. Any code in ASP pages that is between delimiter characters never makes it to the user's browser. By the way, you can embed JavaScript or VBScript code in your ASP pages that will make it to the user's browser--just make sure it's not inside your ASP delimiters, or the ASP engine will attempt to interpret it.
The other major difference is where the code is executed. All server-side code is executed before being sent to the user's browser. Client-side code is executed as needed inside the page in the user's browser. For some types of client-side code, like validation code, it's a great benefit to be able to complete validation without a round-trip to the server.

horizontal rule

WORKING WITH SQL SERVER CURRENCY FIELDS

A user asked why, when retrieving a database field that is of type Currency, no currency symbols are displayed. This is because the Currency data type in the database isn't designed to store the currency symbol. Instead, you can use the built-in FormatCurrency function to format the value using the regional settings of the server. This will ensure that your page displays the value using the proper punctuation and symbols.

horizontal rule

ACCESSING OBJECT PROPERTIES

If you're using properties of objects, such as recordsets or any of the ASP objects, and you plan to use them several times, be sure to store the value in a variable. It is much faster to access a local variable than it is to read the property of an object. (This has to do with how the object is stored in memory.) As a rule of thumb, if I'm using a property more than once, I create a variable for it.

horizontal rule

AVOID THE ADO ADDNEW AND DELETE METHODS

If you're looking to coax some performance from your Web application, be sure that you are using stored procedures or SQL statements to handle all your record additions and deletions. While you can use the AddNew and Delete methods of the ADO Recordset, they are quite a bit slower than the alternate versions that just use plain SQL or stored procedures.
For more performance tips, refer to the Developing Scalable Web Applications section of the MSDN Library.

horizontal rule

BUILDING A FORMAT FUNCTION--PART 1 OF 2

If you're like me, you miss the robust Format function from Visual Basic. The VBScript versions of formatting functions just don't have the oomph that most applications need. One simple solution, however, is to create a COM component that exposes the VB Format function, like this:
<pre>
Public Function FormatData(varInput As Variant, varFormat As Variant)
As Variant
FormatData = Format(varInput, varFormat)
End Function
</pre>
Compile this, and you'll have your Format function in a DLL for later use.

horizontal rule

BUILDING A FORMAT FUNCTION--PART 2 OF 2

Our previous tip showed you how to expose the VB Format function through a DLL. If you want an ASP solution (if you can't install components on your virtual server, for instance), here's a version in VBScript:
<pre>
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
'
' Function LeftPad
'
' This code adds leading zeroes to a number. This function is used
' by FormatDT to properly format dates and times.
'
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Function LeftPad(intNumber, intDigits)
Dim strResult
Dim strTemp
Dim i

strTemp = CStr(intNumber)
strResult = String(intDigits - Len(strTemp), "0")
strResult = strResult & strTemp
LeftPad = strResult
End Function

'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
'
' Function FormatDT
'
' This function allows date/time values to be formatted more flexibly
' than is allowed by the built-in FormatDateTime function.
'
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Function FormatDT(datInput, strFormat)
Dim strResult ' As String
Dim intTemp ' As Integer
Dim strTemp ' As String
strResult = strFormat

strResult = Replace(strResult, "#YEAR_LONG#", Year(datInput), 1,
-1, vbTextCompare)
strResult = Replace(strResult, "#YEAR_SHORT#",
Right(Year(datInput), 2), 1, -1, vbTextCompare)
strResult = Replace(strResult, "#MONTH_NAME#",
MonthName(Month(datInput)), 1, -1, vbTextCompare)
strResult = Replace(strResult, "#MONTH_NAME_SHORT#",
Left(MonthName(Month(datInput)), 3), 1, -1, vbTextCompare)
strResult = Replace(strResult, "#MONTH_2DIGIT#",
LeftPad(Month(datInput), 2), 1, -1, vbTextCompare)
strResult = Replace(strResult, "#MONTH_1DIGIT#", Month(datInput),
1, -1, vbTextCompare)

strResult = Replace(strResult, "#DAY_2DIGIT#",
LeftPad(Day(datInput), 2), 1, -1, vbTextCompare)
strResult = Replace(strResult, "#DAY_1DIGIT#", Day(datInput), 1,
-1, vbTextCompare)
strResult = Replace(strResult, "#HOUR_2DIGIT#",
LeftPad(Hour(datInput), 2), 1, -1, vbTextCompare)
strResult = Replace(strResult, "#HOUR_1DIGIT#", Hour(datInput), 1,
-1, vbTextCompare)
strResult = Replace(strResult, "#MINUTE_2DIGIT#",
LeftPad(Minute(datInput), 2), 1, -1, vbTextCompare)
strResult = Replace(strResult, "#MINUTE_1DIGIT#", Minute(datInput),
1, -1, vbTextCompare)
strResult = Replace(strResult, "#SECOND_2DIGIT#",
LeftPad(Second(datInput), 2), 1, -1, vbTextCompare)
strResult = Replace(strResult, "#SECOND_1DIGIT#", Second(datInput),
1, -1, vbTextCompare)

FormatDT = strResult
End Function
</pre>
You can create additional formatting options as long as the names are unique. The LeftPad function allows you to create times like 05:04:02 using the _2DIGIT tags.

horizontal rule

COM COMPONENTS AND TEXT GENERATION

If you're using COM Components in your ASP applications, remember that they can do a lot of menial tasks much faster than ASP can. For instance, any sort of string manipulation is much faster in the compiled component than it is in VBScript. This means that you can offload some of your string stitching (such as creating a drop-down list) to your component. Instead of passing back a recordset, pass back a complete list as HTML when necessary.

horizontal rule

CONVERTING BITS TO YES/NO VALUES

In an application I've been building, I have many cases in which I need to display to the user the value of bit fields in SQL Server. Instead of showing zeroes and ones or True and False, I created a quick little function that converts the values to Yes and No:
Function ConvertBitToYN(blnInput)
If blnInput Then
ConvertBitToYN = "Yes"
Else
ConvertBitToYN = "No"
End If
End Function
It's simple code, but the simple functions make programming quicker and less bug-prone.

horizontal rule

CREATING A PAGE COUNTER

A number of readers have asked about creating page counters, so we thought we'd dump a few ideas as to how to create counters. Older style counters relied on a graphic being loaded on each page being counted, and this is still possible. Simply create an IMG tag like this:
<pre>
<img src="mycounter.asp" height=1 width=1>
</pre>
The mycounter.asp page is responsible for counting the page hit and redirects the output to an invisible, 1x1 pixel graphic, for instance. A more elegant and efficient way is to call a function in the page to record a hit to a permanent storage system, like a database. The database can record the page name (from Request("SCRIPT_NAME")) and increment the number of pages through a quick stored procedure. A timestamp can be added on automatically, if necessary, or you can simply update the total if you're not tracking the actual hits. In short, there are lots of ways to count your visitors--it just depends on what you're going to do with the information eventually.

horizontal rule

DETERMINING A DATABASE PATHNAME

If you are running on a virtual server system, it can be difficult to determine where your files are in the grand scheme of things. A good example of this is finding your database pathname for your ADO connection string. For instance, on a virtual server system we use, my Web files are in a htdocs directory at the same level as a database directory, which is used to hold any Access databases we create. In order to get the pathname to the database, we have to figure out where we are, but we can't just put in the database directory since it's not accessible directly via the Web. Instead, we use the Server.MapPath routine to determine where the htdocs directory is. We then modify the result to point at the database directory. Voila, there's our database pathname. Again, you have to use the functions available to you if you want to spare yourself a call to tech support.

horizontal rule

DOWNLOAD A NEW ADOVBS.INC

Andreas Kviby has created a new, complete version of ADOVBS.INC that includes all the constants through ADO 2.1. You can download this file, for free, at
http://www.aspsweden.com/manual/adovbs21.asp.txt

horizontal rule

ENCRYPTING THE QUERY STRING

An article by Derrick demonstrates how to encrypt the information passed through QueryString. Using the Vernam encryption technique, you can encrypt the variable names and values that are being passed through QueryString. This is a very useful technique, especially if you need to pass sensitive information through QueryString. You'll find the article at
http://www.4guysfromrolla.com/webtech/012000-1.shtml

horizontal rule

GETTING NEWLY CREATED RECORD ID

In an application I was building, I needed to retrieve the unique ID value generated by SQL Server after I inserted the record. However, in a busy system, I might not get back the correct value. The solution was to use a stored procedure that returns two recordsets. Here's the SQL Server stored procedure I wrote:
<pre>
CREATE Procedure sp_AddImpression
@AdID int,
@AdSpaceID int,
@Referer varchar(255),
@HostAddress varchar(40)
AS
INSERT INTO tblImpressions
(AdSpaceID, AdID, Referer, HostAddress)
VALUES
(@AdSpaceID, @AdID, @Referer, @HostAddress)
Select @@Identity as AdID
</pre>
This inserts an ad impression record into a table, and then returns @@IDENTITY, which was the last identity value created. The interesting thing here is that the Insert statement also returns a recordset, even though it is empty. How do you get the second recordset? You use the often-overlooked NextRecordset method. Here's the code in the ASP page:
<pre>
Set rsImpression = Server.CreateObject("ADODB.Recordset")
rsImpression.Open "sp_AddImpression " & intAdID _
& ", " & intAdSpaceID _
& ", '" & Request.ServerVariables("HTTP_REFERER") _
& "', '" & Request.ServerVariables("REMOTE_HOST") & "'", dcnDB,
adOpenStatic

set rsImpression = rsImpression.NextRecordset()
intAdID = rsImpression("AdID")
rsImpression.Close
</pre>
I skip the first recordset generated by the Insert statement and go right to the second one, which has my identity value in it. This is helpful if you need the ID value back immediately and don't want to risk not getting the right one.

horizontal rule

HARDCODING PAGE NAMES

If you're building a multipage ASP application, you're often going to need to transfer the flow from one page to another. A handy technique I use defines all the page filenames as constants and then uses only the constants in the code. This lets me keep track of filenames, which often change, and lets me make a single change if I need to modify the filename for some reason.

horizontal rule

HEADER ERRORS WITH REDIRECT METHOD

A common problem in using Response.Redirect is an error indicating that header modifications must be made before writing page content. This error occurs because some HTML has been sent to the user's browser before the Response.Redirect call was made. The redirect directive is actually stored in the HTTP header sent along with the contents of the page--which is why you get an error complaining about header modifications. If you're going to use Response.Redirect, make sure that you don't send any HTML or that you use Response.Buffer to buffer the output until you've processed the page. If you use one of these solutions, the header errors will be eliminated.

horizontal rule

LISTING THE SYSTEM DSNS

An article by Mike Shaffer provides a free component that you can use to obtain a delimited list of System DSNs on a Web 
server. This component works with both PWS and IIS. If you have any administration-type pages, this component will save 
you time and automatically account for any DSN changes you may make in the future. Not only is the component DLL freely 
available, but the source code is available too. You'll find the article at
http://www.4guysfromrolla.com/webtech/011900-1.shtml

horizontal rule

ODBC AND ADO

A reader or two have asked me how the ODBC Control Panel applet figures into using ADO. The short answer is that for 
most databases, it isn't necessary. ADO can talk directly to many types of databases, including Oracle, SQL Server, 
Access, and more, without requiring any changes to ODBC on each machine. ODBC can be used if you have an ODBC driver for 
your database but don't have an OLE DB provider. In this case, you'll use the OLE DB provider for ODBC, which in turn 
can talk to your ODBC database. You'll need to make the appropriate ODBC entries in this case, but not under normal 
circumstances.

horizontal rule

PAGING THROUGH LARGE RECORDSETS

One of ADO's nicer features is its ability to work with large recordsets on a page-by-page basis. This means that if you 
have a recordset of 1000 records and want to see only the seventh page of 50 records, you can do so quite easily.
First, open the recordset as a static recordset--not a forward-only one. Set the PageSize property to 50 to indicate 
that you want to divide the records into 50 record segments. Set the AbsolutePage property to the page you want. Then, 
loop through the recordset until you've read 50 records (keep a counter) or hit the end of the recordset (EOF property = 
True). You can also add a page browser by looking at the PageCount property of the recordset (after the PageSize 
property has been set). If you have an odd number of records, the PageCount property will have an extra page for the odd 
records. For instance, 1001 with a PageSize of 50 would give a PageCount of 21.

horizontal rule

RELEASING OBJECTS

When you're done using an object, it's good to set it to Nothing to indicate to the system that you're no longer using 
it. While you can do this in ASP, be aware that the object isn't released until the page is finished running. Unless 
you're creating lots of objects, this won't really affect you. As soon as you set it to Nothing, the object is no longer 
available to you, though. It's just that the system doesn't reclaim the resources until the page is complete.

horizontal rule

SENDING PLAIN TEXT

If you ever have data that you need to send via plain text, you can do it using the Response.ContentType property. If 
you set this value to "text/plain", your browser won't attempt to interpret any HTML in the file. This is a good way to 
obtain numerical data, such as stock quotes and prices, for importing into other applications.

horizontal rule

 

Questions?

Just Check out some of our sponsors

Shop at BestPrices.Com!

web server downtime monitoring

HALO Computer Technology

COPYRIGHT 1998 - 2009 All names used are Trademarks of the respective companies

Home ] Up ]

Send mail to CompanyWebmaster  with questions or comments about this web site.
Copyright © 2009 HALO Computer Technology
Last modified: 03/11/09