Delphi Clinic C++Builder Gate Training & Consultancy Delphi Notes Weblog Dr.Bob's Webshop
Dr.Bob's Delphi Notes Dr.Bob's Delphi Clinics Dr.Bob's Delphi Courseware Manuals
 Dr.Bob Examines... #94
See Also: Dr.Bob's Delphi Papers and Columns

ASP.NET Error Handling
In this article, I'll explain the foundations of ASP.NET error handling, applicable to both ASP.NET 1.1 and ASP.NET 2.0 web applications.

ASP.NET Error Handling consists of catching the error and handling it or at least preventing it from displaying a very ugly error message page to the end user. This also means that we should put user-friendly error messages on screen, but specific, technical error messages on some place where we can examine them - either via a browser or in a logfile or e-mail message.
For the error specifics, I prefer to use the ASP.NET Trace object, with the Write and Warn methods (Warn is the same as Write, but the text is displayed in a red font in the trace window).

Method Specific
The first way to detect and try to handle errors in ASP.NET application is the method specific way; inside each method, we should place a try-except block, placing the original code in the try clause and handling the error in the except clause. This sounds like a lot of work, but it will be worth it in the end.

Error Handling Steps
For a real-world ASP.NET project, I've implemented custom error handling in a number of layers. Using exceptions, page errors as well as application errors. Using exceptions means that I've added error handling try-except as well as resource protection try-finally to most of my methods. This does not prevent all errors from being trapped, however, so more steps are needed.
In each web page .pas file, I've added the following code, starting with an explicit default constructor to the class:

  constructor Create;
Which was implemented as follows, assigning the Error event to the TDefault_Error event handler (which also needs to be defined in the next step).
  constructor TDefault.Create;
  begin
    inherited;
    Include(Self.Error, Self.TDefault_Error);
  end;
As mentioned, we should also define the TDefault_Error event handler itself. This can be added using the Object Inspector, by selecting the web page class and selecting the Error event, or just by adding the following definition to the Designer Manager Code section of the class definition:
    procedure TDefault_Error(sender: TObject; e: System.EventArgs);
Which is in turn implemented as follows:
  procedure TDefault.TDefault_Error(sender: TObject; e: System.EventArgs);
  begin
    Session['LastException'] := Server.GetLastError;
    Response.Redirect('Error.aspx');
  end;
As you can see here, we add the unhandled exception to the session, and redirect to a page where we handle the exception.

Note that the literal strings for LastException and Error.aspx can be extracted and added to the Global.pas unit, to ensure no typing errors are made.

type
  PageNames = class
  const
    Error                   = '~/Error.aspx';
    Default                 = '~/Default.aspx';
    ...
  end;

  KeyStr = class
  const
    LastException    = 'LastException';
   ...
  end;
With this in mind, we can rewrite the error handler a bit cleaner as follows:
  procedure TDefault.TDefault_Error(sender: TObject; e: System.EventArgs);
  begin
    Session[KeyStr.LastException] := Server.GetLastError;
    Response.Redirect(PageNames.Error);
  end;
This will redirect all unhandled exceptions to the page Error.aspx, which should be able to display the message and redirect back to the original page (where we can then fix the problem).
The Error.aspx page can be a content page, or an independent page, needing only a label to show the error message, as well as a simple HTML button with a call to hostory.go(-1) in order to return to the previous page.
  <asp:Label id="lbError" runat="server" />
  <p/>
  <input type="reset" onclick="history.go(-1);" value="Back">
The implementation details can be found in the Page_Load, which is defined as follows:
  procedure TError.Page_Load(sender: System.Object; e: System.EventArgs);
  var
    Ex: Exception;
  begin
    Ex := Server.GetLastError;
    if not Assigned(Ex) then
      if Assigned(Session['LastException']) then
        Ex := (Session['LastException'] as Exception);

    lbError.Text := 'Error: ';
    while Assigned(Ex) do
    begin
      lbError.Text := lbError.Text + Ex.ClassName +
                      '<p/>' + Ex.Message.Replace('<','&lt;')
      {$IFDEF DEBUG}
          + '<pre>StackTrace:' + '<br>' + Ex.StackTrace + '</pre>'
      {$ENDIF}
      + '<hr>';
      Ex := Ex.InnerException;
    end;
    Server.ClearError;
  end;
Note that call to Server.ClearError here, to clear the error message again.

Finally, we can use the Error.aspx page also to handle unhandled exceptions at the application level, by specifying the following in the global.pas unit:

  procedure TGlobal.Application_Error(sender: System.Object; e: EventArgs);
  begin
    Session['LastException'] := Server.GetLastError;
  //Server.ClearError; -- Make sure Error.aspx handles the error now
  end;
And the following in the web.config file:
  <customErrors
      mode="Off"
      defaultRedirect="Error.aspx"
  />
And this will take of all ugly errors from now on.

RAD Studio 2007 ASP.NET 2.0 Web Development
This article is an excerpt from my RAD Studio 2007 ASP.NET 2.0 Web Development courseware manual which is available for purchase (with updates and e-mail support) from my own site.


This webpage © 2007-2010 by Bob Swart (aka Dr.Bob - www.drbob42.com).All Rights Reserved.