Click here to Skip to main content
Click here to Skip to main content

Exception Handling and .NET

, 29 Aug 2013
Rate this:
Please Sign up or sign in to vote.
Exception Handling and .NET - a practical approach

Before We Start

Before you start reading this article you need to ensure you satisfy all the pre-requisites. You must:

  • be familiar with .NET Framework 2.0 or above
  • have C# coding skills
  • have knowledge of SQL Server 2005 or above
  • be familiar with Visual Studio 2005 or above
  • be familiar with creating web application in Visual Studio 2005 or above

Overview

Error Handling has always been crucial for an application in a number of ways. It may affect the execution state of the application, or expose sensitive information to a user. If the error handling is not strong, it may aid the attacker, as the errors returned may assist them in constructing correct attack factors.

An important part of secure application development is to prevent leakage of superfluous information to end user. Error messages (if not proper) may give an attacker great insight into the inner workings of an application.

Exception Handling and .NET

Right Approach

This content focusses more on technical feasibility and implementation of the same, we see here how the points discussed above are disguised in the form of code and learn how to implement these points practically in our application.

Consider the Following Live Scenarios

Let's have an aspx page with the following controls, a textbox, a button and a gridview,

When user inputs a student id in the textbox and submits the form by clicking submit button(Populate Grid), the gridview gets populated with the details of the student as per student id.

Code to populate grid

aspx:

.cs :

Following are the points that need to be taken care of,

  1. The text box value must be an integer value. (Input Validation)
  2. The student id provided should be greater than 0 and less than 5. (Business Logic Validation)

These are the rules known to a developer, but what if end user uses the application? Let's sneak peek into such scenario:

Scenario 1 : User inputs correct value and presses submit button.

Here we get the desired result

Scenario 2: User inputs a string or junk character and presses submit button,

Results in:

As we can clearly see, whole of the code is exposed to end user which is ethically meaningless.

Instead one should display a meaningfull message to the user, so that next time he inputs correct info.

Therefore we need to wrap our code with a try, catch block.

and following piece of code in aspx page:

<div>
    <asp:Label runat="server" ID="lblErrorDisplay" ForeColor="Red" FontBold="true" Visible="false" Font-Size="Medium" ></asp:Label>
</div>

Now when user inputs value other than integer, he is shown a meaningful message as,

Our application should not scare the end user with displaying yellow pages and complex codes but it should be informative and end-user friendly.

Scenario 3: User inputs an integer but violates business logic by entering 5 or integer greater than 5.

Our case: No message is shown to the user, the page simply refreshes itself,

Ideal case: User should be shown a message that "no user exists with the specified ID, please enter another ID between 1 to 5", after getting this message user will no longer sit idle thinking about what is wrong with the web site, he will take some other fruitfull action.

To overcome such issue we can again decorate our code as:

 protected void btnSubmit_Click(object sender, EventArgs e)
    {
        try
        {
            
            string textValue = txtId.Text;
            int id;
            if (!Int32.TryParse(textValue, out id))
            {
                throw new ApplicationException("Please provide correct student id.");
            }

            if (id <= 0 || id >= 5)
            {
                throw new ApplicationException("No user exists with the specified id, please enter another id between 1 to 5");
            }

            string connectionString = ConfigurationManager.ConnectionStrings["Connection"].ConnectionString;
            SqlConnection sqlConnection = new SqlConnection(connectionString);

            SqlCommand sqlCommand = new SqlCommand("Select StudentID,Fnamn,Enamn,Email,Login,Password from egStudent where StudentId=" +
               id.ToString(), sqlConnection);
            DataSet dataSet = new DataSet();
            SqlDataAdapter sqlDataAdapter = new SqlDataAdapter(sqlCommand);
            sqlConnection.Open();
            sqlDataAdapter.Fill(dataSet);
            grdStudentView.DataSource = dataSet.Tables[0];
            grdStudentView.DataBind();
            sqlConnection.Close();
            sqlDataAdapter.Dispose();
        }
        catch (ApplicationException exception)
        {
            lblErrorDisplay.Visible = true;
            lblErrorDisplay.Text = exception.Message;
        }
    }

Therefore the output:

The Exceptions discussed above were the Level 1 and Level 2 type exceptions.

Next comes Level 3. For level 3 type exceptions a special setup needs to be established, so that the exceptions could be handled as desired, simple playing with try catch blocks sometimes does not work with these kind of exceptions,

Scenario 4: A developer mistakingly writes a wrong query in select statement. Suppose he makes a typo and changes table name to egstudents (correct : egstudent). Let's see what happens.

   protected void btnSubmit_Click(object sender, EventArgs e)
    {
        try
        {
            
            string textValue = txtId.Text;
            int id;
            if (!Int32.TryParse(textValue, out id))
            {
                throw new ApplicationException("Please provide correct student id.");
            }

            if (id <= 0 || id >= 5)
            {
                throw new ApplicationException("No user exists with the specified id, please enter another id between 1 to 5");
            }

            string connectionString = ConfigurationManager.ConnectionStrings["Connection"].ConnectionString;
            SqlConnection sqlConnection = new SqlConnection(connectionString);

            SqlCommand sqlCommand = new SqlCommand("Select StudentID,Fnamn,Enamn,Email,Login,Password from egStudents where StudentId=" +
               id.ToString(), sqlConnection);
            DataSet dataSet = new DataSet();
            SqlDataAdapter sqlDataAdapter = new SqlDataAdapter(sqlCommand);
            sqlConnection.Open();
            sqlDataAdapter.Fill(dataSet);
            grdStudentView.DataSource = dataSet.Tables[0];
            grdStudentView.DataBind();
            sqlConnection.Close();
            sqlDataAdapter.Dispose();
        }
        catch (ApplicationException exception)
        {
            lblErrorDisplay.Visible = true;
            lblErrorDisplay.Text = exception.Message;
        }
    }

And so, the output:

In this special case, once the site is up, it becomes hard for the developer to trace the code. Moreover the end user is once again exposed to the unwanted yellow page.

Cure: These kind of Level 3 exceptions need to be centralized (as discussed before in the article). We can write the piece of code in Global.asax on Application_Error event (handles application level errors), one can write the code to log the specific error and show end user a custom error page, to overcome panic situation.

Step1 : Add code to Global.asax,

 void Application_Error(object sender, EventArgs e) 
    {
        Exception exception = Server.GetLastError();
        LoggError.Write(exception);

    }

Step2: Create a Custom Error Page, and define its path in web.config with a key value pair in appsettings

ErrorPage.aspx:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <title></title>
</head>
<body>
<center>
<div><img src="ErrorPage1.jpg" alt="Error Page" /></div>
</center>
</body>
</html>

Page Path:

  <appSettings>
    <add key="ErrorLog" value="~/ErrorLog.txt" />
  </appSettings>

Step 3: Enable Custom error mode in web.config inside system.web node with path to your error page as default redirect,.

<customErrors mode="On" defaultRedirect="Error/ErrorPage.htm">
</customErrors>

Step 4: Add a class to your appCode folder, that logs the error into a text file.

using System;
using System.Configuration;
using System.IO;
using System.Web;

    /// <summary>
    /// The Class Writes Exception and Error information into a log file named ErrorLog.txt.
    /// </summary>
public class LoggError
{
    /// <summary>
    /// Writes error occured in log file,if log file does not exist,it creates the file first.
    /// </summary>
    /// <param name="exception">Exception</param>
    public static void Write(Exception exception)
    {
        string logFile = String.Empty;
        StreamWriter logWriter;
        try
        {
            logFile = HttpContext.Current.Server.MapPath(ConfigurationManager.AppSettings["ErrorLog"].ToString());
            if (File.Exists(logFile))
                logWriter = File.AppendText(logFile);
            else
                logWriter = File.CreateText(logFile);
            logWriter.WriteLine("=>" + DateTime.Now + " " + " An Error occured : " +
                exception.StackTrace + " Message : " + exception.Message + "\n\n");
            logWriter.Close();
            throw exception;

        }
        catch (Exception e)
        {
            throw ;
        }
        finally
        {
            throw ;
        }
    }
}

Finally, when such error occurs, the user is displayed an error page as below:

And for the sake of debugging and development, an actual error is logged in a text file (in my case located at root) as:

=>11/21/2011 7:42:02 PM  An Error occured :    at System.Web.UI.Page.HandleError(Exception e)
   at System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint)
   at System.Web.UI.Page.ProcessRequest(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint)
   at System.Web.UI.Page.ProcessRequest()
   at System.Web.UI.Page.ProcessRequestWithNoAssert(HttpContext context)
   at System.Web.UI.Page.ProcessRequest(HttpContext context)
   at ASP.default_aspx.ProcessRequest(HttpContext context) in c:\Users\akhil.mittal\AppData\Local\Temp\Temporary ASP.NET Files\exceptionhandling\327c9c5b\2858bbb8\App_Web_iexkgkvc.2.cs:line 0
   at System.Web.HttpApplication.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute()
   at System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) Message : System.Data.SqlClient.SqlException (0x80131904): Invalid object name 'egStudents'.
   at _Default.btnSubmit_Click(Object sender, EventArgs e) in d:\Akhil Mittal\Blogs\ExceptionHandling\Default.aspx.cs:line 56
   at System.Web.UI.WebControls.Button.OnClick(EventArgs e)
   at System.Web.UI.WebControls.Button.RaisePostBackEvent(String eventArgument)
   at System.Web.UI.WebControls.Button.System.Web.UI.IPostBackEventHandler.RaisePostBackEvent(String eventArgument)
   at System.Web.UI.Page.RaisePostBackEvent(IPostBackEventHandler sourceControl, String eventArgument)
   at System.Web.UI.Page.RaisePostBackEvent(NameValueCollection postData)
   at System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint)

The log gives full information about the type and source of exception.

There are many other ways to handle Level 3 Exceptions which we'll discuss in next coming articles, but to hit the floor running, this one is the beginning.

And last but not the least, the Finally block.

Finally Block

As the last clause in the try-catch statement a finally block can also be added. This block is used to clean up all the resources allocated in the try block and will always execute whether there is an exception or not. In the above scenarios for example, we can make use of this block to free SQL connection as.

sql connection as ,
sqlConnection.Close();
sqlDataAdapter.Dispose();

And thus the final code.

protected void btnSubmit_Click(object sender, EventArgs e)
    {
        string textValue = txtId.Text;
        int id;
        string connectionString = ConfigurationManager.ConnectionStrings["Connection"].ConnectionString;
        SqlConnection sqlConnection = new SqlConnection(connectionString);
        SqlDataAdapter sqlDataAdapter = new SqlDataAdapter();
        DataSet dataSet = new DataSet();
        try
        {
            if (!Int32.TryParse(textValue, out id))
                throw new ApplicationException("Please provide correct student id.");
            if (id <= 0 || id >= 5)
                throw new ApplicationException("No user exists with the specified id, please enter another id between 1 to 5");
            SqlCommand sqlCommand = new SqlCommand("Select StudentID,Fnamn,Enamn,Email,Login,Password from egStudents where StudentId=" +
           id.ToString(), sqlConnection);
            sqlDataAdapter = new SqlDataAdapter(sqlCommand);
            sqlConnection.Open();
            sqlDataAdapter.Fill(dataSet);
            grdStudentView.DataSource = dataSet.Tables[0];
            grdStudentView.DataBind();
        }
        catch (ApplicationException exception)
        {
            lblErrorDisplay.Visible = true;
            lblErrorDisplay.Text = exception.Message;
        }
        catch (Exception exception)
        {
            throw ;
        }
        finally
        {
            sqlConnection.Close();
            sqlDataAdapter.Dispose();
        }
    }

Conclusion

Now after successfully implementing the exception handling technique according to above discussed code and logic, we better know how and where to initiate exception handling in our code according to our requirements.

Please visit my blog A Practical Approach for more informative articles. 

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

Akhil Mittal
Technical Lead
India India
I am a C# Corner MVP,a Code project MVP,author,blogger and currently working as an Analyst in an MNC and have an experience of more than 6 years in C#.Net. I am a B.Tech in Computer Science and hold a diploma in Information Security and Application Development. My work experience includes Development of Enterprise Applications using C#,.Net and Sql Server,Analysis as well as Research and Development. I am a MCP in Web Applications(MCTS-70-528,MCTS-70-515) and .Net Framework 2.0 (MCTS-70-536). Please visit my blog A Practical Approach for more informative articles.
____________________________________________________________________________________________________________________
 
Article of the Day on Microsoft's site http://www.asp.net/community/articles on 16 August 2013.
Article of the Day on Microsoft's site http://www.asp.net/community/articles on 28 August 2013.
Article of the Day on Microsoft's site http://www.asp.net/community/articles on 08 Sept 2013.
Article of the Day on Microsoft's site http://www.asp.net/community/articles on 29 Sept 2013.
Article of the Day on Microsoft's site http://www.asp.net/community/articles on 29 Oct 2013.
Article of the Day on Microsoft's site http://www.asp.net/community/articles on 21 May 2014.
Member of the month for July 2013 on C# Corner
Month Winner for July 2013 on C# Corner
http://www.c-sharpcorner.com/News/3067/july-2013-month-winners-announced.aspx
Month Winner for May 2014 on C# Corner
http://www.c-sharpcorner.com/News/3798/may-2014-month-winners-announced.aspx
Group type: Collaborative Group

146 members

Follow on   Twitter   Google+   LinkedIn

Comments and Discussions

 
QuestionThank you. Pinmemberudeep kansal10-Sep-13 20:16 
AnswerRe: Thank you. PingroupAkhil_Mittal10-Sep-13 20:46 
GeneralExpensive Pinmemberdan_fish3-Sep-13 1:39 
GeneralRe: Expensive PinmemberRoman Ivantsov3-Sep-13 8:38 
GeneralMy vote of 5 PinmemberVolynsky Alex30-Aug-13 0:12 
GeneralRe: My vote of 5 PingroupAkhil_Mittal30-Aug-13 22:20 
GeneralRe: My vote of 5 PinmemberVolynsky Alex31-Aug-13 2:44 
GeneralMy vote of 3 PinmemberBillWoodruff26-Aug-13 23:47 
GeneralMy vote of 4 PinmemberV.Lorz26-Aug-13 20:26 
GeneralRe: My vote of 4 PingroupAkhil_Mittal26-Aug-13 22:01 
QuestionDoubt in this error handler. PinprofessionalSanthoshobject22-Aug-13 21:43 
AnswerRe: Doubt in this error handler. PingroupAkhil_Mittal26-Aug-13 17:53 
GeneralMy vote of 3 PinprofessionalSanthoshobject22-Aug-13 21:42 
GeneralMy vote of 5 Pinmembergupta_pankaj_magic14-Aug-13 6:55 
GeneralMy vote of 5 PinmemberMember 101973838-Aug-13 1:11 
GeneralMy vote of 5 PinmemberNaushervan9-Jun-13 21:30 
GeneralRe: My vote of 5 PingroupAkhil_Mittal9-Jun-13 23:02 
QuestionWrite Error Log or Exception Log into File in C# .NET PinmemberWorld Traveler19-Mar-13 8:41 
AnswerRe: Write Error Log or Exception Log into File in C# .NET PinmemberAkhil_Mittal19-Mar-13 17:04 
GeneralRe: Write Error Log or Exception Log into File in C# .NET PinmemberWorld Traveler19-Mar-13 19:31 
QuestionNice article, but.. PinmvpEddy Vluggen22-Feb-13 0:28 
GeneralMy vote of 5 PinmemberRuth Aanie21-Feb-13 20:44 
GeneralRe: My vote of 5 PinmemberAkhil_Mittal21-Feb-13 21:07 
QuestionThanks for this post ! PinmemberMas1121-Feb-13 19:44 
AnswerRe: Thanks for this post ! PinmemberAkhil_Mittal21-Feb-13 21:07 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web02 | 2.8.140709.1 | Last Updated 30 Aug 2013
Article Copyright 2013 by Akhil Mittal
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid