Home
    Shop
    Advertise
    Write For Us
    Affiliate
    Newsletter
    Contact

Errors And Exceptions In ASP.NET

Errors, mistakes and failures are unavoidable part of life. ASP.NET development is not much different. Every developer, especially beginners, will make errors whenever tries to create anything useful. Because of that, we need methods and tools for error handling. Fortunately, ASP.NET provides different ways to find, log or even try to correct errors when happened.

 

There are three different kinds of errors you can produce.

1. Syntax errors

Syntax errors occur during development, when you make type mistake in code. If you use anything more advanced than Notepad every syntax error will be marked in code editor. For example, Visual Studio or Visual Web developer will underline error with red zigzag line. If you go with mouse pointer over the error, you'll get more information, like in image bellow:

Syntax error in Visual Web Developer
Image 1: Syntax error in Visual Web Developer

Even if you don't notice this underlined text, Visual Studio or Visual Web Developer will inform you again when you try to compile application. Because of that, syntax errors maybe looks horrible especially for beginners, but they are easy to detect and solve.

2. Run time errors

Great thing in web development is that you can easily get notification by e-mail (or on some other way) every time when error occurs. It could be very disappointing if you don't have some error message reporting system and then accidentally discover that some page doesn't work for a months.

All run time errors in ASP.NET we can divide in two groups:

a) Handled errors - These errors are predicted and we manage them with Try...Catch...Finally blocks. We can manage standard exception types or create our own custom types. Every time error occurs inside try block, catch block should catch created exception object and do something to keep application working.

b) Unhandled errors

We get these errors when there is no Try...Catch block to handle an exception. We have three ways to avoid application crash in this case:

   - Page_Error event used in code of every page.

   - Application_Error event used in Global.asax file or with custom http module.

   - customErrors section in Web.config file.

3. Logical errors

These errors actually are not errors for .NET Framework. Web application works fine, code executes, but it doesn't work on the way you wanted. Remember, computer always do what you literally tell it to be done, not what you wanted. Until now, I don't know for any tool that can discover logical errors. Only way to know about them is testing of your application and collecting feedback from your users.

Difference between exception and error in .Net

Error is just an event, something wrong happened. When error event occurs, CLR creates an object of type Exception (located in System namespace. So, error is an event and exception is .Net object. Exception object contains detailed information about an error, like Message, StackTrace, HelpLink etc., to deal with error easier.

System.Exception class properties

Exception class contains a number of properties to make error management easy.

HelpLink Property

Get or sets URN or URL of help file related to this exception. For example:

http://www.yoursite.com/Exceptions/ArgumentNullException.aspx

or, if you don't have separated page for every exception, you can simply direct your users to support page.

InnerException Property

Read only property, returns an instance of previous exception that causes an current exception. You can use this property to find an earlier exception that led to current exception so you can get more information about error. If there is no previous exception than InnerException property returns null in C# or Nothing in VB.NET.

Message Property

Also read only property, returns a description of current exception and sometimes suggestion how to correct an error. This message is also included in ToString() method.

Source Property

Gets or sets object name or application name that causes an error. By default, this property will return name of assembly where error occurred.

StackTrace Property

Read only property, returns a string representation of the frames on the call stack when error occurred. It contains list of methods that executes. This listing can help you to follow the call sequence to the code line where error occurred.

 TargetSite Property

Read only property, returns a method that throws the current exception. If method is not available and StackTrace is null, than TargetSite also returns null. If StackTrace is not null and the method that thrown exception is not available, then TargetSite returns a method from the StackTrace.

Handling Errors in classic ASP

In classic ASP programmers have a possibility to use very basic error handling, like:

On Error Resume Next

After error occurs, code will simply continue execution on next line.

Next method is On Error GoTo which jumps to specific line number in code, for example:

On Error GoTo 20

On Error Resume Next and On Error GoTo are called unstructured error handling. These methods are still available in VB.NET, but they are not part of C#. Although it is possible use it in VB.NET, it is not recommended.  Net Framework offers structured error handling with try-catch-finally blocks and other terrific ways to handle errors in your web application.

In classic ASP developers could use Server.GetLastError. You should still use this in .Net, but now it returns object of System.Exception type.

Handling ASP.NET errors with Try Catch Finally Block

First effort to avoid errors certainly should be writing of solid code. That means to predict when error can occur and avoid it. For example, if you take some input of your users, you can use ASP.NET validator controls to check is input in correct format. Or, if you want to read text file, you can check first if file exists on disc etc.

Try-Catch block is second way used to try fix your application when error occurs.  If you predict that some part of code could cause an error, you can put it inside try block and add recovering code in catch and/or finally parts. Of course, not all errors you can predict. Sometimes, even your catch block will produce an exception :).

You can write zero or more catch blocks. If your try block is not followed by any catch, you must have finnaly block. If you have at least one catch you are not obligated to write finally part. Example below contains both catch and finally parts.

[ C# ]

try
{
  // Here is the code that possibly creates an error
 
}
catch (Exception ex)
{
  // Here is the code that handles an error
  // and tries to recover application
}
finally
{
  // Here is the code executed always,
  // if error is ocurred or not
}

[ VB.NET ]

Try
  ' Here is the code that possibly creates an error
 
Catch ex As Exception
  ' Here is the code that handles an error
  ' and tries to recover application
 
Finally
 
  ' Here is the code executed always,
  ' if error is ocurred or not
End Try

Try-Catch Example

Let's see how try-catch works on very simple example.

[ C# ]

using System;
 
public partial class _Default : System.Web.UI.Page
{
  protected void Page_Load(object sender, EventArgs e)
  {
    int FirstNumber = 10;
    int SecondNumber = 0;
    try
    {
      // In try block, we'll try to divide two numbers
      // That will cause an error because second number
      // is zero
      int Result = FirstNumber / SecondNumber;
    }
    catch (Exception ex)
    {
      // When error occurs, code in catch block will be
      // executed. We will show warning message to user
      Response.Write("<b> Error messsage: </b><br />" + ex.Message);
    }
  }
}

[ VB.NET ]

Imports System
 
Partial Class DefaultVB
  Inherits System.Web.UI.Page
 
  Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
    Dim FirstNumber As Integer = 10
    Dim SecondNumber As Integer = 0
    Try
      ' In try block, we'll try to divide two numbers
      ' That will cause an error because second number
      ' is zero
      Dim Result As Integer = FirstNumber / SecondNumber
    Catch ex As Exception
      ' When error occurs, code in catch block will be
      ' executed. We will show warning message to user
      Response.Write("<b> Error messsage: </b><br />" _
        & ex.Message)
    End Try
  End Sub
End Class

When we start web application code inside of try block will produce an error so code in catch block will be executed. Output will look like image bellow:

Warning message
Catch block will show a warning message

Multiple exceptions in try-catch block

ASP.NET allows multiple catch blocks related to one try block. When you write multiple catch blocks write most specific exceptions first and end with most general System.Exception object. Every derived exception should be before parent exception. Let say we need to show all products from given category to GridView control. Possible errors we can handle with few catch blocks, like in example bellow:

[ C# ]

using System;
using System.Data;
using System.Data.SqlClient;
using System.Configuration;
 
public partial class _Default : System.Web.UI.Page
{
  protected void Page_Load(object sender, EventArgs e)
  {
    SqlConnection conn = new SqlConnection();
    try
    {
      // Code that can generate different kinds of errors
      int ProductCategory =   Convert.ToInt32( Request.QueryString["CategoryID"].ToString());
      string SQLQuery = "SELECT * FROM Products WHERE CategoryID = " +
      ProductCategory.ToString();
      conn.ConnectionString =  ConfigurationManager.ConnectionStrings[ "ConnStr" ].ConnectionString;
      conn.Open();
      SqlDataAdapter da = new SqlDataAdapter(SQLQuery, conn);
      DataTable dt = new DataTable();
      da.Fill(dt);
      GridView1.DataSource = dt;
      GridView1.DataBind();
    }
    catch (NullReferenceException ex)
    {
      // What to do if CategoryID parameter is null
    }
    catch (FormatException ex)
    {
      // If CategoryID parameter is not a number
    }
    catch (SqlException ex)
    {
      // If there is some problem with database
    }
    catch (Exception ex)
    {
      // Handle all unexpected errors
    }
    finally
    {
      // This code will execute every time
      // Close database if open
      if (conn.State == ConnectionState.Open)
        conn.Close();
    }
  }
}

[ VB.NET ]

Imports System
Imports System.Data
Imports System.Data.SqlClient
Imports System.Configuration
 
Partial Class DefaultVB
  Inherits System.Web.UI.Page
 
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
  Dim conn As SqlConnection = New SqlConnection()
  Try
    ' Code that can generate different kinds of errors
    Dim ProductCategory As Integer = _
    Convert.ToInt32(Request.QueryString("CategoryID").ToString())
    Dim SQLQuery As String = _
      "SELECT * FROM Products WHERE CategoryID = " & _
      ProductCategory.ToString()
    conn.ConnectionString = _
    ConfigurationManager.ConnectionStrings("ConnStr").ConnectionString
    conn.Open()
    Dim da As SqlDataAdapter = New SqlDataAdapter(SQLQuery, conn)
    Dim dt As DataTable = New DataTable()
    da.Fill(dt)
    GridView1.DataSource = dt
    GridView1.DataBind()
  Catch ex As NullReferenceException
    ' What to do if CategoryID parameter is null
  Catch ex As FormatException
    ' If CategoryID parameter is not a number
  Catch ex As SqlException
    ' If there is some problem with database
  Catch ex As Exception
    ' Handle all unexpected errors
  Finally
    ' This code will execute every time
    ' Close database if open
    If conn.State = ConnectionState.Open Then
      conn.Close()
    End If
  End Try
End Sub
End Class

.Net Exception Types

There are hundreds of exception objects in .Net framework. All .Net exceptions are inherited from System.Exception class. To browse existing exceptions, go to Debug -> Exceptions... in Visual Studio menu, like in image bellow:

Debug - Exceptions... in Visual Studio menu

New window will appear, with a list of different types of exceptions:

 

How to throw an exception in ASP.NET

In some scenarios, you may wish to throw an exception. For example, in your catch block you can try to recover from the exception. If you don't success, then you can throw an exception again so exception will be caught by higher level, like Application_Error procedure in Global.asax file. We can do that by using a throw keyword, like in example bellow. Try block will throw an exception and catch block will handle it:

[ C# ]

using System;
 
public partial class _Default : System.Web.UI.Page
{
  protected void Page_Load(object sender, EventArgs e)
  {
    try
    {
      // Throw new exception
      throw new AccessViolationException();
    }
    catch (AccessViolationException ex)
    {
      // Handle an error with catch block
      Response.Write("<b> Error message: </b><br />" + ex.Message);
    }
  }
}

[ VB.NET ]

Imports System
 
Partial Class DefaultVB
  Inherits System.Web.UI.Page
 
  Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
    Try
      ' Throw new exception
      Throw New AccessViolationException()
    Catch ex As AccessViolationException
      ' Handle an error with catch block
      Response.Write("<b> Error message: </b><br />" _
        & ex.Message)
    End Try
  End Sub
End Class

Page_Error event

If you did not catch some exception with Try...Catch block, you can still do it by using Page_Error event. This event will handle every unhandled error on page. To get exception object which invoked Page_Error event you need to use Server.GetLastError() method. GetLastError() method returns Exception object which contains all information about an error. Page_Error procedure could look like this:

[ C# ]

protected void Page_Error(object sender, EventArgs e)
{
  // Get current exception
  Exception CurrentException = Server.GetLastError();
 
  // Now do something useful with exception, like recover from error or
  // send notification e-mail or write log to text file,
  // database, Windows EventLog etc.
  string ErrorDetails = CurrentException.ToString();
  SendEmailToAdmin(ErrorDetails);
 
  // If you want to avoid execution of Application_Error
  // or going to customErrors level use this line
  Server.ClearError();
}

[ VB.NET ]

Protected Sub Page_Error(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Error
  ' Get current exception
  Dim CurrentException As Exception = Server.GetLastError()
 
  ' Now do something useful with exception, like recover from error,
  ' send notification e-mail or write log to text file,
  ' database or Windows EventLog etc.
  Dim ErrorDetails As String = CurrentException.ToString()
  SendEmailToAdmin(ErrorDetails)
 
  ' If you want to avoid execution of Application_Error
  ' or going to customErrors level use this line
  Server.ClearError()
End Sub

ASP.NET Error Handling Remarks

There is always a possibility to create error in your error handling code. In that case you need avoid infinitive loop. For example, if your Page_Error procedure contains an error it will call itself again and again because this procedure is executed every time when error occurs. Similar problem is if error is on application level, inside Application_Error procedure or in custom http module.

This tutorial covers error management on page level with try-catch-finally blocks or with Page_Error procedure, but ASP.NET provides more. Next level is application level, where you need to use Web.config customErrors section and Application_Error event. Application level is used mostly for error logging or sending notification e-mails to administrator. Read more about this in Application Level Error Handling in ASP.NET tutorial.


Tutorial toolbar:  Tell A Friend  |  Add to favorites  |  Feedback  |   Google


comments powered by Disqus