DbCommand.ExecuteReaderAsync throws TaskCanceledException with wrong CancellationToken
- Dominant language
- C#
- Stars
- 989
- Forks
- 340
- Avg merge
- 4d 18h
- Merged PRs (30d)
- 69
Description
I am witnessing this behavior in packages\netstandard.library\2.0.3\build\netstandard2.0\ref\netstandard.dll when running from a .Net Core 3.1 application.
When I call DbCommand.ExecuteReaderAsync with a CancellationToken and cancel it before it finishes, an exception is thrown that contains a TaskCanceledException buried down in the InnerExceptions. I expect that behavior, but the issue is that the TaskCanceledException.CancellationToken is not the CancellationToken that I provided to ExecuteReaderAsync. I do not know where this other CancellationToken is coming from, but I thought we were only supposed to suppress TaskCanceledException in our applications if it is for the provided CancellationToken, so I end up with a lot more unhandled exceptions than I want.
Is it safe to suppress any TaskCanceledException, no matter what CancellationToken it contains? Where does this mystery CancellationToken come from, and could ExecuteReaderAsync just return the CancellationToken given to it?
```c#
using (var cts = new CancellationTokenSource())
{
using (var cmd = db.GetSqlStringCommand(queryString))
{
cts.Cancel();
try
{
using (var rdr = cmd.ExecuteReaderAsync(cts.Token).Result)
{
}
}
catch (Exception ex3)
{
// if you inspect ex3, you will find a TaskCanceledException buried in InnerExceptions, but its CancellationToken is not cts.Token
throw;
}
}
}
```
Additional Comments:
I have tested this with "System.Data.SqlClient.SqlCommand" and "Microsoft.Data.SqlClient.SqlCommand". The result is the same in both cases where the TaskCanceledException holds a new CancellationToken and the TaskCanceledException is wrapped in an AggregateException, so I have to dig down in the exception stack to find the TaskCanceledException , which means I cannot just catch TaskCanceledException.
System.AggregateException: One or more errors occurred. (A task was canceled.)
---> System.Threading.Tasks.TaskCanceledException: A task was canceled.
--- End of inner exception stack trace ---
at System.Threading.Tasks.Task.ThrowIfExceptional(Boolean includeTaskCanceledExceptions)
at System.Threading.Tasks.Task`1.GetResultCore(Boolean waitCompletionNotification)
at System.Threading.Tasks.Task`1.get_Result()
Contributor guide
Assessment
This issue has not been assessed yet.