JScript ASP Library

Audience Level

Beginner and above.

Introduction

A bumper collection of Classic ASP (JScript) functions for use by web programmers. Functions are grouped together by functionality where convenient and are copy-pastable or downloadable from links under the source displays.

The Library

Six years of JScript ASP programming means that I have naturally collected functions that have saved not only programming time and effort but code around common gotchas. The scripts vary from very simple to more involved, but they're listed below because they are so useful to me time and time again when programming JScript ASP. This is only a partial list, there are at least as many again that could be here but they're much more involved and need more careful documentation so they're not listed here for the timebeing.

Table of Content


Request.Form(), Request.QueryString() & Request.ServerVariables() Shortcuts

This first set falls into the “simple” category and provide shortcuts to the Form, QueryString and ServerVariables collections. However, they do make for nicer ways to dereference these collections because they return consistent results and always de-reference the first “Item(1)” for the requested “Key”.

The “RQ” and “RF” functions always return strings, including null strings “""” when there's either no data or no such querystring “Key”. The “RQI” and “RFI” functions always either return a trimmed and parsed Integer number or null — the latter being returned instead of “NaN” because “NaN” is too much hassle to work with reliably. These two also protect against acquiring “QNaN” error values from attempting to convert nulls to Integer numbers. “RS” works the same way as “RQ” but using the “ServerVariables” collection.

/*
Function: RF()
History:
20050131 1549GMT    v1      Andrew Urquhart     Comment added
*/

function RF(strKey) {
    var objKey = Request.Form(strKey);
    return (objKey.Count ? objKey.Item(1) : "");
}


/*
Function: RQ()
History:
20050131 1551GMT    v1      Andrew Urquhart     Comment added
*/

function RQ(strKey) {
    var objKey = Request.QueryString(strKey);
    return (objKey.Count ? objKey.Item(1) : "");
}


/*
Function: RFI()
Description: Like RF() but returns integers. Note that NaN => null;
History:
20060608 0920BST    v1      Andrew Urquhart     Created
*/

function RFI(strKey) {
    var objKey = Request.Form(strKey);
    var intVal  = objKey.Count ? parseInt(objKey.Item(1).trim(), 10) : NaN;
    return (isNaN(intVal) ? null : intVal);
}


/*
Function: RQI()
Description: Like RQ() but returns integers. Note that NaN => null;
History:
20060608 0920BST    v1      Andrew Urquhart     Created
*/

function RQI(strKey) {
    var objKey = Request.QueryString(strKey);
    var intVal  = objKey.Count ? parseInt(objKey.Item(1).trim(), 10) : NaN;
    return (isNaN(intVal) ? null : intVal);
}


/*
Function: RS()
History:
20060321 1446GMT    v1      Andrew Urquhart     Created
*/

function RS(strKey) {
    var objKey = Request.ServerVariables(strKey);
    return (objKey.Count ? objKey.Item(1) : "");
}

Download the JScript ASP source directly.


Server.HTMLEncode() & Server.URLEncode() Shortcuts

More shortcuts to built-in functions, this time shortcuts to the two functions that are the last step in protecting against XSS exploits. The shortcuts perform the useful workaround for the errors that occur when attempting to encode “null” or “undefined” values. Normally these two data values will cause the built-in functions to throw exceptions, but these shortcuts encode these values to harmless null strings, which is usually what you intended to do and just makes for one less thing to worry about.

/*
Function: hEnc()
Description: Sugar wrapper for Server.HTMLEncode to cope with nulls and undefined values
Returns: String
History:
20060330 1447BST    v1      Andrew Urquhart     Created
*/

function hEnc(strRawHTML) {
    return (strRawHTML === null || strRawHTML === undefined ? "" : Server.HTMLEncode(strRawHTML));
}


/*
Function: uEnc()
Description: Sugar wrapper for Server.URLEncode to cope with nulls and undefined values
Returns: String
History:
20060413 1053BST    v1      Andrew Urquhart     Created
*/

function uEnc(strData) {
    return (strData === null || strData === undefined || (typeof strData == "number" && isNaN(strData)) ? "" : Server.URLEncode(strData));
}

Download the JScript ASP source directly.


appendToQuerystring()

When building up a URI with a querystring you often have to append a new key-value pairs to the querystring. However, you don't always know if the URI already contains a querystring and so don't know whether you need to prepend with a question mark or an ampersand before you add your new key-value pair or pairs. This function works that out for you and returns the correctly formated URI by inserting a question mark or ampersand before your fragment. You just give it the current URI and then the key-value pair(s) you want to add to it as part of the querystring, e.g. “key=value&key=value”.

/*
Function: appendToQuerystring()
Description: Adds a combination of querystring 'key=value&key=value' to a URI and correctly inserts linking '?' or '&' as required
Returns: String (URI)
History:
20060815 1542BST    v1      Andrew Urquhart     Created
*/

function appendToQuerystring(strUri, strQSFragment) {
    if (!strUri) {
        throw new Error(1, "Required parameter \"strUri\" was not defined");
    }
    if (!strQSFragment) {
        throw new Error(2, "Required parameter \"strQSFragment\" was not defined");
    }

    if (strUri.indexOf("?") > 0) {
        if (strUri.charAt(strUri.length - 1) != "?") {
            strUri += "&";
        }
    }
    else {
        strUri += "?"
    }

    return strUri + strQSFragment;
}

Download the JScript ASP source directly.


isNumber() & isBoolean()

isNumber()” I find incredibly useful because “NaN” is such a slippery thing to deal with since it gets past “typeof” checking, so this function is a simple wrapper to test both the “typeof” and the “NaN” state of a number — whilst simple it almost entirely removes those “NaN” hassles. “isBoolean()” is similar but is a straight “typeof” check. Of course there could be others such as “isString()”, “isNull()”, “isObject()” and “isFunction()” etc. but on the whole I don't tend to need them so they are omitted here and left as an exercise for the reader!

/*
Function: isNumber()
Description:
Returns:
History:
20060608 0928BST    v1      Andrew Urquhart     Created
*/

function isNumber(varData) {
    if (typeof varData !== "number" || isNaN(varData)) {
        return false;
    }
    return true;
}


/*
Function: isBoolean()
Description:
Returns:
History:
20060608 0928BST    v1      Andrew Urquhart     Created
*/

function isBoolean(varData) {
    if (typeof varData === "boolean") {
        return true;
    }
    return false;
}

Download the JScript ASP source directly.


objectEnumerate()

objectenumerate” is simple but extremely useful function that overrides the default “toString()” method of all Objects and their derivations (so that's pretty much everything in javascript). It's so useful because when you want to debug an object the built-in “toString()” method that is invoked by implicitly casting to a String will return the following: “[object Object]”, which is not much use to anyone. However, by defining “objectEnumerate()” as described then any objects implicitly (or explicitly) cast to strings will enumerate the properties of the object and return a CSV string of them, which can allow you to determine what the object is and what its state is.

Object.prototype.toString = objectEnumerate;


/*
Function: objectEnumerate()
Description: Overrides the default implicit cast to string function for Objects in order to enumerate their contents in CSV format
Returns: CSV String
History:
20060203 1256GMT    v1      Andrew Urquhart     Created
*/

function objectEnumerate() {
    var a = [];
    for (var e in this) {
        var strType = typeof this[e];
        if (strType != "function") {
            a.push(e + ":" + (strType == "string" ? "\"" : "") + ("" + this[e]).replace(/"/g,"\\\"") + (strType == "string" ? "\"" : ""))
        }
    }
    return "{" + a.join(", ") + "}";
}

Download the JScript ASP source directly.


trim(), capitalise() & prefixPad()

The next three functions are attached as methods to the “String” object and prefixPad() is also attached as a method to the “Number” object. trim is commonly defined so you should have seen it already to remove white-space before and after a string, although not always seen as a “String” method, e.g. “var myCompactVar = myPaddedVar.trim()”. “capitalise()” sets the first letter of a “String” to be a capital letter and leaves the remaining characters in whatever case they were in. The same function invoked as “capitalise(true)” does the same but forces all other characters to become lowercase.

prefixPad()” acts on strings and numbers (converting the latter to a “String”). Without any input parameters the function pads out a string or number to at least two characters long and pads with a "0" character. This is intended mainly for presenting hours, days and seconds in a familiar 2-digit format. Optionally you can specify the character to pad with and how much minimum padding is required. For example you could use it for white-space padding.

String.prototype.trim               = trim;
String.prototype.capitalise         = capitalise;
String.prototype.prefixPad          = prefixPad;
Number.prototype.prefixPad          = prefixPad;


/*
Function: trim()
Description:
Returns:
History:
20050202 2215GMT    v1      Andrew Urquhart     Comment added
*/

function trim() {
    var strInput = String(this);

    if (typeof strInput == "undefined" || strInput == null) {
        return this;
    }

    return strInput.replace(/^\s+|\s+$/g, "");
}


/*
Function: capitalise()
Description:
Returns:
History:
20050131 1552GMT    v1      Andrew Urquhart     Comment added and updated readability
*/

function capitalise(blnForceLowercase) {
    var strInput = String(this);

    if (typeof strInput == "undefined" || strInput == null) {
        return this;
    }

    var objWords = ("" + strInput).split(/\s+/);
    for (var i in objWords) {
        var strWord = objWords[i];
        objWords[i] = strWord.charAt(0).toUpperCase() + (blnForceLowercase ? strWord.substring(1).toLowerCase() : strWord.substring(1));
    }
    return objWords.join(" ");
}


/*
Function: prefixPad()
Description:
Returns:
History:
20050202 2234GMT    v1      Andrew Urquhart     Comment added
*/

function prefixPad(strPadChar, intLength) {
    try {
        if (!strPadChar) {
            var strPadChar = "0";
        }
        if (!intLength) {
            var intLength = 2;
        }

        var strInput = String(this);

        if (typeof strInput == "undefined" || strInput == null) {
            return this;
        }
        for (var i=strInput.length; i<intLength; ++i) {
            strInput = strPadChar + strInput;
        }

        return strInput;
    }
    catch (err) {
        propError(err, arguments);
    }
}

Download the JScript ASP source directly.


ADO Enumerations

enumerateADOErrors()” takes an ADO connection object and returns a formatted report on what, if any, errors were found in the ADO Error collection. “enumerateCommandParameters()” takes an ADO Command object as its argument and returns a formatted report on the parameters being passed across to a stored procedure, including return code and input/output parameter names and values. Both are intended for debugging and automated error reports.

/*
Function: enumerateADOErrors()
Description: Enumerate the ADO connection errors collection
Returns: String
History:
20060209 1011GMT    v1      Andrew Urquhart     Created
*/

function enumerateADOErrors(objAdoConn) {
    try {
        if (!objAdoConn) {
            throw new Error(1, "Required parameter \"objAdoConn\" was not defined");
        }

        var intErrCount = objAdoConn.Errors.Count;

        var arrErrs = [];
        arrErrs.push("ADO CONNECTION ERROR REPORT (" + intErrCount + " ERRORS)");


        if (intErrCount > 0) {
            // Enumerate over all errors in error collection
            for (var objAdoErrorsEnum=new Enumerator(objAdoConn.Errors); !objAdoErrorsEnum.atEnd();objAdoErrorsEnum.moveNext()) {
                var objAdoError = objAdoErrorsEnum.item();
                arrErrs.push("Number: " + objAdoError.Number);

                arrErrs.push("\tSource: "       + objAdoError.Source);
                arrErrs.push("\tDescription: "  + objAdoError.Description);
                arrErrs.push("\tHelpFile: "     + objAdoError.HelpFile);
                arrErrs.push("\tHelpContext: "  + objAdoError.HelpContext);
                arrErrs.push("\tSQLState: "     + objAdoError.SQLState);
                arrErrs.push("\tNativeError: "  + objAdoError.NativeError);
            }
        }
        else {
            arrErrs.push("[No errors found!]");
        }

        return arrErrs.join("\r\n");
    }
    catch (err) {
        propError(err, arguments);
    }
}



/*
Function: enumerateCommandParameters()
Description: Like enumerateADOErrors() but for an ADO Command object
Returns:
History:
20060703 1347BST    v1      Andrew Urquhart     Created
*/

function enumerateCommandParameters(objCmd) {
    try {
        var objO            = [];
        var intMaxKeyLen    = 0;

        objO.push("DEFINED COMMAND OBJECT PARAMETERS\r\n=================================\r\n");

        if (!objCmd) {
            objO.push("[ Invalid Command object ]");
        }
        else if (!objCmd.Parameters) {
            objO.push("[ Command object has no parameters ]");
        }
        else {
            var objParams       = new Enumerator(objCmd.Parameters);

            // Determine width of longest key name
            for (; !objParams.atEnd(); objParams.moveNext()) {
                var intKeyLen = objParams.item().Name.length;
                if (intKeyLen > intMaxKeyLen) {
                    intMaxKeyLen = intKeyLen;
                }
            }


            // Write key: value pairs out
            for (objParams.moveFirst(); !objParams.atEnd(); objParams.moveNext()) {
                var objItem         = objParams.item();
                var strKeyName      = objItem.Name.suffixPad("\u00a0", intMaxKeyLen);
                var strKeyValue     = ("" + objItem.Value).replace(/\n/g, "\\n").replace(/\r/g, "\\r").replace(/\t/g, "\\t");
                objO.push(strKeyName + " : " + strKeyValue);
            }
        }

        return objO.join("\r\n");
    }
    catch (err) {
        propError(err, arguments);
    }
}

Download the JScript ASP source directly.


Database Connections

Simple functions for getting and destroying database connections. “getDbConnection()” returns a valid connection object given an ADO read/write mode (“adModeRead”, “adModeWrite”, “adModeReadWrite”) and a connection string. “getConn()” is a wrapper for “getDbConnection()” using a connection string stored in “Application” space. “killConn()” is a safe way to kill a connection object, especially when it's not known if the connection is active. An additional function “doRollback()” is included for initiating ADO transaction rollbacks whilst silently consuming the native exception that occurs if the transaction has already been rolled back.

/*
Function: getDbConnection()
Description: Gets a database connection object
Returns: ADO Database connection object
History:
20051219 12:13GMT   v1      Andrew Urquhart     Created
*/

function getDbConnection(mode, strConnection) {
    try {
        if (typeof mode != "number") {
            throw new Error(1, "Expected parameter \"mode\" was not a number");
        }
        if (!strConnection) {
            throw new Error(2, "Expected parameter \"strConnection\" was not defined");
        }
        if (mode != adModeRead && mode != adModeWrite && mode != adModeReadWrite) {
            throw new Error(3, "Unknown connection mode \"" + mode + "\" specified");
        }

        var objAdoConn  = new ActiveXObject("ADODB.Connection");
        objAdoConn.Mode = mode;
        objAdoConn.Open(strConnection);

        if (objAdoConn && objAdoConn.State != adStateOpen) {
            throw new Error(4, "Failed to open requested database connection");
        }

        if (objAdoConn.Errors.Count > 0) {
            throw new Error(5, enumerateADOErrors(objAdoConn));
        }

        return objAdoConn;
    }
    catch (err) {
        propError(err, arguments);
    }
}


/*
Function: getConn()
Description: Syntactic sugar for getDbConnection() with the MASTER_ADOCONN_STRING
Returns:
History:
20060413 0950BST    v1      Andrew Urquhart     Created
*/

function getConn(intAdoMode) {
    try {
        return getDbConnection(intAdoMode, Application("MASTER_ADOCONN_STRING"));
    }
    catch (err) {
        propError(err, arguments);
    }
}


/*
Function: killConn()
Description: Terminate an open database connection
Returns: Boolean true or null
History:
20060413 0957BST    v1      Andrew Urquhart     Created
*/

function killConn(adoConn) {
    if (adoConn && adoConn.State != adStateClosed) {
        adoConn.Close();
        return true;
    }
    return null;
}


/*
Function: doRollback()
Description: Transaction rollback on a database connection that doesn't fail if their is no active transaction
Returns:
History:
20060913 1457BST    v1      Andrew Urquhart     Created
*/

function doRollback(objAdoConn) {
    try {
        if (objAdoConn && objAdoConn.State != adStateClosed) {
            objAdoConn.RollbackTrans();
            return true;
        }
        return null;
    }
    catch (err) {
        if (err.number == -2147168242) {
            return false; // No open transactions - i.e. probably already rolled back from further down the chain
        }
        else {
            propError(err, arguments);
        }
    }
}

Download the JScript ASP source directly.


Debugging

saveDebug()” utilises two functions that exist elsewhere: “saveFile()” and “createDirectoryPath()” to write whatever the input argument is to a file whose path is defined by application variable “SAVEDEBUG_FILEPATH”, e.g.: “C:\savedebug\” and is useful for debugging routines where you can't easily dump to the default output. “debug()” just dumps the argument to the browser with a little styling and kills further processing.

/*
Function: saveDebug()
Description: Writes a debugging file to a standard location - useful for processes where it is inconvenient to display debugging information
Returns:
History:
20060324 0908GMT    v1      Andrew Urquhart     Created
*/

function saveDebug(strData) {
    try {
        if (typeof arguments.callee.count != "number") {
            arguments.callee.count = 1;
        }
        else {
            ++arguments.callee.count;
        }

        var strData = "" + strData; // Force to string

        var strAbsoluteFilePath = Application("SAVEDEBUG_FILEPATH");

        // If save path is a folder and not a specific file, add a dynamic filename based on the date
        if ((/\\|\/$/).test(strAbsoluteFilePath)) {
            var objNow = new Date();
            strAbsoluteFilePath += objNow.getUTCFullYear() + (objNow.getUTCMonth()+1).prefixPad() + objNow.getUTCDate().prefixPad() + "_"  + objNow.getUTCHours().prefixPad() + objNow.getUTCMinutes().prefixPad() + objNow.getUTCSeconds().prefixPad() + "." + objNow.getUTCMilliseconds().prefixPad("0", 3) + "_UTC_" + arguments.callee.count + ".txt";
        }

        createDirectoryPath(strAbsoluteFilePath)
        var blnSaved = saveFile(strAbsoluteFilePath, "utf-8", strData, true);
        if (!blnSaved) {
            throw new Error(2, "saveFile(" + strAbsoluteFilePath + ") failed");
        }
    }
    catch (err) {
        propError(err, arguments);
    }
}


/*
Function: debug()
Description:
Returns:
History:
20050131 1554GMT    v1      Andrew Urquhart     Comment added
*/

function debug(txt) {
    Response.Write("<div style=\"color: #ff3333; background-color: #ffffff; font-weight: bold; font-family: monospace;\">Value: &quot;" + hEnc(txt).replace(/\r\n|\r|\n/g, "<br />") + "&quot;</div>");
    Response.End();
}

Download the JScript ASP source directly.


enumerateCollection()

enumerateCollection()” generates a <pre>-like formatted list of the many keys and their many values in a collection. Parameter “blnSupportsMultipleKeys” is “true” for “Request.QueryString”, “Request.Form” and “Request.ServerVariables” collections and “false” for the “Application” collection. Particularly useful for debugging and error notification.

/*
Function: enumerateCollection()
Description:
Returns:
History:
20060503 0124BST    v1      Andrew Urquhart     Created
*/

function enumerateCollection(objCollection, blnSupportsMultipleKeys) {
    try {
        var objO            = [];
        var intMaxKeyLen    = 0;
        if (blnSupportsMultipleKeys == null) {
            var blnSupportsMultipleKeys = true; // default behaviour
        }

        var objColl = new Enumerator(objCollection);

        // Determine width of longest key name
        for (; !objColl.atEnd(); objColl.moveNext()) {
            var intKeyLen = objColl.item().length;
            if (intKeyLen > intMaxKeyLen) {
                intMaxKeyLen = intKeyLen;
            }
        }

        // Write key: value pairs out
        for (objColl.moveFirst(); !objColl.atEnd(); objColl.moveNext()) {
            var strKeyName      = objColl.item();
            var strKeyNameNrm   = ("" + strKeyName).suffixPad("\u00a0", intMaxKeyLen);

            if (blnSupportsMultipleKeys) {
                var intValCount     = objCollection(strKeyName).Count;
                for (var i=1; i<=intValCount; ++i) {
                    var strKeyValue = objCollection(strKeyName).Item(i).replace(/\n/g, "\\n").replace(/\r/g, "\\r").replace(/\t/g, "\\t");

                    objO.push(strKeyNameNrm + " : " + strKeyValue);
                }
            }
            else {
                var strKeyValue = ("" + objCollection(strKeyName)).replace(/\n/g, "\\n").replace(/\r/g, "\\r").replace(/\t/g, "\\t");
                objO.push(strKeyNameNrm + " : " + strKeyValue);
            }
        }
        return objO.join("\r\n");
    }
    catch (err) {
        propError(err, arguments);
    }
}

Download the JScript ASP source directly.


sendEmail() & emailReport()

sendEmail()” is a wrapper for invoking “CDO.Message” using mail-server settings held in “Application” space. “emailReport()” is a wrapper for “sendEmail()” for sending formatted application reports including application state — again most useful for debugging and production-level behind-the-scenes error handling. “wrapText()” is defined elsewhere.

/*
Function: sendEmail()
Description: Sends an email
Returns: Exception if critical error occurs, true if no errors
History:
20030928 1459BST    v1      Andrew Urquhart     Created
20041212 0123GMT    v1.1    "                   Massaged to work with CDO.Message
*/

function sendEmail(strToAddresses, strFromAddresses, strSubject, strMessageBody, strReplyToAddresses) {
    try {
        // CACHE DATA
        strToAddresses      = strToAddresses.trim();
        strFromAddresses    = strFromAddresses.trim();
        strSubject          = strSubject.trim();
        strMessageBody      = strMessageBody.trim();
        strReplyToAddresses = strReplyToAddresses   ? strReplyToAddresses.trim() : "";

        // CHECK PARAMETERS
        if (!strToAddresses) {
            throw new Error(1, "Expected parameter \"strToAddresses\" was not defined");
        }
        if (!strFromAddresses) {
            throw new Error(2, "Expected parameter \"strFromAddresses\" was not defined");
        }
        if (!strSubject) {
            throw new Error(3, "Expected parameter \"strSubject\" was not defined");
        }
        if (!strMessageBody) {
            throw new Error(4, "Expected parameter \"strMessageBody\" was not defined");
        }


        // PREPARE DATA
        strMessageBody = wrapText(strMessageBody, 72);


        var strCDOSchemaConfig = "http://schemas.microsoft.com/cdo/configuration/";
        var objCDOConfig = Server.CreateObject("CDO.Configuration");
        objCDOConfig.Fields.Item(strCDOSchemaConfig + "sendusing")              = Application("SMTP_SENDUSING");
        objCDOConfig.Fields.Item(strCDOSchemaConfig + "smtpserverport")         = Application("SMTP_SERVERPORT");
        objCDOConfig.Fields.Item(strCDOSchemaConfig + "smtpconnectiontimeout")  = 30; // seconds
        objCDOConfig.Fields.Item(strCDOSchemaConfig + "smtpauthenticate")       = Application("SMTP_AUTHENTICATE");
        objCDOConfig.Fields.Item(strCDOSchemaConfig + "smtpserver")             = Application("SMTP_SERVERNAME");
        if (Application("SMTP_USERNAME").length > 0) {
            objCDOConfig.Fields.Item(strCDOSchemaConfig + "sendusername")       = Application("SMTP_USERNAME");
        }
        if (Application("SMTP_USERPASS").length > 0) {
            objCDOConfig.Fields.Item(strCDOSchemaConfig + "sendpassword")       = Application("SMTP_USERPASS");
        }
       objCDOConfig.Fields.Update();

        var objCDOMsg                   = Server.CreateObject("CDO.Message");
        objCDOMsg.Configuration         = objCDOConfig;
        objCDOMsg.To                    = strToAddresses;
        objCDOMsg.From                  = strFromAddresses;
        objCDOMsg.Subject               = strSubject;
        if (strReplyToAddresses) {
            objCDOMsg.ReplyTo           = strReplyToAddresses;
        }
        objCDOMsg.BodyPart.CharSet      = "UTF-8";
        objCDOMsg.TextBody              = strMessageBody;
        objCDOMsg.TextBodyPart.CharSet  = "UTF-8";
        objCDOMsg.Send();

        // DIDN'T FAIL, ASSUME SENT!
        return true;
    }
    catch (err) {
        propError(err, arguments);
    }
}



var EMAIL_TYPE_INFO     = 1;
var EMAIL_TYPE_WARNING  = 2;
var EMAIL_TYPE_ERROR    = 3;

/*
Function: emailReport()
Description: Send an error report email
Returns: n/a
History:
20060111 1108GMT    v1      Andrew Urquhart     Created
*/

function emailReport(message, intMessageType) {
    try {
        if (!message) {
            throw new Error(1, "Required parameter \"message\" was not defined");
        }

        var strMessageType = "";
        switch (intMessageType) {
            case EMAIL_TYPE_INFO    : strMessageType = "INFORMATION"; break;
            case EMAIL_TYPE_WARNING : strMessageType = "WARNING"; break;
            case EMAIL_TYPE_ERROR   : strMessageType = "ERROR"; break;
            default                 : strMessageType = "UNKNOWN";
        }

        var arrMsg = [];
        arrMsg.push("$APPLICATION REPORT$");
        arrMsg.push("====================");
        arrMsg.push("REPORT TYPE:         " + strMessageType);
        arrMsg.push("CURRENT DATE:        " + (new Date()).toUTCString());
        arrMsg.push("============================");
        arrMsg.push(message);
        arrMsg.push("===============================");
        arrMsg.push("$APPLICATION STATE INFORMATION$");
        arrMsg.push("===============================");

        try {
            arrMsg.push(enumerateCollection(Application.Contents, false));
            arrMsg.push(enumerateCollection(Request.QueryString, true));
            if (RQ("REQUEST_METHOD").toUpperCase() == "POST") {
                arrMsg.push(enumerateCollection(Request.Form, true));
            }
            arrMsg.push(enumerateCollection(Request.ServerVariables, true));
        }
        catch (err) {
            arrMsg.push("[emailReport() failed to list all state information: " + err.description + "]");
        }

        var strSubject = "$" + strMessageType + ": Report";
        sendEmail(Application("ADMIN_RECIPIENTEMAIL"), Application("SMTP_USERNAME"), strSubject, arrMsg.join("\r\n"), null);
    }
    catch (err) {
        propError(err, arguments);
    }
}

Download the JScript ASP source directly.


propError()

propError()” is a function that you have seen in some of the above functions. It is designed to be invoked from within the “catch” block of a “try”-“catch(err)”-“finally” statement. Invoking “propError(err, arguments)” in this way examines the error object and records the parent functions name and parameter arguments as a new error description and then throws on up the error with the originating error number. If the parent function doesn't handle (consume) the exception that is thrown and also has its own “propError()” invocation from its “catch” block then a cascade can occur that builds up a complete or partial call-tree and its run-time state. If you catch this exception chain before it is passed out of the script engine and on up to generate an ASP HTTP 500 error message, then it is really useful for error reporting in production systems. It tells you what the failure was, where it occurred and how it occurred in lots of gory detail, but it's like having your own run-time debugger always available in a production environment. Consider using it with “emailReport()” or “saveDebug()”.

/*
Function: propError()
Description: Propagate an Error up the call chain, adding function name and parameter information about each stage in the chain
Returns:
History:
20060302 1145GMT    v1      Andrew Urquhart     Created
*/

function propError(errError, argsCaller) {
    var arrTree     = [];
    var blnCascade  = false;
    try {
        if (typeof arguments.callee.count != "number") {
            arguments.callee.count = 1;
        }
        else {
            ++arguments.callee.count;
        }


        arrTree.push("<dl><dt>LEVEL</dt><dd>" + arguments.callee.count + "</dd>");


        // GET FUNCTION NAME AND VALUE OF FUNCTION PARAMETERS
        if (argsCaller) {
            var arrArgs = [];
            for (var i=0, j=argsCaller.length; i<j; ++i) {
                var strDelimiter1, strDelimiter2;
                switch (typeof argsCaller[i]) {
                    case "string" : strDelimiter1 = strDelimiter2 = "\""; break;
                    case "object" : {
                        if (argsCaller[i] instanceof Array) {
                            strDelimiter1 = "["; strDelimiter2 = "]"; break;
                        }
                        else {
                            strDelimiter1 = "{"; strDelimiter2 = "}"; break;
                        }
                    }
                    default : strDelimiter1 = strDelimiter2 = ""; break;
                }
                arrArgs.push(strDelimiter1 + argsCaller[i] + strDelimiter2);
            }


            var strFunctionName = "[ No function name ]";
            if (argsCaller.callee.toString) {
                (/function\s+([\w\d]+)\s*\(([^\)]*)/i).test(argsCaller.callee.toString());
                strFunctionName = RegExp.$1;
            }

            arrTree.push("<dt>FUNCTION</span><dd>" + strFunctionName + "(" + hEnc(arrArgs.join(", ")) + ")</dd>");
        }
        else {
            arrTree.push("<dt>FUNCTION</dt><dd>[ Top Level ]</dd>");
        }

        arrTree.push("<dt>NUMBER</dt><dd>" + errError.number + "</dd>");
        arrTree.push("<dt>MESSAGE</dt><dd>" + errError.description + "</dd>");
        arrTree.push("</dl>");

        blnCascade = true;
    }
    catch (err) {
        throw new Error(err.number, "propError failed with parameters errError=\"" + errError + "\", argsCaller=\"" + argsCaller + "\". Message:\r\n" + err.description);
    }

    // Propagate the error up the call-tree
    if (blnCascade) {
        throw new Error(errError.number, arrTree.join("\r\n"));
    }
}

Download the JScript ASP source directly.

Advertisement

Feedback

Voting Panel
Is this useful?
or
Did you find any bugs?
or
Rate this script: (0=poor, 5=very good)
Answers are anonymous, only the combined totals are stored. Uses cookies.