3

My software uses Try Catch to catch errors; recently an error occurred (a timeout connection to the database) and a Messagebox.Show() pops up alerting the user of the issue. The end users of this in house software are not IT literate at all. The lady who received this message asked me with whom she had lost a connection with (I honestly think she thought it was a spiritual 'connection' since she looks like a hippy).

So what I would like to do is simplify the error messages.

Things I've considered:

I could check/compare the ex.Message string to a list of strings I want to cater for and if it matches one I will display the simplified version. IMO, not realistic.

I then thought having multiple catches, and if it's of a certain type, to display the simple message. But how messy is my code going to be! Not only that, it's also probably going to end up with misleading messages as not all (eg) TimeOutExceptions are the same.

Or, I have to try and write my own Exception type to cater for this.

I then though it would be really handy if each .NET exception had an associated ID - that way, I could write a nice case statement with each ID and my own nice and easy to ready/understand message.

Has anyone else considered this before and did they find any suitable arrangements. Or is it better to just put a message on screen saying "Error - an email has been sent to the software vendor...")?

Dave
  • 8,163
  • 11
  • 67
  • 103

4 Answers4

3

You should never display Exception.message to end users. This is informational text that helps to identify the kind of error.

Anytime you catch the exception, you are supposed to handle it properly or rethrow/throw another. If you are at the point of code that handles the exception by displaying some error message, you should be able to infer the context properly from the Exception itself. You can use proper exception types to create some basic exception domain (DatabaseException, CommunicationException) and the use error codes that discriminate the exception further within its domain.

You can use Data property which belongs to Exception class and is type of IDictionary, thus serving as Exception state bag. You can then store here something like 'ERR_CODE' = CONSTANT and have some single point of exception handling that will check the error code and if it's present, handle the exception with some user friendly output.

You can even register global exception handler within current AppDomain to catch any uncaught exception and display some message. This is common practice, but you must be aware that this approach breaks the natural code-flow and if such thing happens, you are left with handled exception but non-caught exception flow (you didn't handle the exception on the caller site which then doesn't know that the call failed and may behave unpredictable). So use this approach only by printing some user friendly message and ending application or terminating current Usecase.

Martin Macak
  • 3,507
  • 2
  • 30
  • 54
2

If ever you write code like catch (Exception ex) then you are doing something wrong. You should always catch specific exceptions for coding situations that are exceptional.

Have a read of Eric Lippert's "Vexing exceptions" blog entry.

Catching exceptions and just displaying the message is in the "boneheaded" category of exceptions. You should never have them.

Instead you should only have exceptions of the other three types expounded by Eric. And you should catch the specific exception type involved, not the generic Exception type.

If you catch specific exceptions then you can present a very reasonable message to the end user - even providing information about how to solve the problem.

Better still, without all the generic exception catching your code will be easier to debug, cleaner and more terse. The major predictor for bugs in code is the actual lines of code you write. Write less code and have less bugs.

So my suggestion is change your code design and handle the exceptions appropriately.

Enigmativity
  • 113,464
  • 11
  • 89
  • 172
  • 1
    I agree with what you wrote, but your first sentence is a bit strong IMO; is it not useful to know that the fault is fatal (as per Eric's blog). For example, logging: catch(Exception ex) { Logging.Log(ex); throw ex; } Would you still think it's best to avoid Exception ex? Or is your point just about displaying the message on screen? – Dave Oct 25 '12 at 08:26
  • 4
    I use catch (Exception ex) quite often and theres nothing wrong with it, as long as i make sure i catch more specific errors before that. Especially even an Exception (of type System.Exception) is catched i have a good chance to go on with the program, when i know i am in an defined state. – TGlatzer Oct 25 '12 at 08:27
  • @DaveRook - I think it is best to avoid catching plain exceptions all the time. If, in the try block, an unexpected exception fires and you just log it and continue with your app then you have potentially corrupted the `AppDomain` or at the very least you are masking a bug. It creates errors not solves them. – Enigmativity Oct 25 '12 at 08:38
  • @Grumbler85 - Not at all. It's the unexpected exceptions that will kill you. As I just mentioned to David, an exception can kill the `AppDomain` so just merrily moving forward can really cause issues with your program. Exceptions can lead to a very "undefined" state in your app and it takes as much thinking to know that catching `Exception` is safe as it does in catching the specific exceptions that could occur. It's lazy coding to just catch `Exception`. Sorry. – Enigmativity Oct 25 '12 at 08:40
  • @Enigmativity could you please look at my comment again - the point of the code is that it logs an error and then throws the exception (and so the app won't continue). Or, for you (and your style of programming), would you still try to avoid it (sorry if this sounds like the same question again). – Dave Oct 25 '12 at 08:43
  • @Enigmativity - i'm not lazy, but sometimes i just don't care about the results especially if i'm iterating over lists. Sometimes saying "well i don't care about the single instance in this iteration" is just the desired behaviour. And if i think about programming against AD or LDAP there's a vast list of Exceptions i would have to list, isn't it? – TGlatzer Oct 25 '12 at 08:45
  • 1
    Ah, sorry @DaveRook, I meant to address that. When an exception is created you get all sorts of useful stack tracing information in the exception. Throwing it again looses that useful stack trace. You should always throw a new exception and place the current one as its `InnerException`. Best to make something like a `LoggedException` so you can then get the stack trace for where your exception was thrown. – Enigmativity Oct 25 '12 at 08:46
  • 1
    I'm sorry I can only give that comment +1 (and not more!)... This is a great idea, thank you. – Dave Oct 25 '12 at 08:47
  • @Grumbler85 - I'd rather explicitly list all of the possible exceptions, knowing exactly what I'm dealing with, no matter how many that might be, rather than cross-my-fingers and hope I don't write buggy code that throws an unexpected and/or fatal exception. Try writing some code that causes a `StackOverflowException` and see what happens to your program. – Enigmativity Oct 25 '12 at 08:50
  • @DaveRook - Thanks. I appreciate the +1 for the comment. – Enigmativity Oct 25 '12 at 08:51
  • @Enigmativity I just did so - and guess what? My application (Console app) said: "Terminated due to Stackoverflow Exception" Isn't that nice? To throw it I iterated over elements with non-ending recursion. – TGlatzer Oct 25 '12 at 09:35
2

In general, you will need to handle the exception by its type (e.g. catch (SomeSpecificException))

Certain derived exception types do have additional codes, e.g.

e.g. SqlException has a Number property which can be used for control flow / information

catch (System.Data.SqlClient.SqlException sqlEx)
{
  if (sqlEx.Number == 1205) // Deadlock
     ...
  if (sqlEx.Number == -2) // = TimeOut
     ...
  // etc.
}

Edit

Actually, System.Exception does have a protected HRESULT property. See How do I determine the HResult for a System.IO.IOException? and How to get Exception Error Code in C#

Although it isn't directly accessible, you can retrieve it via Marshal.GetHRForException(ex). Different exceptions have different HRESULTs, e.g.

System.Exception :  HRESULT COR_E_EXCEPTION (0x80131500)
System.SystemException : HRESULT COR_E_SYSTEM (0x80131501)

That said, as per other answers, catching specific exceptions is still the preferred mechanism IMO - presumably the HRESULT mechanism is a COM hangover.

Community
  • 1
  • 1
StuartLC
  • 104,537
  • 17
  • 209
  • 285
0

You should handle and provide meaningful message for those exceptions only you anticipate might arise in your code and the exception can be handled. Any exception you do not anticipate, display a generic message and log the message to log file or event log. You may also want to setup a policy for the unhandled/unexpected exceptions such that display message to contact support and exit application.

jags
  • 2,022
  • 26
  • 34