Programmer to ProgrammerTM  
Wrox Press Ltd  
   
  Search ASPToday Living Book ASPToday Living Book
Index Full Text
  cyscape.com

ASPToday Home
 
 
Home HOME
Site Map SITE MAP
Index INDEX
Full-text search SEARCH
Forum FORUM
Feedback FEEDBACK
Advertise with us ADVERTISE
Subscribe SUBSCRIBE
Bullet LOG OFF
                         
      The ASPToday Article
July 4, 2002
      Previous article -
July 3, 2002
   
 
   
   
   
Replacing the Error 500 ASP Page   JS Greenwood  
by JS Greenwood
 
CATEGORY:  Site Design  
ARTICLE TYPE: In-Depth Reader Comments
   
    ABSTRACT  
 
Article Rating
 
   Useful
  
   Innovative
  
   Informative
  
 5 responses

One of the most commonly viewed pages by traditional ASP developers is the "Error 500" page - the page that is displayed whenever there is any untrapped error during the processing of an ASP script. Compared to the error page displayed by ASP.NET, which contains more succinct data, a display of the source code containing the error, and a cleaner page layout, the classic ASP error page is rather unhelpful.



This article firstly looks at how error information is stored and obtained in ASP 3.0 - the ASPError object. This information is then used in the creation of a new error page that mimics the display of the ASP.NET page, providing a unified appearance for the display of errors. This is then extended to provide further functionality such as support for the editing of the offending code on the error page itself, and support for alternate devices (e.g. WAP browsers). This improved functionality allows for the easier location of errors, and a more rapid way of correcting them in small to medium scale projects.




   
                   
    Article Discussion   Rate this article   Related Links   Index Entries  
   
 
    ARTICLE

Introduction

As of ASP v3.0 (IIS 5, Windows 2000), whenever an unhandled error occurs during the processing of an ASP page, control is passed to a page specified in the Custom Errors section of IIS's settings. The default page that is used when such an "Error 500" happens displays similar content to other pages such as the 404 - File Not Found error. This is unhelpful for two reasons. Firstly, the page that is displayed is not very distinctive to developers due to this similarity - the relevant information is presented in a generic manner rather than one appropriate to the fact that there is an error, and more in-depth information would be beneficial. Secondly, for end users, the page displays information that they should probably not be privy to - how the page functions, what type of error has occurred, etc. Such information could theoretically be used to gain unauthorized access to the system. This type of information should be reserved for internal development and testing purposes.

The standard 500-100.asp error page

This article looks at ways of solving both of these problems - mainly focusing on improving the feature-set and usability for the developer. The first section covers the ASPError object, which contains all of the information that is made available by ASP regarding the errors that occur. Following that, the error pages that are displayed by .NET are described, and compared with the standard error pages. An implementation of this style of page is then given for classic ASP.

After all of the information that is available to us has been described and demonstrated, the appearance of this page is then simplified to provide more space for further functionality. Such features as syntax highlighting of source code are also added. Following this, a method of displaying a more appropriate error page for end-users of the system is described and implemented. Extra functionality is then added - such as allowing the editing of the code on the error-page itself (along with coverage of the pitfalls associated with this), support for other devices calling the ASP page, and the e-mailing of errors to the developer. Finally, consideration is given to further features that could be added to the error page.

With the exception of the following discussion of error trapping mechanisms available in the various languages, all of the information presented below is equally valid for ASP pages running VBScript or JScript. Errors that occur during the processing of client-side scripts such as ECMAScript (JavaScript) are not covered by this article.

The ASPError Object

In previous versions of ASP (prior to version 3.0, which is included with IIS 5), error handling was a tricky task. Although JScript has structured error handling, which is in line with the latest languages via try ... catch blocks, the only available option with VBScript was to put an On Error Resume Next before a piece of code, and to then check whether an error occurred after the line using an If Err Then ... construct. Following any error processing, error-trapping could be disabled using an On Error GoTo 0 statement. When functionality wasn't wrapped in COM components, which are largely developed using languages that support better error handling (such as Visual Basic and C++), many applications have been developed that have a single On Error Resume Next before any processing begins, with no subsequent error trapping or handling rather than trapping errors in such a time-consuming way.

With ASP 3.0, the situation changes a little, and error management becomes slightly more structured. This does not mean that VBScript has proper error handling such as an On Error GoTo Label statement, but a step has been made in the right direction with the inclusion of the ASPError object. This object is returned by the Server.GetLastError method call, and has the following read-only public members (which are covered in more detail in MSDN):

ASPCode Returns an error code generated by IIS
Number Returns the standard COM error code
Source Returns the actual source code, when available, of the line that caused the error
Category Indicates if the source of the error was internal to ASP, the scripting language, or an object
File Indicates the name of the .asp file that was being processed when the error occurred
Line Indicates the line within the .asp file that generated the error
Column Indicates the column position within the .asp file that generated the error
Description Returns a short description of the error
ASPDescription Returns a more detailed description of the error if it is an ASP-related error

As can be seen, there is far more information available in this object than in the standard Err object -most notably, the line and column where the error occurred, and an extra description. Whilst these details are far more useful, there is one fundamental problem; a piece of code such as the one given below will not work:

On Error Resume Next
dblValue = 1/0 '== Will cause a divide by 0 error
Set objError = Server.GetLastError
If objError.Number>0 Then
    'Do some error processing
End If

Once an On Error Resume Next statement is used, no errors are raised and objError won't contain any information - the only way to test for an error would be the traditional "If Err.Number<>0 Then ..." statement. If the On Error Resume Next line was missing, then processing would be transferred to the error page as soon as an error is encountered. This means that the only place that the error object can actually be used is on the error page itself. Control is passed to this page via a Server.Transfer() call as soon as an un-trapped error occurs. If needed, On Error statements can still be made to stop execution from passing to this page.

Editing the ASP Error Page

Although the introduction of this ASPError object doesn't provide any real improvement to error-trapping, it does mean that the error page that is displayed can display more detailed information and have much richer functionality. If you compare the error pages produced by IIS5 to the ones from IIS4, the benefits are clear. The page used in IIS5 defaults to the file 500-100.asp in the %SystemRoot%\Help\iisHelp\common folder. This file displays not only the file name and description of the error, but also the line number and column (if it could be calculated) of the error. As an aside, if an error occurs in this 500-100.asp page, then the message displayed will be in the format of that provided by IIS4.

Between IIS5's error page and the one provided for ASP.NET, there is an ever greater difference - the appearance of the latter is cleaner with the page looking noticeably different from other error pages (such as a 404 - file not found error), and a decent sized fragment of the source code is shown, with the offending line highlighted. The first task of this article is to recreate this new error page for classic ASP. Doing this will provide three major benefits

1. A standardized appearance for all error pages

2. A page that contains more information than the default 500-100.asp page

3. A more structured page that can have functionality extended simply

The third point is the most pertinent - if the standard 500-100.asp file is opened in an editor, it can be seen that the code is rather unstructured, with lots of context switches, and quite an obtuse use of HTML. By making this file more proceduralized with a better process-flow, not only can the appearance of the errors be changed more readily, but also support for displaying errors for developers, and a less technical page for remote users is far easier to implement.

Editing the Error 500-100 Page

The Custom Errors IIS settings

Rather than edit the existing 500-100.asp file, a new file to be used for processing errors can be created in any location accessible through IIS's virtual file-system for the web-site. This can be achieved by going into the IIS management console then viewing the properties of the server, application, or virtual-directory that is to have the error page changed. On the Properties window, the relevant setting is found on the Custom Errors tab, towards the bottom of the list under the HTTP Error"500;100" entry. If this item is selected, and the Edit Properties button is selected, then the URL can be changed to point to a different ASP (or HTML) file.

Error Mapping Properties Dialog

For the remainder of this article, the following URLs are assumed:

Recreating the ASP.NET Error Page

The ASP.NET error page

The image above is a sample screenshot of an error page generated by ASP.NET. As can be seen, it is much easier to see what the error is than in traditional pages - much of the superfluous text that used to be on error pages is now gone, and the source code that caused the error is presented in a far more noticeable and readable fashion. To produce a similar page in ASP the separate pieces of information that are required are:

The application name is the first thing that needs to be obtained. This can be formed by a little string manipulation on a couple of the ServerVariable s. The ones that we are interested in are INSTANCE_META_PATH and APPL_MD_PATH. The former of these will return a value such as "/LM/W3SVC/1", and the latter "/LM/W3SVC/1/Root/Projects". From this, we can see that removing the leading characters given in INSTANCE_META_PATH from the APPL_MD_PATH along with the string "/Root/" will give us an application name such as "Projects". The only special case to consider is if the error occurs in the root of the site, in which case the application name would be "/". This can then be written to the page as part of the red page-title, followed by a horizontal rule ("<hr>").

The next three pieces of information are available directly from the ASPError object, and are given (in order) in the Category, Description, and ASPDescription properties of the ASPError object. The first of these is written out as a heading ("<h2>"), and the others as paragraphs of text being preceded by the titles "Description", and "Parser Error Message".

The next piece of information is the largest difference between ASP 3.0 and ASP.NET - the display of the block of source code containing the error. To achieve this, we must create an instance of the Scripting.FileSystemObject class, read in the source file as specified by mapping the ASPError.File property to a physical file location. Once this file is read in, a call can be made to the Split() function passing in a carriage-return/line-feed ( vbCrLf) as a parameter, creating an array of the source-lines. A short For..Next loop can then be constructed to display the couple of lines around the error itself. The following code-sample approximates that which needs to be written:

strContents = Split(objFSO.OpenTextFile(strFileName).ReadAll, vbCrLf)
lngMin = objError.Line - 2
lngMax = objError.Line
If lngMin < LBound(strContents) Then lngMin = LBound(strContents)
If lngMax > UBound(strContents) Then lngMax = UBound(strContents)

For lngCount = lngMin To lngMax
    Response.Write Server.HTMLEncode(strContents(lngCount)) & "<br>"
Next

This code then simply needs the line containing the error highlighting in red, each line prefixing with the line number, and a small piece of HTML to produce the desired layout. One point to mention is that read-only file-access may have to be given to the default IIS user ( IUSR_MachineName) to allow it to obtain the contents to the source file. Also, if virus-killers such as Norton's AntiVirus 2002 are installed, then they may block access to files from ASP scripts - such options should be checked first as they can cause IIS to lock-up.

The next three pieces of information are displayed on a single line - the source-file containing the error, the line number, and the column number. If any of these pieces of information is not found in the ASPError object, then it is omitted from the page. An example of this can be seen in the screenshots below - the column number could not be calculated for the given error, hence it is left out from the page. All three of these pieces of information come straight from the File, Line and Column properties, with the File being converted to a local path using a call to Server.MapPath().

The final piece of information is not particularly useful in ASP 3.0: displaying server version information. In .NET, this information is useful, as it informs the developer of the version of the .NET Runtime and ASP.NET being used, especially important when Betas of the runtime were being tested. In the recreation of this, the information to be displayed is the SERVER_SOFTWARE and GATEWAY_INTERFACE. Both of these Server-Variables contain versioning information, but are of limited use in diagnosing potential problems. The only other Server-Variable that contains version information is the HTTP_USER_AGENT. This contains information regarding the user's browser version. The knowledge of which browser is being used can help to solve problems with the posting of data and so on. For instance, Internet Explorer on the Mac performs multi-part posts (those containing files) in a different manner to IE on a PC. Altering the page to display this information if it is necessary simply consists of editing one line of code, and for a Windows XP machine running the final release of .NET with SP1, and IE 6.0 would be something similar to:

Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461; .NET CLR 1.0.3705)

With all of this information put together into one ASP file, the page that is generated when an error occurs is shown in the screenshot below:

A recreation of the ASP.NET error page for ASP 3.0

Extending the Functionality

With the recreation of the ASP.NET error page, obtaining the majority of the information that is useful on an error page has been covered. What remains now is to decide what to do with this information to add extra functionality.

Firstly, details are given of determining whether or not to display debugging information at all. If an end user navigates to a site, it is generally not desirable to have them view the details of errors that occur, for several reasons. Most importantly, it is unintuitive to novice users - without concise yet descriptive explanations of the tasks they should perform they may abandon the task that they were performing. A secondary issue exists in that if another programmer sees what has caused the error, then vulnerabilities in the system may be exploited, potentially costing both reputation and money.

Following the implementation of a standard error page for users, the implementation of extra features for developers will be covered. Finally, this section covers is how to display the error information on an alternate device. WAP is used as an example of this, as developing WML has long been difficult in ASP due to the fact that the majority of devices can't display the HTML data that is returned from the scripts.

Live/Development Servers

As described above, there are several reasons for the creation of a separate error page for end-users of the system. Depending on the way in which the web-server is being utilized, different approaches to this can be taken. If the entire server is dedicated to one system, and a single user-error-page will suffice, then this page can be embedded in the "New 500-100.asp" file. If the server hosts several sites, then it is more flexible if a different error page can be displayed for each site.

To implement either of these techniques without different versions of pages having to be deployed to different servers, there must first be a way of determining whether the script is executing on a live/development server, or whether it is being executed by a developer or end user. The simplest way to do this, is to check the HTTP_HOST Server-Variable, and see if it is "Localhost". If it is, then we can assume that the system is being used for development purposes. This implementation should suffice in most cases, further implementations become far more intricate and case-specific in determining what role the site is being used under.

The first option is to check the Server-Variable AUTH_USER to see if the user has a valid NT Account (if Authentication is enabled for the site). If so, then the groups that the user is a member of can be checked to see if permissions exist for development roles. The second option is to check the IP Address of the client ( REMOTE_ADDR), and see if it falls within the local address space.

In the support code for this article, the implementation of the IsLiveServer function simply checks to see whether the site is being run from Localhost.

Once the role of the user has been determined, they can either have the debugging information displayed if they are a developer, or can have a standard error page shown if they are an end-user. Displaying the standard error page using the first technique - HTML contained in the New 500-100.asp page is the simplest to implement, either a simple context-switch can be performed, or the page can be displayed using multiple Response.Write statements.

If different pages are to be used for different sites then the task is a little more complex. A location must be found where a default error page resides. This can be done using the same technique used for displaying the application name at the top of the .Net error page. This path can be appended to the HTTP_HOST, and have a standard file name (such as "/error.htm") at the end of the URL. Once this string is created, the user can be sent there with a Response.Redirect command. This then allows the page to be presented with the appearance of other pages from that application - making use of the correct style-sheets, images, and so on.

Both methods of implementing an error page for end-users are given in the support code, in the function DisplayLiveErrorPage(). The particular implementation used is determined by the page-level constant LIVE_ERROR_REDIRECT. If set to true, then a redirection is made to an error page, otherwise an error page similar to the one shown in the screenshot below is given.

Default end-user error page

As this information is very generic, and does not give the user any real insight into whether the error was due to an incorrect action on their part, or whether the application has a bug in it, there is certainly room for improvement. This is one of the added benefits that using COM components can bring to web-development. If error-handling is performed at the business-logic layer - in the components - then more useful error messages can generally be raised, both for developers and end-users. One common technique in doing this is delimiting the error-messages returned - using a character such as a vertical pipe ("|") to separate the message returned for the different classes of user. If this is done, then the following code could be included in a VB component

Public Sub AddOrderQuantity(ByVal Quantity As Long)
    On Error GoTo EH
    '== Do some processing using Quantity
    Exit Sub
EH:
    If Not IsNumeric(Quantity) Then
        Err.Raise Err.Number, _
                "Parameter 'Quantity' not of type Long|" & _
                "Please ensure the entered quantity is a whole number, e.g. '1' or '3'", _
                Err.Source
    Else
        Err.Raise Err.Number, Err.Description & "|Unknown error", Err.Source
    End If
End Sub

The corresponding ASP for this would be something similar to:

    objOrder.AddQuantityToOrder(Request.Item("Quantity"))
    ...
    strDesc = objASPError.Description
    If blnIsLiveServer Then
        Response.Write Mid(strDesc, InStr(strDesc, "|") + 1)
    Else
        Response.Write Left(strDesc, InStr(strDesc, "|") - 1)
    End If

Once such functionality has been implemented, it is possible for a developer to see the error that occurred by replicating an end-users steps on the same machine, with the only difference being the error content that is rendered to the client, rather than introducing any extra variables into the equation.

There are many more in-depth techniques for dealing with errors that go well beyond the scope of this article. These include having lookup tables containing error-codes and their associated descriptions, building up an error-stack on the Err.Source, and so on. For further information on such error-handling methods, see the links at the bottom of this article.

With detection and handling of different user types covered, attention can now be focused on improving the page to make it more functional to developers.

Altering the Aesthetics

Although the information presented in the reworked page is both more complete, and more concise than that given previously, it is still far-removed from being integrated into the way a developer works. In a previous article, an implementation was discussed and developed for a replacement for the IIS directory browser. This browser took on the appearance of a standard Win32 application as much as was possible within the limitations of HTML. It is proposed that having an error page that fits in with this appearance is appropriate for two reasons.

1. It means that a fairly consistent interface for maintenance of a site can be presented - whether it's through a web-interface, or through the Explorer browser.

2. It makes a tabular presentation of data more appropriate, both reducing the cognitive (mental) load on the developer in finding the relative facts, and freeing up more space on the screen for extra functionality.

To produce the standard information presented on this page, a table will be created stating the properties of the ASPError object. To summarize this (as such information as the Category is generally unimportant), the most relevant details will be given to the top of the screen. To give the impression of a Win32 application, CSS-2 values such as ButtonFace and InfoBackground are used to set colors.

Summary of Error Information in Win32 Format

Syntax Highlighting

Beneath the now more compact details of the error, the source code can be displayed in a similar way to the ASP.NET error page, but with a more standardized appearance - i.e. white background, etc. Once this is done, one feature that is easy to implement is the"pretty-printing" of the code block that appears. This could be done with very little coding using the clsHighlighter VBScript class that was developed in an earlier ASP Today article. The implementation for this would be something as basic as:

Set objHighlighter = New clsHighlighter
strContents        = objHighlighter.HighlightCode(strContents, LANGUAGE_ASP)
Set objHighlighter = Nothing

Obviously, once this is done, highlighting the code of the line containing the error in red is no longer an option. With a small addition to the style-sheet, a border can be placed around the offending line of code, along with an alteration to the background-color, as shown below.

Syntax Highlighted code containing error

With the text of the code highlighted, and the background and border of the offending line itself changed, it becomes far easier to spot the errors in code. With an error such as the one above - a non-existent object, it is not particularly important to highlight the code. If the error was a standard syntax error, such as Resposne.Write rather than Response.Write, i.e. with the characters "s" and "n" the wrong way round, the fact that it is highlighted would quickly lead the eye to the error.

E-Mailing Errors

Another very simple feature that can be added to the error page is the ability to notify the developers that an error has occurred on a live site. This can be achieved by adding a single function to the ASP page - SendEMailNotification. This function has only to instance the CDONTS.NewMail class, set values for the recipient, subject, and body, and then send the e-mail. Whether or not this function is called will be based upon the IsLiveServer setting previously implemented. The information that is sent can not only include the error that occurred, and when, but also the data that was posted to cause the error and the current server settings, which may help diagnose the error more readily.

The only real logic performed in this function is a check to ensure that the NewMail class has been instanced properly (so that errors aren't generated on this page), and ensuring that the email is formatted properly to omit properties (such as Column) that may not have values. It should be noted that the From property of the NewMail class should have a valid e-mail address in it, otherwise the virtual SMTP server may fail to send the message. Such functionality could be implemented as below:

Set objASPError = Server.GetLastError
On Error Resume Next
Set objMail     = Server.CreateObject("CDONTS.NewMail")
On Error GoTo 0

If Not objMail Is Nothing Then
    strDomain = Request.ServerVariables.Item("HTTP_HOST")
    objMail.From    = "error@" & strDomain
    objMail.To      = "recipient@tempuri.org"
    objMail.Subject = "Error in http://" & strDomain & _
                      objASPError.File

    objMail.Body    = objASPError.Description & vbCrLf & _
                      "Any other information can go here"

    On Error Resume Next
    objMail.Send
    On Error GoTo 0
End If

In environments with more elaborate bug-tracking systems, this feature could be altered to create an entry in a bug-log to ensure that it is dealt with properly. If the file that caused the error contained the developer's name, then this bug could also be allocated to the correct person. In stricter situations still, such information could be used to determine the percentage of errors introduced by each developer in a team.

Code Editing

When simple errors are detected when coding and testing on a local machine, it is often an annoying process to find the offending ASP file, check it out of any source-control system (such as Source Safe) that is being used, make the change, and check it back in. Especially when the error is regularly something as trivial as a mistyped statement such as the infamous Resposne.Write. This is made even more annoying when the error is on a development server that has a file-system that may be remotely inaccessible, making updates using Interdev, Notepad or any other local editor impossible. In such cases, remote management tools such as Terminal Services, PC Anywhere, or VNC are regularly the main way of accessing these files. Worse still, an FTP connection may be the only method of accessing the files. Updating files in this manner may in itself introduce errors from uploading to the wrong location. This is especially true if there are multiple versions of the site on the machine.

To solve this problem, the error page is to be extended to allow the editing of the page in-situ. In theory, if such editing is to be common-place, then usage of a Java applet, an Active-X control, or client-side script instancing an editor of choice are all reasonable options. For this article, we'll settle for the relatively simple task of adding a <textarea> element and a <submit> button to demonstrate the theory. There are still special cases and best-practices to be considered though. Firstly, the editing pane is not to be displayed all the time - only on the request of the user. This is to remove the possibility of accidentally editing code. The text-area and submit button are placed in an invisible layer that is only shown when the Edit Code >> button is clicked. Similarly, the code can be hidden by clicking on the same button again.

More seriously, when the form is submitted for processing, we must be very careful about what action is taken. The usual case of checking a form variable such as "Action" to see if the user is trying to edit a page cannot be trusted as this action may be taken prematurely - when the original error occurs, if such a field exists on that page. A check to the HTTP_REFERER would be the ideal solution, but is unfortunately out of the question. As the 500-100.asp page is executed using a Server.Transfer call, as far as the browser is concerned, when the error page is displayed it is still at the original location, not that of the error script. Instead, the form fields must be constructed in such a way as to remove the possibility of accidental editing. In the sample code, the field that is checked is called "Err500Action".

To complete the editor, only two things remain to be done. Firstly, a hidden field must be added to the form specifying the URL that is to be edited (technically this could be retrieved from the HTTP_REFERER variable, but that would then rely on the browser sending that information; alternatives to IE may not. Secondly, the server side processing to edit the file needs implementing. This simply involves the instancing of the FileSystemObject class, and the contents from the page writing out to the relevant text-stream. The result of this (success/failure) is then reported to the user via the message box at the top of the screen.

It should be noted that there is potential for end-users to edit the source code of a site if they can convince the IsLiveServer function that they have developer privileges. If this code is to be used on a live server (which if a rigorous development and porting process is being adhered to, it shouldn't), then it should be ensured that there is no reasonable method by which any unauthorized person can forge the credentials required to allow the display of the debugging page/editing of the source code.

For the editor to actually function, it must be ensured that the user's context that IIS is running under has the relevant permissions to edit the file. If this isn't the case, the error that will be displayed on the Error 500 page will be "Object required" as an attempt to edit a file that could not be retrieved will have been made. If the On Error Resume Next code is removed from the line above the OpenTextFile() call, then the true error of "Permission denied" will be seen. To allow editing, any users that are to have access to this online code-editor must have read and write (modify) permissions to the files that exist in IIS's virtual folder-structure. If NTFS is being used, then this can be done from within Explorer by right-clicking on the relevant files/folders, then selecting the "Security" tab, and enabling rights to the relevant users (probably IUSR_ Machine name amongst others).

SourceSafe Integration

One of the more interesting aspects of adding a text editor to the web page itself, is the way in which source-control fits in to the equation. At first glance, it would seem that editing in this manner would break many guidelines and best practices on source-control. When examined in more detail, it is actually quite an appealing option. Although Source Safe is used as an example below, a source-control provider could potentially be used.

Firstly, as a file can be checked out, edited, and checked back in in quick succession, there is less likelihood of preventing other users from editing a file than is normally the case. Secondly, changes are often made to code to test it without actually checking the file out of SourceSafe. When this is the case, there is potential for any changes made to be lost if the source-controlled version is checked out over the top of this file. The final, and possibly the biggest benefit is the ability to add comments to the file. Whenever a change is made, the error message that the user is trying to correct, along with which machine the error was on, the server configuration, and so on, could all be stored as comments, providing in-depth auditing of bug-fixes to a system.

To achieve this functionality, there are two possibilities - either using the command-line SourceSafe tools, or using the SourceSafe object-model. In the included source-code, the object model has been used for three reasons. Firstly, it is simply a COM object like any other, is designed just for automation tasks such as this, and provides greater functionality than the command-line version. Secondly, running executables on unattended servers is never a wise thing to do as feedback via a UI may be required at some point, locking processes on the server until interaction is given. Finally, the IIS user must be given permissions to invoke executables if the command-line option is to be used. This would create a potential security risk, giving more permissions than are strictly necessary to a guest user account.

Performing operations using the SourceSafe object-model requires only a couple of method calls. The code below gives an example of how to check out a file using this method:

Set objSS = Server.CreateObject("SourceSafeTypeLib.VSSDatabase")
objSS.Open INI_PATH, USERNAME, PASSWORD
objSS.VSSItem("c:\sslocal\test.txt").Checkout "", "", VSSFLAG_USERROYES

As can be seen from this code, in addition to knowing what file the action is to be performed on, there are four pieces of information that are required:

VSSFLAG_USERROYES This is constant informing SourceSafe that the ReadOnly flag on the file should be utilized
INI_PATH This is the path to the srcsafe.ini file that contains the configuration data for the SourceSafe database
USERNAME This specifies the username that all actions should be carried out under
PASSWORD This parameter contains the password for the specified username.

Using these values, and other methods, such as CheckIn and UndoCheckout, all of the necessary functions can be carried out on the file being edited. Unfortunately, some users may have problems instancing this object, with an error being raised of "Invalid Class String". This error is generally due to permission problems with the anonymous user. If this is the case, then Read/Execute NTFS rights should be given to the user on the SSAPI.DLL file located in the folder "...\Program Files\Microsoft Visual Studio\Common\VSS\win32". Further information on this error can be found at the referenced URL given at the bottom of this article. Alternatively, a couple of lines of text such as the following could be used to invoke the command-line version:

strCommand = "c:\...\Win32\ss.exe Checkout """ & strFileName & """ -GWR"
Set objShell = Server.CreateObject("WScript.Shell")
objShell.Run strCommand, 0, True

The ellipsis ("...") should be replaced with the path to SourceSafe's folder (usually "C:\Program Files\Microsoft Visual Studio\Common\VSS"), and the "Checkout" sub-string can be replaced with other command such as "Checkin" and "UndoRollback". For the command-line version to function correctly, several environment variables such as SSUSER and SSDIR should be set. For more information on this, see the reference towards the bottom of this article.

Multiple Platform Support

To developers creating application with ASP that aren't targeting an HTML client, the standard error page regularly provides no real use at all, and can cause problems if the data it provides is not in the correct format. For instance, an alternative use for ASP is the creation of WAP sites, where the target language is WML. Whilst the syntax of this language is similar to HTML, several errors will be generated if the standard HTML error page was sent to the client. The first of these errors would be due to the size of the page -WML pages are limited to just a couple of kilobytes. Although this could be easily remedied with the error page displaying a reduced amount of information, this wouldn't solve the more important issue - the document would have the wrong content type, and would not be a valid WML compliant document.

To add support for WML (and potentially for more languages), the error page must detect the client that is requesting the information. This can be achieved by making use of the HTTP_ACCEPT Server-Variable. This value stores a comma-separated list of data-formats that are accepted by the client. For IE (and most other HTML browsers), this list includes "*/*". If this value occurs, then the HTML error page can be displayed, otherwise the WML error page can be rendered instead. In more complex systems, the supported formats of the individual browsers can be checked.

The ASP required to support the WML error page would be something similar to:

If InStr(Request.ServerVariables.Item("HTTP_ACCEPT"), "*/*")>0 Then
    DisplayHTMLErrorPage
Else
    Response.Write "<?xml version='1.0'?>"
    Response.Write "<!DOCTYPE wml PUBLIC '-//WAPFORUM//DTD WML 1.1//EN' 
'http://www.wapforum.org/DTD/wml_1.1.xml'>" & vbcrlf
    Response.Write "<wml>" & vbcrlf
    Response.Write "  <head>" & vbcrlf
    Response.Write "    <meta http-equiv='cache-control' content='must-revalidate'/>" & vbcrlf
    Response.Write "    <meta http-equiv='pragma' content='no-cache'/>" & vbcrlf
    Response.Write "  </head>" & vbcrlf
    Response.Write "    <card id='Error' title='Error'>" & vbcrlf
    Response.Write "    <do type='prev' label='Back'><prev /></do>" & vbcrlf

    Response.Write "    <p>" & objASPError.Category & "</p>" & vbcrlf
    Response.Write "    <p>" & objASPError.Description & "</p>" & vbcrlf
    Response.Write "    <p>" & objASPError.ASPDescription & _
                    ": Line " & objASPError.Line & "</p>" & vbcrlf

    Response.Write "  </card>" & vbcrlf
    Response.Write "</wml>" & vbcrlf
End If

Rather than providing one-off implementations such as this, an XML document describing the error that has occurred could be generated. The type of document that the client accepts could then be detected, with a specific XSLT transformation being applied for each. This would allow for debugging of systems developed for CHTML and iMode browsers amongst others.

Further Extensions

As described earlier, the e-mail functionality could be extended to provide support for full development teams - sending messages to the relevant developers, and creating entries into a bug-tracking system automatically, and adding comments to source-controlled files. To do this, meta-information would need to be stored in the source-file, containing such information as the developer's name/username, which application the code was part of (this could probably be calculated from the IIS application name), etc.

Although the text editor makes quick-fixes very easy to carry out, it is less functional than the most basic implementation of Notepad. The addition of a go-to-line function would certainly help a lot, and the ability to set tab-indents, highlight the code, and so on would make this a viable second-choice development environment when it is known that there are several errors that all need correcting across a site.

To implement such features, it would be necessary to replace the Textarea element with an Active-X edit control, Flash/Java applet, or other program based on a richer language than HTML. There are several editors on the market that have Active-X interfaces - enabling them to be embedded in compliant environments (e.g. Delphi, Visual Basic, C++). These can also be embedded into web pages, and a simple piece of DHTML to set the content of a hidden field to the value of the Active-X control's text before posting the form back would ensure the remainder of the implementation would still function as before.

A further issue that could be addressed by this page is in the transmission of error codes to client browsers. Internet Explorer v5.0 and above has settings that are enabled by default to "Show Friendly HTTP Error Messages". These messages over-ride error pages that are sent from the server, replacing their content with fairly generic information regarding errors. These "friendly" pages are only displayed if an error code (a status other than 200) is sent to the client with the web page. If no call is made to Response.Status in the error page to specify an error code, then the browser will always display the content that is returned from IIS.

Conclusion

In this article, the ASPError object that was introduced with ASP 3.0 was discussed. This was then related to the use of custom error pages - more specifically the Error 500-100 error page that is displayed when an error occurs on the server during the execution of the script. A comparison of the functionality between the page that is displayed in ASP 2.0, 3.0, and .NET was made, concluding with a re-implementation of the ASP.NET error page to allow for more rapid debugging.

The re-implementation of the ASP.NET page was followed with coverage on how to use error pages for two different reasons - alerting the end-user to errors, and allowing a developer to have the necessary information to correct such errors. With this information, a less technical error page was developed for end-users before adding further functionality to the development error page. This functionality included syntax highlighting of the code containing errors, e-mailing of errors to development staff, and the ability to edit and correct the code in-situ. Source-safe integration was then added to allow for the usage of such features in enterprise scale environments.

Finally, the re-use and extension of the code was dealt with - including integration with a bug-tracking system and the replacement of the text-editor with a full-featured one. The result of this article is a replacement for the standard IIS Error 500 page that:

1. Makes it simpler to identify errors

2. Makes it much simpler to correct these errors

3. Allows for more appropriate error messages to be displayed to end-users of the system

The finished error page created in this article

Please rate this article using the form below. By telling us what you like and dislike about it we can tailor our content to meet your needs.

Article Information
Author JS Greenwood
Chief Technical Editor John R. Chapman
Project Manager Helen Cuthill
Reviewers Vikram S, Dinar Dalvi

If you have any questions or comments about this article, please contact the technical editor.

 
 
   
  RATE THIS ARTICLE
  Please rate this article (1-5). Was this article...
 
 
Useful? No Yes, Very
 
Innovative? No Yes, Very
 
Informative? No Yes, Very
 
Brief Reader Comments?
Your Name:
(Optional)
 
  USEFUL LINKS
  Related Tasks:
 
 
   
  Related ASPToday Articles
   
  • Textually Parsing ASP Files (March 25, 2002)
  • Replacing the IIS Directory Browser (November 30, 2001)
  •  
           
     
     
      Related Sources
     
  • Source Safe Object Model: http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnvss/html/vssauto.asp
  • Command Line Source-Safe: http://msdn.microsoft.com/library/en-us/ssusexp98/html/ssugecommand_line_overview.asp?frame=true
  • http://www.asphole.com/StoriesRead.ASP?ID=31: ASPError documentation
  • VB Error Handling : http://angelibrary.tripod.com/computer/visual_basic/ch14.htm
  • ASP Error 800a01ad : http://support.microsoft.com/support/kb/articles/q194/8/01.asp
  • Norton Antivirus : http://www.amazon.com/exec/obidos/ASIN/B00005NZ5Z/ref=nosim/asptoday-20
  • CDONTS Object Model : http://www.devasp.com/Samples/mail.asp
  •  
     
           
      Search the ASPToday Living Book   ASPToday Living Book
     
      Index Full Text Advanced 
     
     
           
      Index Entries in this Article
     
  • ASP code
  •  
  • ASP.NET
  •  
  • ASPCode property
  •  
  • ASPDescription property
  •  
  • ASPError object
  •  
  • Category property
  •  
  • CDONTS
  •  
  • Column property
  •  
  • cross-platform compatibility
  •  
  • custom errors
  •  
  • debugging
  •  
  • Description property
  •  
  • displaying
  •  
  • editing
  •  
  • email, sending
  •  
  • Err object
  •  
  • error handling
  •  
  • error information
  •  
  • error messages
  •  
  • error page
  •  
  • File property
  •  
  • FileSystemObject object
  •  
  • From property
  •  
  • generating WML using ASP
  •  
  • GetLastError method
  •  
  • HTML
  •  
  • IIS
  •  
  • JavaScript
  •  
  • Line property
  •  
  • MapPath method
  •  
  • NewMail object
  •  
  • Number property
  •  
  • object model
  •  
  • OpenTextFile method
  •  
  • problems with
  •  
  • Redirect method
  •  
  • Request object
  •  
  • Response object
  •  
  • Send method
  •  
  • Server object
  •  
  • ServerVariables collection
  •  
  • Source property
  •  
  • SourceSafe
  •  
  • split method
  •  
  • syntax highlighting
  •  
  • Transfer method
  •  
  • using
  •  
  • VBScript
  •  
  • Visual SourceSafe
  •  
  • WAP
  •  
  • WML
  •  
     
     
    HOME | SITE MAP | INDEX | SEARCH | REFERENCE | FEEDBACK | ADVERTISE | SUBSCRIBE
    .NET Framework Components Data Access DNA 2000 E-commerce Performance
    Security Admin Site Design Scripting XML/Data Transfer Other Technologies

     
    ASPToday is brought to you by Wrox Press (http://www.asptoday.com/OffSiteRedirect.asp?Advertiser=www.wrox.com/&WROXEMPTOKEN=724574ZAnfolMicLVsJe7QDwtp). Please see our terms and conditions and privacy policy.
    ASPToday is optimised for Microsoft Internet Explorer 5 browsers.
    Please report any website problems to webmaster@asptoday.com. Copyright © 2002 Wrox Press. All Rights Reserved.