Dissecting Error Messages

by Alek Davis



Listing One



//-------------------------------------------------------------------

// $Workfile: BasePage.aspx.cs $

// Description: Implements the BasePage class.

// $Log:  $

//-------------------------------------------------------------------

using System;



namespace ErrorSample

{

/// <summary>

/// Base class implementing common utility functions reused by

/// different pages belonging to this Web application.

/// </summary>

/// <remarks>

/// Page classes on this site must derive from

/// <see cref="ErrorSample.BasePage"/>, not the usual

/// <see cref="System.Web.UI.Page"/>.

/// </remarks>

public class BasePage: System.Web.UI.Page

{

    // We need to keep the counters of the popup script blocks.

    // (Actually, we can distinguish between client-side and

    // start-up scripts, but why bother?)

    private int _errorScriptCount         = 0;

    private string _errorScriptNameFormat = "_errorScript{0}";

    /// <summary>

    /// Formats string and replaces characters, which can break 

    /// JavaScript, with their HTML codes.

    /// </summary>

    /// <param name="message">

    /// Message or message format.

    /// </param>

    /// <param name="args">

    /// Optional message parameters.

    /// </param>

    /// <returns>

    /// Formatted string which is JavaScript safe.

    /// </returns>

    private static string FormatJavaScriptMessage

    (

        string          message,

        params object[] args

    )

    {

        // Make sure we have a valid error message.

        if (message == null)

            return String.Empty;

        // If we have message parameters, build a formatted string.

        if (args != null && args.Length > 0)

            message = String.Format(message, args).Trim();

        else

            message = message.Trim();

        // Make sure we have a valid error message.

        if (message.Length == 0)

            return String.Empty;

        // Back slashes, quotes (both single and double),

        // carriage returns, line feeds, and tabs must be escaped.

        return message.Replace(

            "\\", "\\\\").Replace(

                "'", "\\'").Replace(

                    "\"", "\\\"").Replace(

                        "\r", "\\r").Replace(

                            "\n", "\\n").Replace(

                                    "\t", "\\t");

    }

    /// <summary>

    /// Shows a formatted error message in a client-side (JavaScript)

    /// popup dialog.

    /// </summary>

    /// <param name="message">

    /// Error message or message format.

    /// </param>

    /// <param name="args">

    /// Optional message arguments.

    /// </param>

    /// <remarks>

    /// Error popup will be rendered as the first element of the

    /// page (form).

    /// </remarks>

    public void ShowErrorPopup

    (

        string          message, 

        params object[] args

    )

    {

        ShowErrorPopup(true, message, args);

    }

    /// <summary>

    /// Shows a formatted error message in a client-side (JavaScript)

    /// popup dialog.

    /// </summary>

    /// <param name="showFirst">

    /// Flag indicating whether the error message must be rendered

    /// as the first element of the page (form).

    /// </param>

    /// <param name="message">

    /// Error message or message format.

    /// </param>

    /// <param name="args">

    /// Optional message arguments.

    /// </param>

    public void ShowErrorPopup

    (

        bool            showFirst,

        string          message, 

        params object[] args

    )

    {

        // Build message string which is safe to display in JavaScript code.

        message = FormatJavaScriptMessage(message, args);

        // If we did not get any message, we should not generate any output.

        if (message.Length == 0)

            return;

        // Generate a unique name of the start-up script.

        string scriptBlockName = String.Format(

        // Generate HTML for the script.

        string scriptHtml = String.Format(

                           "{0}" + "<SCRIPT Language=\"JavaScript\">{0}" + 

                           "<!--{0}" + "alert(\"{1}\");{0}" + "-->{0}" + 

                           "</SCRIPT>{0}", Environment.NewLine, message);

        // Generate script opening a popup with error message.

        if (showFirst)

            RegisterStartupScript(scriptBlockName, scriptHtml);

        else

            RegisterClientScriptBlock(scriptBlockName, scriptHtml);

    }

}

}

//-------------------------------------------------------------------

// $Workfile: Default.aspx.cs $

// Description: Implements the DefaultPage class.

// $Log:  $

//-------------------------------------------------------------------

using System;

using System.Collections;

using System.ComponentModel;

using System.Data;

using System.Drawing;

using System.Web;

using System.Web.SessionState;

using System.Web.UI;

using System.Web.UI.WebControls;

using System.Web.UI.HtmlControls;



namespace ErrorSample

{

/// <summary>

/// Implements the default Web page.

/// </summary>

public class DefaultPage: BasePage

{

    protected System.Web.UI.WebControls.Button btnTest;

    private void Page_Load(object sender, System.EventArgs e)

    {

    }

    #region Web Form Designer generated code

    override protected void OnInit(EventArgs e)

    {

        // CODEGEN: This call is required by the ASP.NET Web Form Designer.

        InitializeComponent();

        base.OnInit(e);

    }

    /// <summary>

    /// Required method for Designer support - do not modify

    /// the contents of this method with the code editor.

    /// </summary>

    private void InitializeComponent()

    {    

        this.btnTest.Click += new System.EventHandler(this.btnTest_Click);

        this.ID = "Form";

        this.Load += new System.EventHandler(this.Page_Load);

    }

    #endregion

    // Displays error messages when button is clicked.

    private void btnTest_Click(object sender, System.EventArgs e)

    {

        for (int i=0; i<4; i++)

        {

            // Display errors with odd IDs as the first elements of

            // the form and the rest as the last elements of the form.

            bool showFirst = (i & 0x1) == 1;

            ShowErrorPopup( showFirst, "Error '{0}' occurred at:{1}{1}{2}", 

                            i, Environment.NewLine, DateTime.Now);

        }

    }

}

}







Listing Two



bool CreateAccounts()

{

  UserListInfo = GetUserListInfo();

  foreach(UserInfo in UserListInfo)

  {

    if (not CreateAccount(UserInfo))

    {

      Report error.

    }

  }

}

bool CreateAccount(UserInfo)

{

  if (not CreateProfile(UserInfo))

  {

    Report error.

    return false;

  }

  if (not CreateMailbox(UserInfo))

  {

    Report error.

    return false;

  }

  return true;

}

bool CreateProfile(UserInfo)

{

  Create profile.

}

bool CreateMailbox(UserInfo)

{

  Create mailbox.

}





Listing Three 



bool CreateAccounts()

{

  UserListInfo = GetUserListInfo();

  string msg, errMsg;

  foreach(UserInfo in UserListInfo)

  {

    if (not CreateAccount(msg, UserInfo))

    {

      errMsg = "Cannot create account for user "+UserInfo.UserID + ". " + msg;

      ReportError(errMsg);

    }

  }

}

bool CreateAccount(errMsg, UserInfo)

{

  string msg;

  if (not CreateProfile(msg, UserInfo))

  {

    errMsg = "Cannot create profile for " +

                UserInfo.ProfileName +

                ". " + msg;

    return false;

  }

  if (not CreateMailbox(msg, UserInfo))

  {

    errMsg = "Cannot create mailbox for " + UserInfo.MailboxName + ". " + msg;

    return false;

  }

  ...

  return true;

}

bool CreateProfile(errMsg, UserInfo)

{

  if (profile exists)

  {

    errMsg = "Profile already exists.";

    return false;

  }

  Create profile.

  ...

  return true;

}

bool CreateMailbox(errMsg, UserInfo)

{

  if (mailbox exists)

  {

    errMsg = "Mailbox already exists.";

    return false;

  }

  Create malbox.

  ...

  return true;

}





Listing Four 



bool DoThis(TCHAR** ptszErrMsg, ...)

{

  TCHAR* ptszMsg = NULL;

  if (!DoThat(&ptszMsg, ...))

  {

    BuildMessage(ptszErrMsg, _T("Cannot do that. %s"), ptszMsg);

    TryDeleteMessage(&ptszMsg);

    return false;

  }

  return true;

}

bool DoThat(TCHAR** ptszErrMsg, ...)

{

  TCHAR* ptszMsg = NULL;

  if (!DoTheOther(&ptszMsg, ...))

  {

    BuildMessage(ptszErrMsg, _T("Cannot do the other. %s"), ptszMsg);

    TryDeleteMessage(&ptszMsg);

    return false;

  }

  return true;

}

main()

{

  TCHAR* ptszMsg    = NULL;

  TCHAR* ptszErrMsg = NULL;

  

  if (!DoThis(&ptszMsg, ...))

  {

    BuildMessage(&ptszErrMsg, "Cannot do this. %s", ptszMsg);

    puts(ptszErrMsg);

    TryDeleteMessage(&ptszMsg);

    TryDeleteMessage(&ptszErrMsg);

  }

}









6



