First time here? Check out the site's "greatest hits" or read a post from the archives. Feel free to leave a comment or ask a question, and consider subscribing to the latest posts via RSS or e-mail. Thanks for visiting!
« Hanselminutes Podcast 31 - Test Driven D... | Main | SOLVED: How to Force IIS to load a certa... »

I was coming up with Good Exception Management Rules of Thumb for .NET. Here's what my brainstorming came up with. What do you have as good Rules o' Thumb?

  • Exceptions are exceptional and should be treated as such. If something exceptional, unusual, or generally "not supposed to ordinarily happen" then an exception is a reasonable thing to do.
    • You shouldn't throw exceptions for things that happen all the time. Then they'd be "ordinaries".
  • If your functions are named well, using verbs (actions) and nouns (stuff to take action on) then throw an exception if your method can't do what it says it can.
    • For example, SaveBook(). If it can't save the book - it can't do what it promised - then throw an exception. That might be for a number of reasons.
  • If you can, throw an exception that means something, and if there's an exception that already exists that matches what happened semantically, throw that.
    • Don't create a HanselmanException just because you're writing the Hanselman module unless you're adding data or valuable semantics to the type.
      If you are building a framework (or even if you're not) throw ArgumentExceptions and ArgumentNullExceptions liberally. Just as your method should throw if it can't do what it promised, it should throw if you supplied it with crap input.
  • If something horrible happens (something exceptional) then you need to decide if you can keep going.
    • Don't catch exceptions you can't do anything about. It's likely if you could do something about it, it wouldn't be exceptional, and you might consider calling TryParse, or File.Exists, or whatever it takes to prevent that exception.
  • There are reasons to swallow exceptions (catch (Exception ex)) but they are few and far between and they should be logged if appropriate and documented liberally.
    • Remember always if you do catch an exception and intend to rethrow it, then use throw; not throw ex; lest you lose your call stack and good bits of context.
  • Create a global error handler that logs everything.
    • A user shouldn't ever see an exception dialog or ASP.NET Yellow Screen of Death, but if they do, let them know that you've been notified.
    • {smartassembly} is an easy way to make this happen. So is ELMAH for ASP.NET. (I freakin' love ELMAH)
  • Yes Response.Redirect in ASP.NET causes an internal exception. Yes, it's a bummer, but there's a reason. It was an easy way to stop execution. If you don't like it, call its overload and stop page execution yourself. Personally, I don't sweat that one, but then I avoid Redirects, too.
Tracked by:
"Exception Management Rules" (Commonality) [Trackback]
"Interesting Finds: August 30, 2006" (Jason Haley) [Trackback]
"Exception Handling: A Good Set of Reminders" (Patrick Altman) [Trackback]
"To throw or not to throw!" (Matt's Blog) [Trackback]
"Exception Management Rules" (Gustavo Echeverry's Blog) [Trackback]
"Event Testing Tools can Fall into the Trap" (Commonality) [Trackback]
"Vuistregels voor het omgaan met Exceptions" (Microsoft Enterprise Solutions Blo... [Trackback]
"Make Exception Classes Serializable" (Commonality) [Trackback]


Wednesday, August 30, 2006 3:38:53 PM (Pacific Standard Time, UTC-08:00)
I'd probably mention that there is a difference between how you handle exceptions when writing a library vs writing an application. For example, a library should generally just propagate exceptions unless it's absolutely sure it can handle it in the best way possible.

Applications can often catch exceptions and provide the user a means to correct an action. But in either case, if the code can't handle the exception, don't even catch it.

Retry logic in a library when an exception occurs, for example, can be a bad idea. Let the consumer choose what to do with the exception.

If you do create your own exceptions, don't derive ApplicationException. Derive from Exception. In a library, if you need to derive from a more specific Exception such as ArgumentException, consider the fact that existing clients that are catching ArgumentException will catch your new exception, but maybe shouldn't be.
Wednesday, August 30, 2006 4:20:15 PM (Pacific Standard Time, UTC-08:00)
Great list Scott. How about:

* Catch exceptions at boundaries, for example WCF (wrap exceptions in FaultException), WSE (wrap exceptions in SoapException)
* Make custom exceptions serializable
Wednesday, August 30, 2006 4:53:18 PM (Pacific Standard Time, UTC-08:00)
I write a number of Windows services and I always ensure that my main processing thread and any functions that are invoked in a managed thread pool always have a generic catch(Exception ex) in with proper logging of the exception. An unhandled exception at those levels could easily cause the service to shutdown unexpectedly. The program (especially if it has no front end) should always catch any error that may cause it to shutdown and recover from it (ie, if it is a server program, just disconnect the user or something to ensure it can continue running).
Wednesday, August 30, 2006 5:49:34 PM (Pacific Standard Time, UTC-08:00)
Scott,

Here's another interesting blog post on this topic.

http://codebetter.com/blogs/karlseguin/archive/2006/04/05/142355.aspx
Wednesday, August 30, 2006 8:22:12 PM (Pacific Standard Time, UTC-08:00)
DavidB - Excellent! I like "catch exceptions at boundaries" - catchy and common sense. Good stuff.
Scott Hanselman
Wednesday, August 30, 2006 8:44:47 PM (Pacific Standard Time, UTC-08:00)
For libraries mostly: Create a static, internal ExceptionHelper class and put all the logic for the default exceptions (ArgumentNullException, ArgumentOutOfRangeException, InvalidOperationException, etc.) in that class.

It makes methods more readable, especially if there are three arguments to a method, all with restrictions. And you save lots of typing.

The common ones I use:

ThrowIfObjectNull(object o)
ThrowIfStringIsNullOrEmpty(string s)
ThrowInvalidOperationException(bool condition)

You can get pretty fancy with these. For example, Brad Abrams and Krzysztof Cwalina recommend putting all of your custom exception messages in resx files. So I do that, 'cause I'm anal and we may have to internationalize some time.
Wednesday, August 30, 2006 9:23:33 PM (Pacific Standard Time, UTC-08:00)
if you have to throw an exception from inside an exception handler, always remember to include the existing exception as an inner exception.
e.g.
catch (ArgumentException ex))

if (can handle it) {...
//handle it
} else {
throw new exception("a genuinely useful description taking into consideration the fact that sometimes we *can* handle this kind of exception, describing the known facts before making suggestions/jumping to conclusion", ex);
//note that ex is passed to the inner exception parameter, so that the stack trace etc isn't /lost/ lost.
}
Thursday, August 31, 2006 1:50:49 AM (Pacific Standard Time, UTC-08:00)
Exceptional list of pointers...

...(urg) sorry!, couldn't resist
DC
Thursday, August 31, 2006 5:06:51 AM (Pacific Standard Time, UTC-08:00)
Regarding the .TryParse/File.Exists rules, I like to shorten it to:

"Don't pee your pants to see if your fly is unzipped"
Thursday, August 31, 2006 6:38:48 AM (Pacific Standard Time, UTC-08:00)
"You shouldn't throw exceptions for things that happen all the time. Then they'd be 'ordinaries'.
"...throw an exception if your method can't do what it says it can."

If you have "ordinary" failure cases that crop up so often that exception handling is harming your performance enough to be a problem, you should add a function with a different name that can fail without throwing an exception (and whilst still completing its "verb").

E.g. The case where a string containing non-numeric data was passed to Double.Parse() turned out to be common enough that they added Double.TryParse().

That tip came from Jason Clark at DevWeek 2006. He gave a great talk about exceptions. His rules were about the same as yours.

He related an interesting titbit from the CLR team. Apparently they are somewhat sorry that they implemented CLR exceptions using SEH (which is what makes them slow). They told him there is no reason they have to be done that way, and they will seriously think about reimplementing them fi they ever become "one of our customers' top 5 real-world performance issues". :-)
James Chaldecott
Friday, September 22, 2006 1:35:19 PM (Pacific Standard Time, UTC-08:00)
I'm curious about your last point. Why do you avoid redirects?
Friday, September 22, 2006 3:21:47 PM (Pacific Standard Time, UTC-08:00)
I'm curious about your last point as well. I think I understand why, but not so much how. It seems impossible to avoid Redirects completely. Could you talk about this more?
Smoke
Friday, September 22, 2006 3:41:24 PM (Pacific Standard Time, UTC-08:00)
I'm saying that I like to avoid this:

* Load, click, postback, immediate redirect to next page

I like:

* Load, click, postback, show next page (either via Transfer or via a Panel/Workflow
Comments are closed.

Contact

Sponsors

Hosting By

On this page...

Tags

Calendar

<November 2008>
SunMonTueWedThuFriSat
2627282930311
2345678
9101112131415
16171819202122
23242526272829
30123456

Archives

Google Ads