I encountered an issue when I was using Task.Factory.StartNew and tried to capture an exception that is thrown. In my application I have a long running task that I want to encapsulate in a Task.Factory.StartNew(.., TaskCreationOptions.LongRunning);
However, the exception isn’t caught when I’m using Task.Factory.StartNew. It is however working as I expect when I use Task.Run, which I thought was just a wrapper on Task.Factory.StartNew (according to for instance this MSDN article).
A working example is provided here, the difference being that the exception is written to console when using Task.Run, but not when using Factory.StartNew.
My question would be:
if I have a LongRunning task that has the possibility to throw exceptions, how should I handle them in the calling code?
private static void Main(string[] args)
{
Task<bool> t = RunLongTask();
t.Wait();
Console.WriteLine(t.Result);
Console.ReadKey();
}
private async static Task<bool> RunLongTask()
{
try
{
await RunTaskAsync();
}
catch (Exception e)
{
Console.WriteLine(e);
return false;
}
Console.WriteLine("success");
return true;
}
private static Task RunTaskAsync()
{
//return Task.Run(async () =>
// {
// throw new Exception("my exception");
// });
return Task.Factory.StartNew(
async () =>
{
throw new Exception("my exception");
});
}
Your problem is that
StartNewdoesn’t work likeTask.Runwithasyncdelegates. The return type ofStartNewisTask<Task>(which is convertible toTask). The "outer"Taskrepresents the beginning of the method, and the "inner"Taskrepresents the completion of the method (including any exceptions).To get to the inner
Task, you can useUnwrap. Or you can just useTask.Runinstead ofStartNewforasynccode.LongRunningis just an optimization hint and is really optional. Stephen Toub has a good blog post on the difference betweenStartNewandRunand whyRunis (usually) better forasynccode.Update from @usr comment below:
LongRunningonly applies to the beginning of theasyncmethod (up until the first incomplete operation isawaited). So it’s almost certainly better all around to useTask.Runin this case.