views:

408

answers:

7

I've found several C# application crashes in response to error conditions such as obj = null or obj.member = null. A lot of time, the obj from the interface of 3rdPartyApp. And caused both 3rdPartyApp and MyCsApp crashed together.

How could I add exception handling in all possible areas so that my application can survive in these disastrous situations? It is a challenge to add try-catch to ALL places, and recover from the situation.

How could I accomplish this in a way which is realistic, reliable and bullet-proof?

[Update: Industry Automation Control]

Structure:

GUI(asp.net, c++) - RuntimeApp (C++) - MyCsApp(cs) - 3rdPartyApp(Cs)

Normal procedure:

  1. HostApp --(Connect through ethernet Cabele)-- MyCsApp
  2. Operator -- GUI -- RuntimeApp -- MyCsApp

Abnormal conditions:

  1. Some non-standard operation procedure;
  2. some hardware issue occurred;
  3. etc.

I'd better handle all the abnormall conditions. And most importantly, I must think how to recover from the situations.

+4  A: 

you should certainly not add try catch everywhere

you just need a top level catch of all exceptions. If this is a GUI app then just display a nice dialog with a button saying 'please report to support' (it can write out a stack trace snapshot to the screen or a file)

if you are lucky then the app can continue (lucky since you have no way of knowing if you are really stuck badly)

note that you can also do this

        AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);
        Forms.Application.ThreadException += new System.Threading.ThreadExceptionEventHandler(Application_ThreadException);

but that doesnt stop it crshing, it just lets you capture the failure

pm100
+18  A: 

You do not want to catch every exception everywhere.

You want to prevent exceptions from "leaking out" of the lower layers of your application up to where they can kill the application or corrupt it.

But preventing corruption is going to require more than just catching exceptions. You're going to have to make sure that the application is always safe to interrupt at every point where an exception could be thrown. This may mean that you need to clean up complicated operations. For example:

ComplexBuilder cb = new ComplexBuilder();
try
{
    cb.AddOperation(...);  // Once building starts,
    cb.AddOperation(...);  // it's not safe to use cb
    cb.AddOperation(...);
}
catch (SpecificException ex)
{
    cb.Cleanup();          // until it's cleaned up
}

// Now safe to access cb, whether or not an exception was thrown

I recently ran into an application with a similar attitude. There was piece of this application that was considered to be "important". When that "important" thing happened, there were other things that were supposed to happen, but which were considered "not important". The idea was that if there was an exception in the "not important" part, then it was necessary for the "important" part to continue.

What happened is that an attempt to read a resource failed for some reason. This returned null instead of the string resource. This caused an ArgumentNullException in a String.Format call. This caused the exception to be caught by code that just continued.

But between the first exception and the last one, an object was to have been allocated, and the reference to the object was to have been set. But because of the exception, setting the reference never happened. The result was that I saw a NullReferenceException, four stack levels up, and two .csproj files away from where the actual problem happened.

So when you talk about catching exceptions so that your program can continue, you need to keep in mind that the control flow of your program is changed drastically by catching all these exceptions. In fact, it could be changed so much that you can no longer determine whether it's safe for your program to continue executing.

John Saunders
Ding, Ding, Ding. We have a winner.
Simucal
A: 

One technique to avoid such exceptions is to use the null object pattern.

So instead of having Account account = null; you would do Account account = Account.SpecialNullAccount; and in your Account class you would define SpecialNullAccount as a static Account object. Now if you try to use account.Name in some inconsequential code (like, say logging code) you don't get an Exception, instead you get a value like, say "NO NAME" defined on the static null object instance.

Of course it's important that such an object DOES throw Exceptions in any important case like .PayInvoice() or objectContext.SaveChanges() so take steps to ensure that happens.

Hightechrider
@Hightechrider: yes, the null object pattern prevents exceptions, but it doesn't make the program any more correct. It would be better to have the exception, safe the application, then fix the problem.
John Saunders
@John Saunders. Disagree that null value pattern doesn't improve your code. The null value pattern prevents pointless exceptions that really weren't necessary (e.g. log (account.Name) is NOT somewhere you want an Exception just because the user isn't logged in) AND it reveals more about your code because it differentiates between forgetting to initialize a variable and having a value that's deliberately not set yet: When PayInvoice() fails you can immediately see whether it's because the account value was never set OR because the user wasn't logged in.
Hightechrider
Null object pattern in OO is very similar to `NULL` values in databases - it solves some problems, but brings with it a mountain of new ones. It prevents "fail fast", allowing a program to run incorrectly for a long time and fail mysteriously later on. What *would* help to ensure correctness in this scenario is non-nullable types, such as those implemented by Spec#, but the time to introduce extensions like that is when the code is stable, not crashing everywhere.
Aaronaught
A: 

AppDomain.UnHandledException and/or AppDomain.ThreadException are events you can subscribe to to catch unhandled exceptions. I don't think you can use this to continue execution where it left off (and this probably woudn't be a good idea anyway). They can be used swallow the error message or log it, etc.

Whether this is a good idea to do is up to you however!

Martin Booth
One Caveat to this advice is that if the exception happened due to being in a bad/unrecoverable state, this will actually cause the app to continue to misbehave, and thoroughly frustrate a user. Sure it's frustrating to deal with an app that crashes, however it's more frustrating to deal with an app that is overly misbehaving.
Jason D
A: 

If it is a Winforms application add event handlers for for the following events in Main method like this

Application.ThreadException += Application_ThreadException;
AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;

You can then show a messagebox or other notification, loog the exeception etc and continue working without crashing the app.

Pratik
One Caveat to this advice is that if the exception happened due to being in a bad/unrecoverable state, this will actually cause the app to continue to misbehave, and thoroughly frustrate a user. Sure it's frustrating to deal with an app that crashes, however it's more frustrating to deal with an app that is overly misbehaving.
Jason D
Agree with Jason. I was describing a LOB app that has errors due to individual bad data and not in general. So you can happily continue after catching the exception. Another set of data you work with may have no issue at all.
Pratik
I wouldn't say that you can "happily" continue. At a *bare minimum* these errors need to be thoroughly logged, investigated, tracked, resolved in a sane and organized fashion. Simply skipping the file or outputting a cryptic debug message may allow the *application* to keep running but will bring down the *business* very fast.
Aaronaught
Aaronaught, you misunderstood the "you". You in this case is the end user. Of course the exception handler logs everything and the end user reports the error via some ticketing system. Each support ticket is analysed, fixed, reported etc. What I meant is that for the end user the app doesn't crash but he/she can continue using it after reporting the error. You the developer of course has the responsibility the fix the cause of the error and not happily shove it under the bench.
Pratik
+2  A: 
tommieb75
Nano HE
+7  A: 

This is something that a lot of developers don't get. By the time your exception catch-all gets hit, your application has already crashed. Something unexpected happened, which means that your code didn't anticipate it, and things are very likely to be in an indeterminate state (i.e. you can't be certain exactly how much of the offending function completed at the point the exception was generated, you don't know how much data got written out, what bits got set in the hardware, etc.). Is it safe to continue on? Should you try to save out the user's data? Who knows!

When you reach this high-level catch-all you're going to provide, you haven't prevented your app from crashing. You're just deciding what to do about the crash at that point. You can put up a different message than the standard:

This application has performed an illegal operation

...but what's your custom message going to say that's any better?

We're shutting down without warning for unscheduled maintenance, but rest assured that it had nothing to do with a flaw in this excellent software

...?

Scott Smith