Mukarram Mukhtar

Error Handling in .NET

In this application I’ll show you three different ways of handling errors let’s name them as:

 

1.      Application level, minimal coding required.

2.      Module level, some coding required.

3.      Blend of the upper two, my personal favorite, some more coding required.

 

Let’s start,

 

·        Start Microsoft Visual Studio 2003 or later.

·        Click Create New Project

·        In New Project dialog box, select Visual C# in Project types panel on left.

·        Select ASP.NET Web Application in the Templates panel on right.

·        Give a decent physical path and name to your project and select OK.

 

  errorhandlingnewproject

 

 

By doing this, IDE will create a web application project with a default form added into it.

 

·        Leave Default.aspx as is.

·        Add Global.asax to the project by right clicking project root node in Solution Explorer.

·        Add another web page to the project by right clicking project root node in Solution Explorer; name it ErrorPage.aspx.

·        Next step would be adding a folder to the project by right clicking project root node in Solution Explorer; name it Module.

·        Right click Module folder and add three web forms in it namely, ModuleForm1.aspx, ModuleForm2.aspx and ModuleErrorPage.aspx.

 

After completing the above steps your Solution Explorer should look something like this:

 

 errorsolutionexplorer

 

 

Now let’s start with application level error handling techniques. In order to do this, write the following line in your web.config.

 

<customErrors mode=On defaultRedirect=ErrorPage.aspx></customErrors>

 

And then open your ErrorPage.aspx file and write some standard error message in it:

 

<body>

    <form id=”form1″ runat=”server”>

    <div>

        <b>

        Some unexpected error occured in the application. If the problem persists, please contact your application vendor.

        </b><br /><br /><hr />       

        <input type=”button” id=”btnBack” value=”Back” onclick=’history.back();’ />

        <input type=”button” id=”btnClose” value=”Close” onclick=’window.close();’ />

    </div>

    </form>

</body>

 

 

This reminds me Windows 95/97’s blue screen error messages that always used to end on ‘If the problem persists, please contact your application vendor’. Anyways, so that’s it; we are done with simplest form of application level, exception handling. Now as we know, every hero needs a villain; we need a villain page that would throw exceptions. Let’s start coding Default.aspx:

 

<body>

    <form id=”form1″ runat=”server”>

    <div>

        Divide <asp:TextBox ID=”txtNum1″ runat=”server”></asp:TextBox> with

        <asp:TextBox ID=”txtNum2″ runat=”server”></asp:TextBox>

        <asp:Button ID=”btnDivide” runat=”server” Text=”Divide!” onclick=”btnDivide_Click” />

        <br />

        Result:

        <asp:Label ID=”lblResult” runat=”server” ></asp:Label>

    </div>

    </form>

</body>

 

No explanation is needed since everything is so simple in the above code. Let’s write our one line code of btnDivide_Click event:

 

        protected void btnDivide_Click(object sender, EventArgs e)

        {

            this.lblResult.Text = (int.Parse(this.txtNum1.Text) / int.Parse(this.txtNum2.Text)).ToString();

        }

 

 

As you can easily guess, as long as texts in txtNum1 and txtNum2 are valid numbers and txtNum2’s text is not zero, application will work fine. But the moment you enter some non numeric text in any of these text boxes or you enter zero in txtNum2, you’ll get an error, see the following screenshots.

 

 

errorhandlingdefault

 

Good, divided successfully, but things are not always like that:

 

 

 errorhandlingdefaultbadinput

 

Dumb user!

 

 

 errorhandlingdefaulterror

 

See how simple that was? That’s the end of the first approach, application level exception handling.

 

 

Ok now let’s try the second approach, module level error handling; this requires a little bit of coding. Before we start working on the second approach let’s quickly add 3 more lines in Default.aspx; these lines will help us navigation to module level web pages:

 

        <br />

        <input type=”button” id=”btnModuleForm1″ value=”Go to Module Form1″ onclick=”location.href=’Module/ModuleForm1.aspx’;” />

        <input type=”button” id=”btnModuleForm2″ value=”Go to Module Form2″ onclick=”location.href=’Module/ModuleForm2.aspx’;” />

 

After adding the above lines, our Default.aspx looks like this:

 

 

 errorhandlingdefault2

 

Now let’s suppose we have a separate module in our application and we want some different information to be displayed on the error page, in case an exception is uncaught. As we’ve already added a folder named ‘Module’ and we have pages in that folder as well so let’s start coding ModuleForm1.aspx.cs; copy-paste the exact code from Default.aspx. The only difference is, in ModuleForm1.aspx we’ll add one extra directive ErrorPage=”~/Module/ModuleErrorPage.aspx” in the first line of the page:

 

<%@ Page Language=”C#” AutoEventWireup=”true” ErrorPage=”~/Module/ModuleErrorPage.aspx” CodeBehind=”ModuleForm1.aspx.cs” Inherits=”prjExceptionHandling.Module.ModuleForm1″ %>

 

This will tell the application that if an error occurs in this page, don’t go to main application’s ErrorPage.aspx; go to ModuleErrorPage.aspx in its stead. btnDivide_Click here is a little bit more different as well.

 

protected void btnDivide_Click(object sender, EventArgs e)

{

    try

    {

       this.lblResult.Text = (int.Parse(this.txtNum1.Text) / int.Parse(this.txtNum2.Text)).ToString();

    }

    catch (Exception exc)

    {

        Session[“ModuleException”] = exc;

        throw exc;

    }

}

 

In this case, we are catching the highest level of exception, which is the parent of all the exceptions and after storing it in a session level variable we are re-throwing the same exception. The result would be, as you might have already guessed, application will take you to ModuleErrorPage.aspx, where we have done some coding in slightly different way than ErrorPage.aspx. Here is the body of ModuleErrorPage.aspx:

 

<body>

    <form id=”form1″ runat=”server”>

    <div>

        <b>

        Some unexpected error occured in the application. If the problem persists, please contact your application vendor.

        Please see the following message for more details:

        </b><br /><br />

        <asp:Label ID=”lblErrorMessage” Font-Size=”Larger” Font-Bold=”true” ForeColor=”Red” runat=”server” ></asp:Label><br /><br />

        <asp:Label ID=”lblErrorDetails” ForeColor=”Red” runat=”server” ></asp:Label>

        <br /><hr />       

        <input type=”button” id=”btnBack” value=”Back” onclick=’history.back();’ />

        <input type=”button” id=”btnClose” value=”Close” onclick=’window.close();’ />

   

    </div>

    </form>

</body>

 

In this page we’ve added two new label controls for displaying verbose error message. Page_Load event of ModuleErrorPage will also be different:

 

        protected void Page_Load(object sender, EventArgs e)

        {

            if (Session[“ModuleException”] != null)

            {

                Exception exc = (Exception)Session[“ModuleException”];

                this.lblErrorMessage.Text = exc.Message;

                this.lblErrorDetails.Text = exc.ToString();

            }

        }

 

Run the application and on Default page, select Go to Module Form1 button, we’ll get From1, enter bad data in it, the resultant screenshots are as follows:

 

 errorhandlingform1

 

 

 And we’ll get a lot better error message as this:

 

 

errorhandlingmoduleerror 

 

That’s the end of the second approach.

 

 

Now let’s see the third approach, my favorite one. What I normally do is I try to catch as many exceptions within the form as I can think of. Nonetheless, there are still many occasions where is miss to foresee how unexpected and error producing data, users can enter (in other words, how dumb users can be). Thus I always try to give an informative error message on the same page for all the exceptions I could expect on that page and then there is a standard error message for all other exceptions that were really ‘unexpected’; blend of above two approaches, require a little bit more coding. Let’s see this in action in our ModuelForm2.aspx, but before that let’s add one more entry in web.config:

 

      <appSettings>

            <add key=ErrorMessage value=Verbose />           

      </appSettings>

 

Then comes Global.asax:

 

        protected void Application_Error(object sender, EventArgs e)

        {

            string errorMessage = “<b>Some unexpected error occured in the application. If the problem persists, please contact your application vendor. “;

            Exception exc = Server.GetLastError();

 

            if (exc != null && exc.InnerException != null)

            {

                errorMessage += “Please see the following message for more details:</b><br /><br /><font color=’red’><H4>” + exc.InnerException.Message + “</H4>”;

 

                if (WebConfigurationManager.AppSettings[“ErrorMessage”] != null &&

                    WebConfigurationManager.AppSettings[“ErrorMessage”] == “Verbose”)

                {

                    errorMessage += exc.InnerException.ToString();

                }

 

                errorMessage += “</font><br />”;

            }

 

            errorMessage += “<hr /><input type=’button’ id=’btnBack’ value=’Back’ onclick=’history.back();’ />” +

                            “&nbsp;<input type=’button’ id=’btnClose’ value=’Close’ onclick=’window.close();’ />”;

 

            Response.Clear();

            Response.Write(errorMessage);

            Response.End();

        }

 

This whole code will produce exactly the same effect as produced in ModuleErrorPage. Code is pretty easy to understand so I think there is no need of any explanation. Now let’s see ModuleForm2.aspx. UI will be exactly same as Default.aspx, btnDivide_Click, however, will be different as follows:

 

        protected void btnDivide_Click(object sender, EventArgs e)

        {

            try

            {

                this.lblResult.Text = (int.Parse(this.txtNum1.Text) / int.Parse(this.txtNum2.Text)).ToString();

            }

            catch (DivideByZeroException dbzexc)

            {

                this.lblResult.Text = “Division by zero is not allowed, please enter another value.”;

            }

            catch (Exception exc)

            {

                throw exc;

            }

        }

 

In this method, I caught DivideByZeroException and displayed a proper message right in the page. For all other exceptions I just caught them and re-threw them. All such exceptions will be caught in Global.asax’s Application_Error method. There, an error message will be displayed depending upon web.config’s settings. If this is a development server then surely you want ‘Verbose’ error message. On production server, nevertheless, you should keep it ‘Succinct’. Clients don’t like to watch long red error message which they don’t even understand. The above code will engender the following screenshots.

 

 

 

form2dividebyzero

 

Diving by zero? Not a problem, I knew user would do this…

 

 form2dividebyzeroresult

 

Exception caught right at the spot. But what if user enters something I couldn’t even think of?

 

 form2wronginput

 

Don’t worry, for this villain, I have my Global.asax hero standing by:

 

 form2wronginputresult

 

On production server, keep web.config’s entry as this:

 

            <add key=ErrorMessage value=Succinct />          

 

Which will show the following screen on the same error:

 

 form2wronginputresultsuccinct

 

So that’s it folks; exception handling in .NET, simple and robust. Feel free to give me your feedback, should you have any questions, don’t hasitate in asking, not even for the source code.

 

Until next time…

Advertisements

3 Comments »

  1. Hei Mukarram,
    3rd method is very interesting.I tried 3rd method.but i have a doubt that in which page we get the error message?.
    we are generating error message from Global.asax.But how can we display it(using which page)?.It will be appreciable,If you could send the code or can you help me.
    Thanks a lot for the post

    Regards,
    Binto Thomas

    Comment by Binto — November 4, 2009 @ 10:52 am

    • As you can see in browser’s address bar, the page will be the same where error was generated. The code in the global.asax will clear the contents of the current page and display the error message in it. Once error is displayed, Back button will take you back to the original form of the page.

      For source code, I’ll try to find this project’s source and will send it to you. As you can see no one ever asked for this project’s source, you are the first one. That’s why I almost lost its project files, but let me see if I can find it.

      Regards,
      Mukarram

      Comment by Mukarram Mukhtar — November 4, 2009 @ 2:34 pm

  2. Extremely nice article sir……

    Comment by Sumit — August 5, 2011 @ 6:53 am


RSS feed for comments on this post. TrackBack URI

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Blog at WordPress.com.

%d bloggers like this: