I am writing some kind of a wrapper for WCF calls (using BackgroundWorker) to keep GUI from freezing while the call is ongoing. It is working mostly as it should, but I have a problem with the BackgroundWorker when the WCF call is throwing an exception. If an exception occurs in DoWork, I am able to detect it in RunWorkCompleted, but rethrowing it to the GUI does not work. I have read numerous threads with people mentioning that this should work.
Code for the wrapper (notice that the WCF call is symbolized by an exception being thrown):
private void GetSomething(Action<IEnumerable<int>> completedAction)
{
BackgroundWorker b = new BackgroundWorker();
b.DoWork += (s, evt) => { throw new Exception(); evt.Result = new List<int> { 1, 2, 3 }; };
b.RunWorkerCompleted += (s, evt) =>
{
if (evt.Error == null && completedAction != null)
{
completedAction((IEnumerable<int>)evt.Result);
}
else if(evt.Error != null)
{
throw evt.Error;
}
};
b.RunWorkerAsync();
}
Invoking code in a Windows form:
private void button3_Click(object sender, EventArgs e)
{
try
{
GetSomething(list =>
{
foreach (int i in list)
{
listView1.Items.Add(new ListViewItem(i.ToString()));
}
});
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
While debugging this, I get:
- “Exception of type ‘System.Exception’ was thrown” in DoWork
- “Exception of type ‘System.Exception’ was thrown” at throw evt.Error
- “TargetInvocationException was unhandled” at Application.Run(new Form1()) in the Main method
What am I doing wrong? I would like to catch the exception in the Windows form.
The event
b.RunWorkerCompletedis where you should do the error handling. You can pass in anAction<Exception>to do the error handling likeHowever this tends to get ugly. If you use .Net 4 or 4.5 you can resort to Tasks. The
Task<TResult>was created for exactly that case:Taskbasically is a signalling construct with.Resultproperty.Exceptionproperty.ContinueWith()methodWithin
ContinueWith()you can check if theTaskin a faulted state (Exception got thrown).You can use it like
If you use .Net 4.5 and C#5 (you need VS2012 or VS2010 and the Async CTP) you can even resort to
asyncandawaitlike… and all the magic is done by the compiler. Note that you can use
trycatchas you are used to.