A348 Error Handling |
Modified: |
Studies analyzing the cause of downtime to online systems found that over 50% of the episodes were due to human operators, not programming errors or user errors. Even well designed and tested systems will fail, as software designers and implementers we should handle failures as gracefully as possible, minimizing the consequences, and providing the user with information that a failure occurred and their options.
Designers of Web-based systems practice in a dangerous environment where their systems are exposed to naive users and professional attacks.
There are several points to consider about system faults:
Most modern languages handle detected failures generally as exceptions where an exception is some out of the ordinary condition that results in the execution of code reserved for dealing with the exceptional condition. Many languages implement exception handling with the try-catch-finally statement discussed below.
Portions of the following description was extracted from the Microsoft Visual Studio Help
- tryStatements
- Required. Statements where an error can occur.
- exception
- Required. Any variable name. The initial value of exception is the value of the thrown error.
- catchStatements
- Optional. Statements to handle errors occurring in the associated tryStatements.
- finallyStatements
- Optional. Statements that are unconditionally executed after all other error processing has occurred.
The try...catch…finally statement provides a way to handle some or all of the possible errors that may occur in a given block of code, while still running code. If errors occur that the programmer has not handled, JScript simply provides its normal error message to a user, as if there was no error handling.
- try contain code where an exception may be thrown. If an exception is thrown while executing in the try, program control is passed immediately to catch.
- catch contains the code to handle any exception thrown, if no error occurs, catch is never executed.
- finally contains code that is always executed after the try or catch is finished.
- throw raises an exception, within a try, program execution transfers to the matching catch.
If the error cannot be handled in the catch associated with the try where the error occurred, use the throw statement to propagate, or rethrow, the error to a higher-level error handler.
After all statements in try have been executed and any error handling has occurred in catch, the statements in finally are unconditionally executed.
Notice that the code inside finally is executed even if a return statement occurs inside the try or catch blocks, or if the catch block re-throws the error. finally is guaranteed to always run, unless an unhandled error occurs (for example, causing a run-time error inside the catch block).
Example 1
| print("1"); try { print("2"); throw "an exception"; print("3"); } catch(e) { print("4 " + e); } finally { print("5"); } } function print(s){ document.write(s); } |
This produces the following output:1 2 4 an exception 5
|
The following example illustrates JavaScript exception handling in a nested hierarchy. The general rules are:
- A throw inside a try will execute the companion catch.
- A throw inside a catch or finally will execute an enclosing catch.
| try { // throw "first exception"; print("1"); try { |
This produces the following output:1 2 4 an exception 5 6 an exception re-thrown 7
|
Exercise 1What is the output after un-commenting the line in Example 2?
|
The following example is from the project, Portfolio.asp. The essential approach is that any reported exception will be caught and somewhat gracefully reported to the user. By wrapping nearly the complete, normal execution script in a try block, all exceptions will be treated identically.
Portfolio.asp <%@ Language=JScript%>
<%
if(Session("trader") == undefined)
Response.Redirect("Login.xml");
try {
conn = Server.CreateObject("ADODB.Connection");
conn.Mode = 3;
conn.Open ("DSN=Project");
trader=Session("trader");
rs = conn.Execute(
"SELECT PORTFOLIO.SYMBOL, NAME, SHARES, PRICE, " +
"SHARES*PRICE as STOCKVALUE " +
"FROM STOCK INNER JOIN PORTFOLIO ON " +
"STOCK.SYMBOL = PORTFOLIO.SYMBOL WHERE ID='"+trader+"';");
var xmlDoc = Server.CreateObject("Msxml2.DOMDocument");
xmlDoc.async = false;
rs.Save (xmlDoc, 1) ; // Convert recordset to XML
var xsl = Server.CreateObject("Msxml2.DOMDocument");
xsl.async = false; // Convert XML tree using XSL
xsl.load(Server.MapPath("PortfolioContent.htm"))
// Write tree as HTML
Response.Write(xmlDoc.transformNode(xsl));
conn.Close();
}
catch(e) {
%>
<html>
<head>
<title>Stock Trader - Technical Error</title>
</head>
<body>
<h2>Stock Trader - Technical Error</h2>
<p>Trading cannot be continued at this time. </p>
<p>Please try again later.</p>
<p>Contact 1-800-123-4567 to report this problem or send email to:
<a href="mailto:">Online@StockTrader.com</a></p>
</body>
</html>
<% } %>
|
Stock Trader - Technical ErrorTrading cannot be continued at this time. Please try again later. Contact 1-800-123-4567 to report this problem or send email to: Online@StockTrader.com
|
Exercise 2
|
Rather than displaying an error message and depending upon the user to report the error, more useful for the developer is to try individual elements that throw exceptions and write details to a system log for later analysis.
The following example has separate try/catch statements for each source of an exception (i.e. the operations that throw exceptions to the caller). By handling each exception, specific error information can be logged to a file. The user sees the same error message in any failure case.
<%@ Language=JScript%>
<%
if(Session("trader") == undefined)
Response.Redirect("Login.xml");
var errorstr =" [Portfolio.asp] ";
var error = false;
conn = Server.CreateObject("ADODB.Connection");
conn.Mode = 3;
conn.Open ("DSN=Project");
if(!error) try {
trader=Session("trader");
rs = conn.Execute(
"SELECT PORTFOLIO.SYMBOL, NAME, SHARES, PRICE, " +
"SHARES*PRICE as STOCKVALUE " +
"FROM STOCK INNER JOIN PORTFOLIO ON " +
"STOCK.SYMBOL = PORTFOLIO.SYMBOL WHERE ID='"+trader+"';");
} catch(e) {
error = true;
errorstr = errorstr + " SELECT " + e;
}
if(!error) try {
var xmlDoc = Server.CreateObject("Msxml2.DOMDocument");
xmlDoc.async = false;
rs.Save (xmlDoc, 1) ; // Convert recordset to XML
} catch(e) {
error = true;
errorstr = errorstr + " XML " + e;
}
if(!error) try {
var xsl = Server.CreateObject("Msxml2.DOMDocument");
xsl.async = false; // Convert XML tree using XSL
xsl.load(Server.MapPath("PortfolioContent.htm"))
} catch(e) {
error = true ;
errorstr = errorstr + " XSL LOAD " + e;
}
if(!error) try {
Response.Write(xmlDoc.transformNode(xsl));
conn.Close();
} catch(e) {
error = true ;
errorstr = errorstr + " XSL TRANSFORM " + e;
}
if(error) {
try {
var d = new Date();
var ForAppending = 8;
fs = new ActiveXObject("Scripting.FileSystemObject");
a = fs.OpenTextFile("c:\\Project\\errorlog.txt", ForAppending, true);
a.Write("\r\n" + d + errorstr);
a.Close;
} catch(e) { }
%>
<html>
<head>
<title>Stock Trader - Technical Error</title>
</head>
<body>
<h2>Stock Trader - Technical Error</h2>
<p>Trading cannot be continued at this time. </p>
<p>Please try again later.</p>
<p>Contact 1-800-123-4567 to speak to technical support or send email to:
<a href="mailto:">Online@StockTrader.com</a></p>
</body>
</html>
<% } %>
|
Stock Trader - Technical ErrorTrading cannot be continued at this time. Please try again later. Contact 1-800-123-4567 to speak to technical support or send email to: Online@StockTrader.com Error in XSL of PortfolioContent.htm transformation Response.Write(xmlDoc.transformNode(xsl));
Produces contents in errorlog.txt of: Thu Jun 19 05:32:50 EDT 2005 |
Note - Our script also handles exceptions when attempting to write the error log by executing within a try/catch statement. A cleaner solution than including the HTML in each ASP script would be to place in a separate, error notification file and after logging the error, redirect to that file.
Exercise 3
|