Getting ExitCode From Exception Handler

2019-07-11 06:28发布

问题:

I have following error handler in my console application

Main Procedure:

AppDomain.CurrentDomain.UnhandledException +=
                new UnhandledExceptionEventHandler(ErrorHandler);

Handler Procedure:

static void ErrorHandler(object sender, UnhandledExceptionEventArgs args)
        {
            Exception e = (Exception)args.ExceptionObject;
            ... Loging Error ...
            //Environment.Exit(?);
        }

And the problem is that error is logged but after that application failed and windows popup (application is not responding) is showed.

So i want to add Environment.Exit() to prevent that behavior, but how to specify the exitCode from the exception ? I dont want to set Exit(0) (which means everything is okay) because i also want see the error (only information that some error happened, exception is already logged) in the scheduler application which trigger this script.

Thank you

回答1:

Can you use the Exception.HResult?

Consider the following code:

class Program
{
    static int Main(string[] args)
    {
        AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException; ;

        if (args.Any() && args[0] == "/t")
        {
            Console.WriteLine("I am going to throw an exception");

            throw new ApplicationException("This is an exception");
        }
        else
        {
            Console.WriteLine("I am going to exit");
            //Environment.Exit(0);
            return 0;
        }
    }

    private static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
    {
        Console.WriteLine("An unexpected error has occurred");
        Exception ex = (Exception)e.ExceptionObject;

        Environment.Exit(ex.HResult);
    }

}

Then execute this from a batch file twice - once with the /t parameter and the other without:

@echo off
cls
echo Running Console Application with no error
ConsoleApplication2.exe
echo %errorlevel%

echo Running Console Application with error
ConsoleApplication2.exe /t
echo %errorlevel%
pause

In the first run you exit with 0. I've made Main return an int and just return 0 for successful execution - you can do Environment.Exit(0) here.

With the second run that throws an ApplicationException, the UnhandledException is handled, then Environment.Exit(ex.HResult) is called.

I think the HResult is tied in to specific exceptions as per MSDN. However, you may want different exit codes depending on what caused the exception. In this case you can throw custom exceptions then have some cafuffled logic in the UnhandledException handler:

private static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
    {
        Console.WriteLine("An unexpected error has occurred");
        Exception ex = (Exception)e.ExceptionObject;
        if (ex is MyException)
        {
            Environment.Exit(10009); // my own exit codes
        }

        Environment.Exit(ex.HResult);
    }

}

class MyException : Exception
{

}

But would you really care why it failed in the console? If you get an unhandled exception then it failed. You can have lots of possible failure points. What are you really going to do with the error code? You have logged the exception out. That provides the vital information.



回答2:

Most programmers simply use Environment.Exit(1). Almost always works just fine. But that is not technically correct, if a program dies on an exception then its exit code is normally the same as the underlying exception error code. The event handler ought not change that behavior.

Doing it right is a mouthful:

   Environment.Exit(System.Runtime.InteropServices.Marshal.GetHRForException(e));

There's a FUD factor here, you can't completely trust a library with custom exception objects that don't set an error code. Still okay, the fallback is E_FAIL.