Learning the ASPError Object - ASP's 7th built in object
No more of the old, bland error messages that everyone's used to
from the older releases of IIS and ASP. If you're using ASP 3 and
IIS 5, you have a new ASP object to work with and might not have
even noticed it was there!
The ASPError Object allows you to get detailed error
information and provides a handy way to get everything you need
to know about an error caused by ASP code.
Now how can we pull this sweet trick off? Well, when an error occurs in
code, like this:
<%
err.raise 43254, "myclass object v1.0", "please enter a valid path."
%>
and no error handling is found to handle the error,
a couple of things happen. First, the server generates an http code of 500
with a sub-type of 100. This indicates that an ASP error has occurred. At this
time, ASP fills the properties of the ASPError Object with information about
the error and transfers control to the 500-100.asp file. This file is built
into and installed with IIS but you can point that particular error to any file
on the server using the IIS console.
I'm getting ahead of myself. First you need to create your error handler page.
Often times the best error handler page is a page that pretends that
everything's kosher even though something fatal happened during code processing.
In other words, a user hits a page and it craps out for whatever reason... Normally
the user gets an error message with debugging info. Sloppy. What is the average
user going to do with a line number? Instead, print a cool "temporarily updating
content or database" message. That way, it looks like we meant for the site to go
down just then...
Of course, we need that debugging info because if it's not grabbed then, it's
lost forever (of course it will always be in the event logs though). So behind the
iron curtain of a flat out lie ("site temporarily down because we're updating
content" message), we can do something useful like save the debugging info into
a log file. The log file can be as specific as you want it to be as the
ASPError object exposes some sweet properties.
Just like any other ASP page, you can do whatever you want in your error handler
page but the most important thing will be interacting with the ASPError object. Here's how it
works. When ASP transfers control to whatever file is specified to handle the 500-100 error
(which is going to be your new custom error handler page), it's like the current
error has gone away. The 500 error generated before to call this page is gone so
you need to put it back. This step is mandatory and must be the first thing that
any error handler page meant to handle 500-100 errors does. It looks like this:
<% @ language="VBScript" %>
<%
Option Explicit
With Response
.Buffer = True
.Clear
.Status = "500 Internal Server Error"
.ContentType = "text/html"
.Expires = 0
End With
%>
As you can see above, you must set the http status to a code of 500 as well as set the
content-type header to text/html. You don't have to enable the response buffer but
it will come in handy for the next part... and it's usually good to force the
expiration header to be sent as well so that the page isn't cached.
Now we've put the 500 error back in (that's just by design. On this page, you must
specify the http status code or it will be like an error never happened). We'll raise
an error in the IIS Event Logs of 500 but the user won't have any idea of what just
happened.
The second step is to call a special method of the Server object. This method must be
called before anything is written to the browser - that's why the response buffer is
turned on above. Calling the GetLastError method of the server object provides you
with an instance of the ASPError object with it's read-only properties set and ready
to go.
Set objASPError = Server.GetLastError
After this line, you go hog-wild, doing whatever you want with the info about the
error... To serve as a guide, here's a listing of all the properties and what
they return:
<%
objASPError.ASPCode 'Returns the error code generated by IIS.
objASPError.Number 'Property returns the standard COM error code.
objASPError.Source 'Returns the actual source code, when available,
'of the line that caused the error
objASPError.Category 'Indicates if the source of the error was internal
'to ASP, the scripting language, or an object
objASPError.File 'Indicates the name of the .asp file that was being
'processed when the error occurred
objASPError.Line 'Indicates the line within the .asp file that generated
'the error
objASPError.Column 'Indicates the column position within the .asp file
'that generated the error
objASPError.Description 'Returns a short description of the error
objASPError.ASPDescription 'Returns a more detailed description of the error
'if it is an ASP-related error
%>
These are all read-only properties that return variants. Most can be tested against an empty
string "" to see if they contain any useful data. For example:
<%
Dim tmp
tmp = objASPError.ASPDescription
If tmp <> "" Then Response.Write(tmp)
%>
Now to take all that data above and use it for something useful. Here's a simple custom error
page that writes to a log file. It has two procedures. The first, LogASPError, logs the error
information to a log file. The second, GetError, gathers error data from the ASPError object.
Together, these two functions gather and record any ASP error that occurs in your pages.
<% @ language="VBScript" %>
<%
option explicit
With response
.buffer = true
.clear
' set the proper http status code (mandatory)
.status = "500 internal server error"
.contenttype = "text/html"
.expires = 0
end With
sub logasperror(byval code, byval num, byval src, byval cat, byval file, _
byval line, byval column, byval desc, byval adesc)
' error handling is important because any errors
' that occur on our new 500-100 custom error
' page will be fatal and cause the old, ugly
' error messages to appear... The chance for error
' really only lies with the FileSystemObject...
' so I start handling errors here.
dim olog, ofile
on error resume next
set olog = createobject("scripting.filesystemobject")
set ofile = olog.opentextfile(server.mappath("/asperrorlog.log"), 8, true)
' write the error code
if code <> "" then ofile.write(code & vbtab)
' using hex on the number property gives it
' that incomprehensible feel that has always
' been associated with ASP Error numbers...
if num <> "" then ofile.write("0x" & hex(num) & vbtab)
' source is the line of source code that made the error
if src <> "" then ofile.write(src & vbtab)
' tells you what threw the error - could be IIS, VBScript or whatever...
if cat <> "" then ofile.write(cat & vbtab)
' file is the actual page that crapped out on your site...
if file <> "" then ofile.write(file & vbtab)
' line is the line that failed.
if line <> "" then ofile.write(line & vbtab)
' column is the character that failed
if column <> "" then ofile.write(column & vbtab)
' returns a description of why the code failed, for
' example: variable not defined 'i'
if desc <> "" then ofile.write(desc & vbtab)
' if the error is an asp error, this property has more info for ya.
if adesc <> "" then ofile.write(adesc & vbtab)
ofile.write(vbcrlf)
ofile.close
set ofile = nothing
set olog = nothing
on error goto 0
end sub
sub geterror
' gather details about the error from the ASPError object
dim objasperror, code, num, src, cat
dim line, column, desc, adesc, file
' get the last error that occurred!
set objasperror = server.getlasterror
' go through the properties and get whatever you need...
With objasperror
code = .aspcode
num = .number
src = .source
cat = .category
file = .file
line = .line
column = .column
desc = .description
adesc = .aspdescription
end With
' free ASPError object
set objasperror = nothing
' prepare to log error stuff to a file
logasperror code, num, src, cat, file, line, column, desc, adesc
end sub
%>
<HTML>
<BODY>
<H3>Temporarily unavailable!</H3>
Sorry, we're temporarily updating this page! Please check back soon,
after we have finished updating our content.
<%
' get the error that brought us to this page in the first place
geterror
%>
</BODY>
</HTML>
Okay. After you've written your new error handler page using the
ASPError object, you need to install it. In otherwords, you need
to tell IIS that it won't be using the default 500-100.asp file, it
will use yours instead.
Here's how to do it:
- Put your new error page somewhere on your web site. Make sure
you save it as an ASP file.
- Open Internet Services Manager
-
right click on your HTTP service and select properties
-
once in the properties screen, click on the "Custom Errors" tab. Then scroll
down to the bottom
of the list until you get to the 500;100 error. Select it and click the Edit
Properties button.
-
Here is where you declare the path to your new custom error page.
First, select a URL message type and then type in the virtual path
to your new error handler page.
-
Now would be a good time to type
IISRESET into the command prompt
to reset your site, ensuring that the change takes effect immediately.
|
Now when ASP encounters an error that's not handled in your web site,
it will transfer control to your new error page and the ASPError info
will be gathered and logged. Since ASP will do a server.transfer to go to
your new ASP page, no one will know the path to your error page as their
address bar will still be on the page that failed.
Voila, you just learned how to use the seventh built-in ASP object to
handle all your error-logging. There's basically no restrictions here
at all. Instead of logging the error, you could email it or save it into
a database or just print it to the screen. At least now you have some options
to disguise ugly error messages.
Download
http://downloads.aspemporium.com/aspError.zip