I'm trying to convert my sync functions to async. In all my sync functions I have a cancellation token which is used on function, task and parallel blocks. I have a try/catch block before calling the async function, but I'm getting an unhandled exception:
Exception thrown: 'System.OperationCanceledException' in System.Threading.Tasks.Parallel.dll An exception of type 'System.OperationCanceledException' occurred in System.Threading.Tasks.Parallel.dll but was not handled in user code The operation was canceled.
My async function:
public async Task DecodeAsync(string? fileFullPath, FileDecodeType fileDecodeType, OperationProgress? progress = null) =>
await Task.Run(() => Decode(fileFullPath, fileDecodeType, progress), progress?.Token ?? default);
How I call it:
try
{
await SlicerFile.DecodeAsync(fileName, fileDecodeType, Progress);
}
catch (OperationCanceledException) { } // Do not work!
catch (Exception exception) // Works for other exceptions
{
await this.MessageBoxError(exception.ToString(), "Error opening the file");
}
catch (OperationCanceledException)
is never reached nor catch (Exception exception)
in a cancel event. As my try is at top most, why doesn't it catch the exception?
But if I do:
public async Task DecodeAsync(string? fileFullPath, FileDecodeType fileDecodeType, OperationProgress? progress = null) =>
await Task.Run(() => throw new Exception("Test"));
I get the exception catch on the generic Exception (it's handled)
In other hand with old code it's working and handling the OperationCanceledException
:
var task = await Task.Factory.StartNew( () =>
{
try
{
SlicerFile.Decode(fileName, fileDecodeType, Progress);
return true;
}
catch (OperationCanceledException) {} // Works!
catch (Exception exception)
{
Dispatcher.UIThread.InvokeAsync(async () =>
await this.MessageBoxError(exception.ToString(), "Error opening the file"));
}
return false;
});
What am I doing wrong?
CodePudding user response:
The results of Task.Run don't need to be awaited right there necessarily. You can just return the running Task and then the method doesn't need to be awaited or be async any longer.
Task DecodeAsync(string? fileFullPath, FileDecodeType fileDecodeType, OperationProgress? progress = null) => Task.Run(() =>
Decode(fileFullPath, fileDecodeType, progress), progress?.Token ?? default);
And since you're passing in progress with a token, you can monitor that to exit the decode method cleanly instead of trying to catch and ignore the operation cancelled exception.
You'll have better luck if you make the decode method itself asynchronous if you can. It already returns a Task, so it could return a Task (or whatever). Your old code is also asynchronous in the same way, so there's no advantage to your new code that I can see.