views:

244

answers:

7

Hi,

I am working on application where user invokes a method from UI , on this I am calling a method from business class which calls another methods

UI--> Method1 -->Method2 --> Method3

I want to display the error message to user if any exception occurs in any of the method.

Shall I go with throwing the exception directly to the caller method and at the UI layer I will catch exception and display the message.

Apart from Throwing exceptions and catching it at caller is there any better way to handle it?

I do not want to use the C++ convention where integer is returned as the result.

+15  A: 

If you can't recover from the exception in the method where the exception happens, don't try to catch it (unless you want to log it, in which case throw it again after logging). Then catch at the UI-level.

Trying to catch exceptions at every level just adds bloat to your code.

Dr Herbie
Even if you can't recover from the exception you might be able to add more information about the error, e.g. which key the update failed for. Should you then throw a new custom exception with the new information or use return codes to propagate the error to the caller?
adrianm
I think that's s design decision that works either way. Exceptions are expensive, so handling return codes would give better performance where it matters, but if you've already got exception handling code set up at the UI end then using exceptions means that you only have to cater for one error mechanism, rather than two.
Dr Herbie
A: 

As a rule of thumb, exceptions should only be used for exceptional cases. That is, if you expect a method call to fail sometimes, you shouldn't use exceptions. If there are several possible outcomes, you could use an enumeration:

public enum AddCustomerResult
{
    Success,
    CustomerAlreadyExists,
    CustomerPreviouslyRetired
}

You'd still get exceptions thrown, for database-unavailable errors, and the like; but you'd be testing for expected (albeit possibly rare) cases and indicating success/failure/etc as required.

This is just one technique that works well for me.

With exceptions you want to throw them in exceptional circumstances and anywhere where there is a layer traversal (my own convention, don't know how correct it is) you'd want to catch exceptions and rethrow with a custom wrapper class for that layer.

For example, in the DAL you'd want to catch exceptions and rethrow them as an inner exception on a DataAccessException perhaps; on a web service you'd wrap all your methods in exception handlers to rethrow with a MyWebServiceException. At the UI (which traverses the from inside the app to the user's screen) you'd want to catch, log and give them a nice message. As far as I can see no reason to catch or rethrow anywhere else.

It gives you an opportunity to hide the underlying exception (which you likely don't want to expose to the caller: e.g. database errors), log in centrally, and provide a common repeatable failure mode.

In your example, you'd catch exceptions at the UI level only; because if a UI operation fails you don't want the app to crash out with an unhandled exception.

Hope that helps!

Kieren Johnstone
+3  A: 

The basic rule is "Don't catch exceptions when you cannot handle it." So any unexpected exception should ultimately tell the user that something went wrong and shut down the application as gracefully as possible. Not shutting down the application is risky because the state might be corrupted and in turn corrupt information important to the user.

Robust applications are modular so that the application can recover without shutting down by stopping or restarting single components like services or plugins.

There are some cases where you might want to catch exceptions that you cannot handle but then the exception should either be re-thrown or a new exception should be thrown.

If you want to log exceptions you will catch, log and re-throw.

If you want to improve the error message you will catch, wrap in a new exception, and throw. For example you may want to wrap a generic FileNotFoundException when reading a file in a new exception with a more descriptive message telling the user what file could not be found.

Daniel Brückner
+2  A: 

Whatever you decide - be consistent. 30 days from now yourself (or another developer) will need to understand your code.

Also, as Scott Hanselman likes to quote on his podcast (and I think it might be in the Beautiful Code book) -

All problems in computer science can be solved by another level of indirection," is a famous quote attributed to Butler Lampson, the scientist who in 1972 envisioned the modern personal computer.

Throwing exceptions is expensive. And I like to have my business layer have its own specialized exception that only it can throw. That way it makes it easier to track it down. For example (off the top of my head since I do not have a C# compiler in front of me):

public class MyException : Exception
{
   private MyException(Exception ex, string msg) {
       this.Message = msg;
       this.InnerException = ex;
   }

   internal static MyException GetSomethingBadHappened(Exception ex, string someInfo) {
      return new MyException(ex, someInfo);
   }
}
Kris Krause
A: 

When you design a multi-tier application, you should keep in mind that those tiers can be distributed, maybe hosted within different services on different machines, thus making it necessary to throw exceptions through remote boundaries which is not a very preferable way to do. In such a case, catching them and just bubbling some sort of error message or code is a better way in my opinion. Additionally you should allways trace the exception when you catch it. Its always good to know whats going on in your application.

oldbread
A: 

It almost always pays to separate exception handling and error reporting.

Catch exceptions where it makes sense to catch them, where you have enough context to know what exactly happened and how to recover - inside Method1..3. On catching known exception, push a record to the error log.

After completing operation or step UI level can check error log and present message of "Following errors occurred: ...".

ima
+1  A: 

Given your example of UI--> Method1 -->Method2 --> Method3, I would make sure that the UI has a try/catch, but then none of the other methods should catch exceptions unless they can handle them without re-throwing. And even if they handle the exception, you should question whether that exception should happen in the first place. If you handle an exception and go about your merry way, then that exception is part of your normal process flow which is a serious code smell.

Here are my recommendations:

1) Put your exception handling code in all your UI events, and then have the actual action farmed off to some other method. Don't scatter exception handling code all over the place. It's clunky and makes the code hard to read.

protected void Button1_Click(object sender, EventArgs e) {
   try {
      DoSomething();
   }
   catch Exception e {
      HandleError(e);
   }
}

2) Don't do this. You'll lose your stack trace and the next developer who maintains your code will hunt you down.

try {
   DoSomething();
}
catch Exception e {
   throw e; // don't rethrow!!!
}

If you aren't going to handle the exception, don't catch it. Or, use a naked throw like this:

try {
   DoSomething();
}
catch SomeException e {
   HandleException(e);
}
catch {
   throw ; // keep my stack trace.
}

3) Only throw exceptions in exceptional circumstances. Don't have try/catch blocks as part of your normal process flow.

4) If you're going to throw an exception, don't ever throw a System.Exception. Derive an exception object and throw it. I often just a generic BusinessException class. This way, users of your code can determine what exceptions you made up and which ones are system/environment related.

5) Throw ArgumentException, ArgumentNullException, or ArgumentOutOfRangeException if a method caller violates the contract (preconditions) of your method. If you catch one of these, it's a programming bug. A user should never see these exceptions.

If you remember that exceptions should be a very rare occurrence and that handling them is almost always a UI concern (so the bulk of your try/catch code should stay at the UI level) you will do well.

mattmc3