If in code you are reporting an exception then you will have one or both of the following use cases in mind:
- An end user being able to look at the error details and solve the problem.
- The exception information being sent to you or a developer colleague to look at and resolve the problem.
For users you want a simple and descriptive message that tells the user what went wrong and how to fix it. The following would be a good example:
The employee 'Frank' was not found in the database.
This tells the user why the error occurred and implies possible solutions (e.g. enter a different name or add the employee to the database). By including the name in the error the user can see if it is correct (maybe they typed it incorrectly) and by putting quotes around it even if the name is blank the user can see that it was blank.
For developers however we want as much information as possible including full stack traces and the very original exception that was thrown so we can start investigating as close to the source of the problem as possible.
Looking at these two use cases they appear to be competing, if we display all the exception details including inner exceptions and stack traces to an end user then even if there is a useful error message in there they will most likely look at the entire lot, panic and send it to you. If however you only display the outer-most exceptions message then if it is not something obvious (e.g. it could be a generic null reference exception for example) the user will send it to you anyway and you will have a horrible time trying to track down where it is coming from.
The solution I have used many times now is to have a custom exception dialog that when first displayed shows only the outer-most exceptions message but that has a "Show Details" button which shows the full exception output (including stack traces and all inner exceptions).
Tip: To show the full exception details including all inner exceptions and stack traces you can simply call .ToString() on the exception.
This gives the best of both worlds and I find works very well. It means that if an exception is thrown with a user resolvable error message you don't even hear about it and the user is happy because they didn't have to wait for you in order to finish what they were doing. If however an exception is thrown that the user does not understand they can give you the full details and you can hopefully work out what is going on pretty quickly, saving you time and thus keeping the user happier.
Remember that whenever you catch an exception and then throw a new exception with more context or a meaningful message, you should always include the exception that you caught as the inner exception. Take our example above where we have thrown an exception saying "The employee 'Frank' was not found in the database.". This could be correct but what if Frank is in the database? The user will then send you the error details and tell you "but Frank exists". It may be that the database has gone offline or the system is connecting to the wrong database or something else entirely. If you have the inner exceptions you will hopefully be able to see that immediately and then quickly rectify the problem. Without the inner exceptions you are far more likely to end up spending ages trying to track down the problem.
When reporting an exception to a user there are some types that we may want to show the message from an inner exception as it is more likely to help the end user. For instance the TargetInvocationException, this has the message "Exception has been thrown by the target of an invocation." and occurs when you call a method using reflection that throws an exception. Obviously this exception has an end user unfriendly message and is also fairly generic, however the exception that was actually thrown by the target may have a very end user friendly message. What I do for exceptions like this is look to see if they have an inner exception and if so display the message from that exception to the user. It is still useful to include all the exceptions in the "show details" view however as it may help you or another developer track down an issue faster.