0

I'm using background worker and found that new exceptions raised in the RunWorkerCompleted event handler are not visible in the Application.ThreadException handler. For example: somewhere in the Program.cs:

    [STAThread]
    static void Main()
    {
        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);

        Application.ThreadException += delegate(object o, ThreadExceptionEventArgs args)
        {
            if (args.Exception != null)
                Console.WriteLine("thread error {0}", args.Exception.Message);
        };

        Application.Run(new Form1());
    }

and then in the button click (for testing purposes only)

        var bw = new BackgroundWorker();
        bw.DoWork += delegate(object o, DoWorkEventArgs args) { /* some calculations here */ };
        bw.RunWorkerCompleted += delegate(object sender1, RunWorkerCompletedEventArgs eventArgs)
        { 
            try
            {
                //in run worker completed exception occurs
                throw new ApplicationException("test exception 1");
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
                Console.WriteLine("throwing new exception");
                throw new ApplicationException(string.Format("catched '{0}'", ex.Message), ex);
            }
        };

        bw.RunWorkerAsync();

Program output is below:

test exception 1

throwing new exception

thread error test exception 1

I beleive that in the Application.ThreadException handler exception with text thread error catched 'test exception 1' should appear, not original exception.

Could you please help me - why it happens and how it can be solved? This is only sample code. There are several nested methods inside RunWorkerCompleted handler in the real code. And some of those methods catch exception, and throw new with additional information and original exception in the inner exception. So in the Application.ThreadException handler I would like to get not only original exception that was thrown, but the whole chain.

Thank you


I've found that GetBaseException is not called for unhandled exceptions from button click (for example)

lets assume that there is TreadException event handler in the Program.Main method like below:

        Application.ThreadException += (o, args) =>
        {
            Console.WriteLine("BEGIN ThreadException handler");
            ShowException(args.Exception);
            Console.WriteLine("END ThreadException handler\r\n");
        };

and Program.ShowException method like this:

    static void ShowException(Exception ex)
    {
        var tab = "";
        while (ex != null)
        {
            Console.WriteLine("{1}error '{0}'", ex.Message, tab);
            tab += '\t';
            ex = ex.InnerException;
        }
    }

When code

        try
        {
            throw new ApplicationException("button click 1");
        }
        catch (Exception ex)
        {
            throw new ApplicationException(string.Format("BC caught '{0}'", ex.Message), ex);
        }

is executed in the button click, it produces the following output:

BEGIN ThreadException handler

error 'BC caught 'button click 1''

  • error 'button click 1'*

END ThreadException handler

As you can see - entire exception chain is available.

But ThreadException handler shows only original exception for very similar code in the RunWorkerCompleted event handler (code below was executed in the button click event):

        var bw = new BackgroundWorker();
        bw.DoWork += delegate(object o, DoWorkEventArgs args) 
        { 
            /* some calculations here */
        };
        bw.RunWorkerCompleted += delegate(object sender1, RunWorkerCompletedEventArgs eventArgs)
        { 
            try
            {
                //in run worker completed exception occurs
                Console.WriteLine("RWC exception test, throwing");
                throw new ApplicationException("test exception 1");
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
                Console.WriteLine("RWC got exception, throwing new");
                throw new ApplicationException(string.Format("RWC caught '{0}'", ex.Message), ex);
            }
        };

        bw.RunWorkerAsync();

and output is below:

RWC exception test, throwing

test exception 1

RWC got exception, throwing new

BEGIN ThreadException handler

error 'test exception 1' -- only original exception here

END ThreadException handler

Seems that GetBaseException is executed only for RunWorkerCompleted event.

oleksa
  • 3,688
  • 1
  • 29
  • 54
  • duplicate of http://stackoverflow.com/questions/3007066/very-strange-application-threadexception-behaviour – Peter Ritchie Sep 18 '12 at 14:47
  • @PeterRitchie Actually I've thought that RunWorkerCompleted is executed in the GUI (main) thread, since it is safe to access GUI controls from it. It is a pity that link to the GetBaseException call issue is broken, I've failed to find this bug [link](https://connect.microsoft.com/SearchResultsLive.aspx?SearchQuery=GetBaseException) to vote. There is one more thread [link](http://stackoverflow.com/questions/8565761/prevent-outer-exception-from-being-discarded-when-thrown-from-begininvoke) I've found it by GetBaseException – oleksa Sep 19 '12 at 10:07

1 Answers1

1

For whatever reason, the framework is calling Exception.GetBaseException on the exception you threw and using that exception to pass into the ThreadException event. If you don't want that, don't pass in a base/inner exception.

Peter Ritchie
  • 35,463
  • 9
  • 80
  • 98
  • Thank you for your comment, but i've found that GetBaseException is called not every time, please see my post below – oleksa Sep 19 '12 at 07:52