Exit the application in case of any unhandled exce

2019-03-05 11:13发布

[I understand that there are 100's of similar question on the net but I am still not able to find out a working solution to this problem and hence posting it.]

I have a c# Win-Form application. The application is used for downloading images via FTP from another server.

With the help of a task scheduler, the application runs 3 times a day and downloads the images and after that it closes automatically.

It used to work fine last year, however, since the beginning of this year, we are getting unhandled exception like "request timed out" or "operation timed out" from the application.

Thus instead of the application getting closed automatically, it shows a windows dialog with "continue" and "quit" button.

My requirement is that the application should close automatically in case any unhandled exception is thrown.

I have written the following code in my program.cs to handle this. However, this is also not working and I am still getting exceptions window.

    [STAThread]
    static void Main()
    {
        AppDomain currentDomain = AppDomain.CurrentDomain;
        currentDomain.UnhandledException += new UnhandledExceptionEventHandler(MyHandler);
        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);
        Application.Run(new Form1());
    }
    static void MyHandler(object sender, UnhandledExceptionEventArgs args)
    {
        System.Diagnostics.Process proc = System.Diagnostics.Process.GetCurrentProcess();
        System.Windows.Forms.Application.Exit();
        System.Environment.Exit(0);
        proc.Kill();
        return;
    }

2条回答
\"骚年 ilove
2楼-- · 2019-03-05 11:54

There are several events to which you may need to subscribe to ensure that you catch EVERY possible exception:

Application.ThreadException += yourThreadExceptionHandler;
AppDomain.CurrentDomain.UnhandledException += yourUnhandledExceptionHandler;
TaskScheduler.UnobservedTaskException += yourUnobservedTaskExceptionHandler;

And of course you should also have a try/catch around the body of the program:

public static void Main()
{
    try
    {
        runProgram();
    }

    catch (Exception exception)
    {
        // Your main exception handler.
    }
}

You can have a common exception handling mechanism that all your attached handlers call, to avoid duplicated code. UnobservedTaskException might be something you want to handle differently (log it and otherwise ignore, perhaps).

查看更多
混吃等死
3楼-- · 2019-03-05 12:09

Dealing with unhandled exceptions is a pain, and usually leads to a loss of context, making it very hard to know what to do next. There are ways of dealing with this gracefully though.

As it happens, I wrote a blog post on the subject just today. This extends the usual exception handling to give you a more robust and predictable execution path.

The way it works is that you wrap any potentially failing parts of the code in something that will catch any exceptions, and wrap them up in a way that you can deal with them. I did this by having an abstract Fallible class that has three inherited classes, Success, Failure and BadIdea. There is a helper method that does this for you, leaving you with an object that either contains the data you want, or an exception that you can use to log the error, report to the user, etc.

The abstract class looks like this...

public abstract class Fallible<T> {
  public static Fallible<T> Do(Func<T> f) {
    Fallible<T> result;
    try {
      T fResult = f();
      result = new Success<T> {Value = fResult};
    }
    catch (BadIdeaException ex) {
      result = new BadIdea<T> {Exception = ex};
    }
    catch (Exception ex) {
      // NOTE that in a real application, we would log the exception at this point
      result = new Failure<T> {Exception = ex};
    }
    return result;
  }

  public void Match(Action<T> onSuccess, Action<Exception> onFailure,
                                         Action<Exception> onBadIdea = null) {
    switch (this) {
      case Success<T> success:
        onSuccess(success.Value);
        break;
      case BadIdea<T> badIdea:
        if (onBadIdea != null) {
          onBadIdea(badIdea.Exception);
        } else {
          onFailure(badIdea.Exception);
        }
        break;
      case Failure<T> failure:
        onFailure(failure.Exception);
        break;
    }
  }
}

You then create inherited classes like this...

public abstract class Fallible<T> {
}

public class Success<T> : Fallible<T> {
  public T Value { get; set; }
}

public class Failure<T> : Fallible<T> {
  public Exception Exception { get; set; }
}

You can then wrap your potentially failing calls in the Do() method, and handle what happens afterwards...

var c = Fallible<Customer>.Do(() => CustomerBll.GetCustomer(id));
c.Match(
  c => Customer = c,
  e => AlertUser(ex)
);

The first lambda passed to Match tells it what to do in case of success, and the second tells it what to do in case of failure.

This enables you to handle your exceptions much more gracefully. See the blog post for more details.

This avoids the need for a global exception handler.

查看更多
登录 后发表回答