[thelist] ASP Error Handling

David.Cantrell at Gunter.AF.mil David.Cantrell at Gunter.AF.mil
Fri Dec 27 09:34:00 CST 2002


>So - I've posted what I have got at the moment at the bottom of this post.
>The only problem is that it's not very generic, and a bit ugly.  I realise
>this is my first attempt, but I was wondering if anyone can see anything
>wrong with the code, help me improve the code or point me on my way to
>making a kill error handling class or anything inbetween.

Not really, though just make sure you understand how ASP handles errors.
Whenever an error is encountered it populates the ASPError object, available
through Server.GetLastError(). Not sure if you had that in there, but I
didn't see it.

You can use a class like this to catch errors provided you do a On Error
Resume Next and On Error Goto 0 block whenever you want to trap errors. I
wouldn't do a global On Error Resume Next, just switch it on whenever I
wanted to trap a specific error. Plain-jane ASP with VBScript isn't a very
nice development environment in that it doesn't support true exceptions and
exception handlers, etc. So error-handling with VBScript is always a bit of
a kludge anyway. And I speak from experience. :)

15Seconds has a great article which automatically e-mails you when an error
occurs, logs the info to a database, and provides a reference number to the
customer so they can refer back to you with it. I was going to implement on
my site, but now I'm moving to a .NET shop in six weeks and I'm in the midst
of re-deploying our site using a custom framework so I may or may not,
haven't yet decided. :)

	http://www.15seconds.com/issue/020821.htm

I've just resorted to letting the 500-100 error handler page take care of it
for me. I've tried tinkering with and having a good error-handling 500-100
that displays a friendly error message, but the problem is if it uses ASP
code at all you are SOL because once you run into an ASP error that causes
you to go to the 500-100 the engine has effectively shut down on you and the
fancy ASP code doesn't run. :(

Also, just a picky point I have about your class design: I wouldn't name any
public properties or methods with Hungarian notation, i.e. eh_bLogErrors. I
figure the "eh" stands for "Error Handler", but that will be semantically
obvious from your instantiated variable (assuming you do something like "Set
ErrorHandler = New CError") so it's superfluous really. Also, I would throw
out the "b" as well and just name it LogErrors. In the method docs specify
what it can and cannot accept. You'll notice I did this in my code. VBScript
can't do real Design By Contract but we can at least document the contract
we are creating with the caller.

Anyways, I'm babbling incoherently at this point. My point basically is, I
as the caller couldn't care less about the underlying infrastructure of your
class, I just need to be able to find in the docs that LogErrors expects a
single parameter of boolean type, and that's it. Everything else is just
cruft. :)

Also a tip from someone who's written a LOT of VBScript classes for ASP: All
of my classes have a standard name "ClassNameObject", e.g. your "CError"
would become "ErrorHandlerObject". This means I can do this in my code:

	dim ErrorHandler : Set ErrorHandler = New ErrorHandlerObject
	ErrorHandler.LogErrors = true

Much clearer to read, I think. But that's just my 2 cents worth, take it
with a grain of salt, yadda yadda yadda... :)

Still in the interests of sharing, here's a class and it's associated XSL
that I used in our previous architecture. It didn't work 100% perfectly, but
it worked okay for what I was doing. It also was written almost two years
ago, only slightly modified since then, so it's old code and not the way I
would do things now. As I've said, I've decided to fall back on using the
500-100 error handler page instead of custom classes, because the ASP
framework just doesn't work the way you/we want it to. Sad, but true.

HTH,
-dave

PS I know this class mentions a class called XmlUtils -- in the new
framework I'm using it is now XmlUtilsObject, so I do follow my own advice!
;)

=== BEGIN ERROR CLASS ===

<%
Class ErrorHandler
'Generic error handler class
'Allows caller to:
'   * Throw an error automatically if the Err object is populated
'   * Throw an error using the Err object
'   * Throw a custom error by providing source and description
'   * Throw an XML ParseError by providing an XmlDom ParseError object
'All errors are handled by an error handler XSL stylesheet which can be
customized
'
'ASSUMES: XmlUtils class is included in the same script which references
this class



'---------------------------------------------------------------------------
------------------------------------------
' Public Properties
'---------------------------------------------------------------------------
------------------------------------------
Public Property Let Handler( s )
'About:     Sets the path to the XSL file which will display the error.
'Accepts:   s. String. Required. Path to the XSL file. Default is
"/il/lib/class/error-handler.xsl"
  ERROR_HANDLER_XSL = s
End Property

'---------------------------------------------------------------------------
------------------------------------------
Public Property Get Handler()
'About:     Returns the path to the XSL file used to display the error.
'Returns:   String.
  Handler = ERROR_HANDLER_XSL
End Property



'---------------------------------------------------------------------------
------------------------------------------
' Public Methods
'---------------------------------------------------------------------------
------------------------------------------
Public Sub CheckForError
'About:     Throws an error if the Err object is populated.
'Accepts:   Nothing.
'Returns:   Nothing.
'Assumes:   Option Explicit is turned on -- otherwise the error would be
raised by VBScript before reaching this method
'Ensures:   ThrowError is called
  If Err.Number <> 0 then ThrowError
End Sub

'---------------------------------------------------------------------------
------------------------------------------
Public Sub ThrowError
'About:     Displays the error information from the Err object.
'Accepts:   Nothing.
'Returns:   Nothing.
'Assumes:   Err object has already been populated.
'Ensures:   XmlDomDocument is populated and passes the information through
the stylesheet for display.
  dim loXml  : Set loXml  = Server.CreateObject( "Msxml2.DomDocument.3.0" )
  dim loRoot : Set loRoot = loXml.CreateElement( "error" )
  Set loXml.DocumentElement = loRoot

  loRoot.SetAttribute "type", "vbscript"
  loRoot.SetAttribute "src", Err.Source
  loRoot.SetAttribute "num", Err.Number

  dim loText : Set loText = loXml.CreateElement( "text" )
  loText.text = Err.Description
  loRoot.AppendChild loText
  Set loText = Nothing

  dim loXmlUtils : Set loXmlUtils = New XmlUtils
  response.write loXmlUtils.TransformXml( loXml, ERROR_HANDLER_XSL )
  response.end

  Set loXmlUtils = Nothing
  Set loRoot     = Nothing
  Set loXml      = Nothing
End Sub

'---------------------------------------------------------------------------
------------------------------------------
Public Sub ThrowCustomError( src, text )
'About:     Displays a "custom" error message.
'Accepts:   src. String. Required. The source of the error, e.g. script
name, line number, etc.
'Accepts:   text. String. A description of the error which has occured.
'Assumes:   Nothing.
'Ensures:   src and text are placed into the XmlDomDocument and passed
through the stylesheet for display.
  dim loXml   : Set loXml   = Server.CreateObject( "Msxml2.DomDocument.3.0"
)
  dim loRoot  : Set loRoot  = loXml.CreateElement( "error" )
  Set loXml.DocumentElement = loRoot

  loRoot.SetAttribute "type", "custom"
  loRoot.SetAttribute "src", src

  dim loText : Set loText = loXml.CreateElement( "text" )
  loText.text = text
  loRoot.AppendChild loText

  dim loXmlUtils : Set loXmlUtils = New XmlUtils
  response.write loXmlUtils.TransformXml( loXml, ERROR_HANDLER_XSL )
  response.end

  Set loXmlUtils = Nothing
  Set loText  = Nothing
  Set loRoot  = Nothing
  Set loXml   = Nothing
End Sub

'---------------------------------------------------------------------------
------------------------------------------
Public Sub ThrowXmlError( oParseError )
'About:     Displays the error information contained in the XmlDom
ParseError object.
'Accepts:   oParseError. XmlDomDocument->ParseError. Required. A valid
XmlDomDocument.ParseError object.
'Returns:   Nothing.
'Assumes:   oParseError is populated with error information.
'Ensures:   Populated error XmlDomDocument is passed through a stylesheet
for display.
  dim loXml   : Set loXml   = Server.CreateObject( "Msxml2.DomDocument.3.0"
)
  dim loRoot  : Set loRoot  = loXml.CreateElement( "error" )
  Set loXml.DocumentElement = loRoot

  loRoot.SetAttribute "type", "xml"
  loRoot.SetAttribute "num", oParseError.ErrorCode
  loRoot.SetAttribute "src", oParseError.SrcText
  loRoot.SetAttribute "line", oParseError.Line
  loRoot.SetAttribute "linepos", oParseError.LinePos
  loRoot.SetAttribute "filepos", oParseError.FilePos

  dim loText : Set loText = loXml.CreateElement( "text" )
  loText.text = oParseError.Reason
  loRoot.AppendChild loText

  dim loXmlUtils : Set loXmlUtils = New XmlUtils
  response.write loXmlUtils.TransformXml( loXml, ERROR_HANDLER_XSL )
  response.end

  Set loXmlUtils = Nothing
  Set loText  = Nothing
  Set loRoot  = Nothing
  Set loXml   = Nothing
End Sub



'---------------------------------------------------------------------------
------------------------------------------
' Start Up / Tear Down
'---------------------------------------------------------------------------
------------------------------------------
Private Sub Class_Initialize
  ERROR_HANDLER_XSL = "/il/lib/class/error-handler.xsl"
End Sub



'---------------------------------------------------------------------------
------------------------------------------
' Private Properties
'---------------------------------------------------------------------------
------------------------------------------
dim ERROR_HANDLER_XSL



End Class
%>

=== END ERROR CLASS ===

And here's the stylesheet that was used with it:

=== BEGIN STYLESHEET ===

<?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
  <xsl:output method="html"/>
  <xsl:template match="/">

    <style type="text/css">
      table.error
      {
        width: 50%;
        border: solid #cccccc 2;
      }

      table.error tr th
      {
        font-family: Tahoma;
        font-size: .75em;
        font-weight: bold;
        text-align: left;
        width: 25%;
        border: solid #cccccc 1;
        padding: .25em .5em;
      }

      table.error tr td
      {
        font-family: Tahoma;
        font-size: .75em;
        text-align: left;
        border: solid #cccccc 1;
        padding: .25em .5em;
      }
    </style>

    <h1>Error</h1>

    <h3>
      An error was encountered while processing your request. Please contact
the site administrators if this problem continues. Detailed information
follows.
    </h3>

    <table class="error" cellpadding="0" cellspacing="0">
      <xsl:apply-templates />
    </table>
  </xsl:template>

  <xsl:template match="error">
    <xsl:apply-templates select="@type"/>
  </xsl:template>

  <xsl:template match="@type">
    <tr>
      <th>Error Type:</th>
      <td valign="top">
        <xsl:choose>

          <xsl:when test=".='vbscript'">
            VBScript error
            <xsl:apply-templates select="../@num"/>
            <xsl:apply-templates select="../@src"/>
            <xsl:apply-templates select="../text"/>
          </xsl:when>

          <xsl:when test=".='custom'">
            Custom error
            <xsl:apply-templates select="../@src"/>
            <xsl:apply-templates select="../text"/>
          </xsl:when>

          <xsl:when test=".='xml'">
            XML error
            <xsl:apply-templates select="@num"/>
            <xsl:apply-templates select="@src"/>
            <xsl:apply-templates select="@line"/>
            <xsl:apply-templates select="@linepos"/>
            <xsl:apply-templates select="@filepos"/>
            <xsl:apply-templates select="text"/>
          </xsl:when>

        </xsl:choose>
      </td>
    </tr>
  </xsl:template>

  <xsl:template match="@num">
    <tr>
      <th >Error Number:</th>
      <td  valign="top">
        <xsl:value-of select="."/>
      </td>
    </tr>
  </xsl:template>

  <xsl:template match="@src">
    <tr>
      <th >Error Source:</th>
      <td  valign="top">
        <xsl:value-of select="."/>
      </td>
    </tr>
  </xsl:template>

  <xsl:template match="@line">
    <tr>
      <th >Line:</th>
      <td  valign="top">
        <xsl:value-of select="."/>, position <xsl:value-of
select="../@linepos"/> (file position <xsl:value-of select="../@filepos"/>)
      </td>
    </tr>
  </xsl:template>

  <xsl:template match="text">
    <tr>
      <th >Description:</th>
      <td  valign="top">
        <xsl:value-of select="."/>
      </td>
    </tr>
  </xsl:template>

</xsl:stylesheet>

=== END STYLESHEET ===



More information about the thelist mailing list