dotnet / standard

This repo is building the .NET Standard
3.06k stars 427 forks source link

DbCommand.ExecuteReaderAsync throws TaskCanceledException with wrong CancellationToken #1793

Closed Coder3333 closed 2 years ago

Coder3333 commented 3 years ago

I also reported this issue at https://github.com/dotnet/runtime/issues/58583, in case that is a more appropriate place.

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?

                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;
                        }
                    }
                }
John0King commented 3 years ago

@Coder3333 I believe it use a inner token and linked by your token because it also have a timeout on connection

terrajobst commented 2 years ago

Closing as duplicate of dotnet/runtime/issues/58583.