Everything about Web and Network Monitoring

Home > Industry Info > Application Performance Management > Improving ASP.NET Performance Part 14: Exception Management

Improving ASP.NET Performance Part 14: Exception Management

In our last article in the ASP.NET series we discussed String Management. In this article we’ll address the best practices for Exception Management. Exceptions are expensive. By knowing the causes of exceptions, and by writing code that avoids exceptions and that handles exceptions efficiently, you can significantly improve the performance and scalability of your application.

 

Best practices and Guidelines

When you design and implement exception handling, consider the guidelines in the sections below to ensure optimum performance:

Implement a Global.asax Error Handler

The first step in managing exceptions is to implement a global error handler in the Global.asax file or in the code-behind file. Implementing a global error handler traps all unhandled exceptions in your application. Inside the handler, you should, at a minimum, log the following information to a data store such as a database, the Windows event log, or a log file:

·         The page that the error occurred on

·         Call stack information

·         The exception name and message

In your Global.asax file or your code-behind page, use the Application_Error event to handle your error logic, as shown in the following code sample:


public void Application_Error(object s, EventArgs ev)

{

   StringBuilder message = new StringBuilder();

   if (Server != null) {

     Exception e;

     for (e = Server.GetLastError(); e != null; e = e.InnerException)

     {

        message.AppendFormat(“{0}: {1}{2}”,

                             e.GetType().FullName,

                             e.Message,

                             e.StackTrace);

     }

     //Log the exception and inner exception information.

  }

}

Monitor Application Exceptions

To reduce the number of exceptions occurring in your application, you need to effectively monitor your application for exceptions. You can do the following:

·         If you have implemented exception handling code, review your exception logs periodically.

 

·         Monitor the # of Exceps Thrown / sec counter under the .NET CLR Exceptions Performance Monitor object. This value should be less then 5 percent of your average requests per second.

Use Try/Finally on Disposable Resources

To guarantee resources are cleaned up when an exception occurs, use a try/finally block. Close the resources in the finally clause. Using a try/finally block ensures that resources are disposed even if an exception occurs. The following code fragment demonstrates this.


try

 

{

 

   conn.Open();

 

  

 

}

 

finally

 

{

 

   if(null!=conn)

 

     conn.close;

 

}

Write Code That Avoids Exceptions

The following is a list of common techniques you can use to avoid exceptions:

·         Check for null values. If it is possible for an object to be null, check to make sure it is not null, rather then throwing an exception. This commonly occurs when you retrieve items from view state, session state, application state, or cache objects as well as query string and form field variables. For example, do not use the following code to access session state information.


try {

 

  loginid = Session["loginid"].ToString();

 

}

 

catch(Exception ex) {

 

  Response.Redirect(“login.aspx”, false);

 

}

 

Instead, use the following code to access session state information.

 

if(Session["loginid"]!=null)

 

  loginid = Session["loginid"].ToString();

 

else

 

  Response.Redirect(“login.aspx”, false);

·         Do not use exceptions to control logic. Exceptions are just that — exceptions. A database connection that fails to open is an exception. A user who mistypes his password is simply a condition that needs to be handled. For example, consider the following function prototype used to log in a user.


public void Login(string UserName, string Password) {}

 

The following code is used to call the login.

 

try

 

{

 

  Login(userName,password);

 

}

 

catch (InvalidUserNameException ex)

 

{}

 

catch (InvalidPasswordException ex)

 

{}

 

It is better to create an enumeration of possible values and then change the Login method to return that enumeration, as follows.


public enum LoginResult

 

{

 

  Success,InvalidUserName, InvalidPassword, AccountLockedOut

 

}

 

public LoginResult Login(string UserName, string Password) {}

 

The following code is used to call Login.

 

LoginResult result = Login(userName,password)

 

switch(result)

 

{

 

  case Success:

 

   . . .

 

  case InvalidUserName:

 

   . . .

 

  case InvalidPassword:

 

}

·         Suppress the internal call to Response.End. The Server.Transfer, Response.Redirect, Response.End methods all raise exceptions. Each of these methods internally call Response.End. The call to Response.End, in turn, causes a ThreadAbortException exception. If you use Response.Redirect, consider using the overloaded method and passing false as the second parameter to suppress the internal call to Response.End.

·         Do not catch exceptions you cannot handle. If your code cannot handle an exception, use a try/finally block to ensure that you close resources, regardless of whether an exception occurs. Do not catch the exception if you cannot try recovery. Permit the exception to propagate to an appropriate handler that can deal with the exception condition.

Set Timeouts Aggressively

Page timeouts that are set too high can cause problems if parts of your application are operating slowly. For example, page timeouts that are set too high may cause the following problems:

·         Browsers stop responding.

·         Incoming requests start to queue.

·         IIS rejects requests after the request queue limit is reached.

·         ASP.NET stops responding.

The default page timeout is 90 seconds. You can change this value to accommodate your application scenario.

Consider the following scenario where an ASP.NET front-end application makes calls to a remote Web service. The remote Web service then calls a mainframe database. If, for any reason, the Web service calls to the mainframe start blocking, your front-end ASP.NET pages continue to wait until the back end calls time out, or the page timeout limit is exceeded. As a result, the current request times out, ASP.NET starts to queue incoming requests, and those incoming requests may time out, too. It is more efficient for your application to time out these requests in less than 90 seconds. Additionally, timing out the requests in less than 90 seconds improves the user experience.

In most Internet and intranet scenarios, 30 seconds is a very reasonable timeout limit. For high traffic pages such as a home page, you might want to consider lowering the timeout limit. If your application takes a long time to generate certain pages, such as report pages, increase the timeout limit for those pages.

Ard-Jan Barnas

About Ard-Jan Barnas

Ard-Jan is a highly technical writer with deep knowledge into the industry. He has an international background and always brings forth articles that are not just technical but with a mix of business application. This encompassing approach to technology married to business is a welcome approach to writing.