Tired of looking for errors in log files? Use OneTrueError - Automated exception management in .NET.

Do NOT catch that exception!

Ohhh, I’ve recently seen one to many application where the developer try to be safe by catching exceptions all over the place. It can be everything from a small simple method that doesn’t throw that many exceptions to a large method with multiple try/catch statements. Most of those catch blocks just logs the exception and rethrow it.

Please do not catch that exception. Let it travel down the call stack. I promise you that you won’t regret it. You’ll get a warm and fuzzy feeling next time you’ll test your application. I promise you! Really!

Why? You’ll get a complete exception with all the details you need to fix the error, it’s very easy to loose information if you catch/wrap/rethrow exceptions . The problem with all of those try/catch blocks is they doesn’t help your application in any way. They just clutter up the code and your log files.

If you still want to catch exceptions: I’ll try to explain the way to do it.

Catching exceptions in the correct way.

Yeah. Proper exception handling can be something wonderful. You’ll smile every time you get an exception. First of all: Exceptions only happens when something exceptional occurs.  Please have that in mind, because it helps you remember that you don’t need those try/catch block everywhere.

That brings us to the golden rule about when to catch exceptions:

Only catch exceptions that you can handle to rescue the situation.

That means that you should only catch exceptions if you, by handling it, can let the application continue as (almost) expected. Let me rephrase that: Only catch a exception if you, by catching it, can let the method return a result as promised.

There are of course exceptions, namely two of them:

Do not let layer specific exceptions propagate up the call stack.

For instance, if the data layer fails and throws a SqlException (if you are using Sql Server) you should catch it and wrap it inside a more generic exception. Create a DataSourceException which could be used even if you switch data source from a database to a Web Service. You should of course add details to the exception such as the method name, parameters or anything else that can be useful. Do NOT forget to add the original exception as  inner exception.

public class UserRepository : IUserRepository
{
    public IList<User> Search(string value)
    {
        try
        {
              return CreateConnectionAndACommandAndReturnAList("WHERE value=@value", Parameter.New("value", value));
        }
        catch (SqlException err)
        {
             var msg = String.Format("Ohh no!  Failed to search after users with '{0}' as search string", value);
             throw new DataSourceException(msg, err);
        }
    }
}

Update 2013-03-01: I’m not following this rule any more. The only time I wrap exceptions is if I add more context information to help me prevent the exception in the future. It doesn’t really matter if the data layer exception is passed up the call stack, since it won’t be handled but just logged in the top layer

If you don’t want to display data layer specific information to the user, then simply display something like "An unexpected error occurred" instead of showing exception information. The exception information doesn’t really help your user either way.

Try/Catch all is OK in the layer closest to the user.

Ok, so you have let the exceptions propagate through all your layers to the presentation layer (winforms/asp.net etc). Fine. Go ahead, give the user some fancy error pages. Also log those errors. But just don’t log them. Notify a support team. Send an email to the project lead.

When everything else fails

Are you not sure that your new exception policy will catch all of those exceptions? Is it scary? The I got the solution for YOU!

Asp.Net Implement Aplication_OnError(object source, EventArgs e) in your global.asa. It will be called for all unhandled exceptions.
WinForms Subscribe on Application.ThreadException
WinServices Subscribe on AppDomain.CurrentDomain.UnhandledException. The problem with this event is that it will still terminate the application. But there’s a way around that too.
WCF WCF: Implement IErrorHandler and log the exceptions in it (added 2013-03-01).
ASMX ASMX: Create a custom Soap Extension. (added 2013-03-01).

In the next blog post I’ll discuss common mistakes in those catch blocks and how your tailor made exceptions should look like.

Update 2013-04-17

I’ve written a new exception series. Starting with What are exceptions?

This entry was posted in Architecture, CodeProject and tagged . Bookmark the permalink.
  • http://www.cuttingedge.it/blogs/steven Steven

    I wholeheartedly agree with you. Nothing more to add.

  • Peter

    My application has events raised by thrid party coponents which arrive on a listening thread. The application also employs the Application Framework. I’ve never had any success with trapping the Application.ThreadException event and (I think) the Framework interferes with this event. The Framework’s generic UnhandledException event soes not seem to catch excpetions raised on other events. As a result of all of this I tend to wrap each event in a Try Catch block so I can cath and log exceptions for diagnostic purposes. I know this is inefficient but – what to do? I’d be grateful if your next blog post would address this dilemma.

  • Pingback: When to throw exceptions jgauffin's coding den

  • Peter

    I think your update should be at the top of this article

    • JonasGauffin

      fixed.

  • Victor Dzundza

    Thanks !