Reputation: 4037
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''
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.
Upvotes: 0
Views: 1411
Reputation: 35870
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.
Upvotes: 1