Fix #79556. (#79562)
authorEirik Tsarpalis <eirik.tsarpalis@gmail.com>
Tue, 13 Dec 2022 14:38:01 +0000 (16:38 +0200)
committerGitHub <noreply@github.com>
Tue, 13 Dec 2022 14:38:01 +0000 (14:38 +0000)
src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Metadata/JsonTypeInfoOfT.WriteHelpers.cs
src/libraries/System.Text.Json/tests/Common/CollectionTests/CollectionTests.AsyncEnumerable.cs
src/libraries/System.Text.Json/tests/Common/Utf8MemoryStream.cs

index 75b0b3f..db6dde9 100644 (file)
@@ -121,6 +121,8 @@ namespace System.Text.Json.Serialization.Metadata
                     supportContinuation: true,
                     supportAsync: true);
 
+                state.CancellationToken = cancellationToken;
+
                 using var bufferWriter = new PooledByteBufferWriter(Options.DefaultBufferSize);
                 using var writer = new Utf8JsonWriter(bufferWriter, Options.GetWriterOptions());
 
index 52f3f2f..0ae7c05 100644 (file)
@@ -5,6 +5,7 @@ using System.Collections;
 using System.Collections.Generic;
 using System.IO;
 using System.Linq;
+using System.Runtime.CompilerServices;
 using System.Threading;
 using System.Threading.Tasks;
 using Xunit;
@@ -116,6 +117,28 @@ namespace System.Text.Json.Serialization.Tests
             Assert.Equal(1, asyncEnumerable.TotalDisposedEnumerators);
         }
 
+        [Fact]
+        public async Task WriteAsyncEnumerable_CancellationToken_IsPassedToAsyncEnumerator()
+        {
+            // Regression test for https://github.com/dotnet/runtime/issues/79556
+            using var utf8Stream = new Utf8MemoryStream(ignoreCancellationTokenOnWriteAsync: true);
+            using var cts = new CancellationTokenSource();
+
+            IAsyncEnumerable<int> value = CreateEnumerable();
+            await JsonSerializer.SerializeAsync(utf8Stream, value, cancellationToken: cts.Token);
+            Assert.Equal("[1,2]", utf8Stream.AsString());
+
+            async IAsyncEnumerable<int> CreateEnumerable([EnumeratorCancellation] CancellationToken cancellationToken = default)
+            {
+                yield return 1;
+                await Task.Delay(20);
+                Assert.False(cancellationToken.IsCancellationRequested);
+                cts.Cancel();
+                Assert.True(cancellationToken.IsCancellationRequested);
+                yield return 2;
+            }
+        }
+
         [Theory, OuterLoop]
         [InlineData(5000, 1000, true)]
         [InlineData(5000, 1000, false)]
index 1faa960..2904d74 100644 (file)
@@ -2,19 +2,31 @@
 // The .NET Foundation licenses this file to you under the MIT license.
 
 using System.IO;
+using System.Threading;
+using System.Threading.Tasks;
 
 namespace System.Text.Json.Serialization.Tests
 {
     public sealed class Utf8MemoryStream : MemoryStream
     {
-        public Utf8MemoryStream() : base()
+        private readonly bool _ignoreCancellationTokenOnWriteAsync;
+
+        public Utf8MemoryStream(bool ignoreCancellationTokenOnWriteAsync = false) : base()
         {
+            _ignoreCancellationTokenOnWriteAsync = ignoreCancellationTokenOnWriteAsync;
         }
 
         public Utf8MemoryStream(string text) : base(Encoding.UTF8.GetBytes(text))
         {
         }
 
+#if NETCOREAPP
+        public override ValueTask WriteAsync(ReadOnlyMemory<byte> buffer, CancellationToken cancellationToken = default)
+            => base.WriteAsync(buffer, _ignoreCancellationTokenOnWriteAsync ? default : cancellationToken);
+#endif
+        public override Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
+            => base.WriteAsync(buffer, offset, count, _ignoreCancellationTokenOnWriteAsync ? default : cancellationToken);
+
         public string AsString() => Encoding.UTF8.GetString(ToArray());
     }
 }