Replacing the Error 500 ASP Page - Extending the Functionality (Page 4 of 7 )
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.
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-userís 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:
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.
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.