Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

StreamReader.ReadAsync() does not propagate CancellationToken to the underlying stream #31306

Closed
asmichi opened this issue Oct 26, 2019 · 2 comments
Assignees
Milestone

Comments

@asmichi
Copy link
Contributor

asmichi commented Oct 26, 2019

public class StreamReader : TextReader
{
    public override ValueTask<int> ReadAsync(Memory<char> buffer, CancellationToken cancellationToken = default);
}

The above overload of StreamReader.ReadAsync() cannot be canceled with cancellationToken even if the underlying stream supports cancellation because it does not propagate cancellationToken to the underlying stream

Actual Behavior

StreamReader.ReadAsync() indefinitely blocks.

Excpected Behavior

OperationCanceledException is thrown.

Environment

  • .NET Core SDK 3.1.100-preview1-014459
  • Windows 10 Pro 1903 (Build 18362.418)

Repro

The code below prints 0 chars read instead of canceled. See StreamReaderCancellation.zip for the full code.

using var serverPipe = new NamedPipeServerStream(
    pipeName, PipeDirection.InOut, NamedPipeServerStream.MaxAllowedServerInstances, PipeTransmissionMode.Byte, PipeOptions.Asynchronous);

// Simulate an idle connection: have another thread connect to the server and disconnect in 2000 ms.
var clientTask = Task.Run(() =>
{
    using var clientPipe = new NamedPipeClientStream(".", pipeName, PipeDirection.Out);
    clientPipe.Connect();
    Thread.Sleep(10000);
});

serverPipe.WaitForConnection();

using (var cts = new CancellationTokenSource(200))
using (var streamReader = new StreamReader(serverPipe, Encoding.UTF8, leaveOpen: true))
{
    try
    {
        var buffer = new char[256];
        var count = await streamReader.ReadAsync(buffer, cts.Token);
        Console.WriteLine("{0} chars read", count);
    }
    catch (OperationCanceledException)
    {
        Console.WriteLine("canceled");
    }
}
@asmichi
Copy link
Contributor Author

asmichi commented Oct 26, 2019

At first glance this looks like a simple oversight of not adding a CancellationToken parameter to StreamReader.ReadBufferAsync() (patch included in the zip). I suspect there may be a reason, though.

May affect #20824.

@asmichi
Copy link
Contributor Author

asmichi commented Nov 4, 2019

Awesome, thank you! I'm really glad this got into 3.1.

@msftgits msftgits transferred this issue from dotnet/corefx Feb 1, 2020
@msftgits msftgits added this to the 5.0 milestone Feb 1, 2020
@ghost ghost locked as resolved and limited conversation to collaborators Dec 11, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

3 participants