Implement new streaming APIs for the `System.Net.Http.Json` extensions (#89258)
authorDavid Pine <david.pine@microsoft.com>
Mon, 24 Jul 2023 16:51:40 +0000 (11:51 -0500)
committerGitHub <noreply@github.com>
Mon, 24 Jul 2023 16:51:40 +0000 (17:51 +0100)
* Contributes to #87577

* More updates

* Added unit tests, generated ref, and minor clean up

* Added missing triple slash comments

* Update src/libraries/System.Net.Http.Json/tests/FunctionalTests/HttpClientJsonExtensionsTests.cs

Co-authored-by: Eirik Tsarpalis <eirik.tsarpalis@gmail.com>
* Correct the preprocessor directives, and delegate to JsonTypeInfo overload - per peer feedback.

* Refactor for deferred execution, remove helper methods since they're no longer needed

* Add test to ensure deferred execution semantics, updates from Miha.

* Apply suggestions from code review

Co-authored-by: Miha Zupan <mihazupan.zupan1@gmail.com>
* Update src/libraries/System.Net.Http.Json/src/System/Net/Http/Json/HttpClientJsonExtensions.Get.AsyncEnumerable.cs

Co-authored-by: Eirik Tsarpalis <eirik.tsarpalis@gmail.com>
* Update test per Miha's feedback

* A few more updates from peer review, Eirik's nits.

* No need for the length limit read stream.

* Add limit per invocation, not element. Share length limit read stream logic.

---------

Co-authored-by: Eirik Tsarpalis <eirik.tsarpalis@gmail.com>
Co-authored-by: Miha Zupan <mihazupan.zupan1@gmail.com>
src/libraries/System.Net.Http.Json/ref/System.Net.Http.Json.cs
src/libraries/System.Net.Http.Json/src/System.Net.Http.Json.csproj
src/libraries/System.Net.Http.Json/src/System/Net/Http/Json/HttpClientJsonExtensions.Get.AsyncEnumerable.cs [new file with mode: 0644]
src/libraries/System.Net.Http.Json/src/System/Net/Http/Json/HttpClientJsonExtensions.cs
src/libraries/System.Net.Http.Json/src/System/Net/Http/Json/HttpContentJsonExtensions.AsyncEnumerable.cs [new file with mode: 0644]
src/libraries/System.Net.Http.Json/tests/FunctionalTests/HttpClientJsonExtensionsTests.cs
src/libraries/System.Net.Http.Json/tests/FunctionalTests/HttpContentJsonExtensionsTests.cs
src/libraries/System.Net.Http.Json/tests/FunctionalTests/TestClasses.cs

index b1520a4..efde74c 100644 (file)
@@ -8,109 +8,130 @@ namespace System.Net.Http.Json
 {
     public static partial class HttpClientJsonExtensions
     {
-        [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("JSON serialization and deserialization might require types that cannot be statically analyzed. Use the overload that takes a JsonTypeInfo or JsonSerializerContext, or make sure all of the required types are preserved.")]
         [System.Diagnostics.CodeAnalysis.RequiresDynamicCodeAttribute("JSON serialization and deserialization might require types that cannot be statically analyzed. Use the overload that takes a JsonTypeInfo or JsonSerializerContext.")]
+        [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("JSON serialization and deserialization might require types that cannot be statically analyzed. Use the overload that takes a JsonTypeInfo or JsonSerializerContext, or make sure all of the required types are preserved.")]
         public static System.Threading.Tasks.Task<object?> DeleteFromJsonAsync(this System.Net.Http.HttpClient client, [System.Diagnostics.CodeAnalysis.StringSyntaxAttribute("Uri")] string? requestUri, System.Type type, System.Text.Json.JsonSerializerOptions? options, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
         public static System.Threading.Tasks.Task<object?> DeleteFromJsonAsync(this System.Net.Http.HttpClient client, [System.Diagnostics.CodeAnalysis.StringSyntaxAttribute("Uri")] string? requestUri, System.Type type, System.Text.Json.Serialization.JsonSerializerContext context, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
-        [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("JSON serialization and deserialization might require types that cannot be statically analyzed. Use the overload that takes a JsonTypeInfo or JsonSerializerContext, or make sure all of the required types are preserved.")]
         [System.Diagnostics.CodeAnalysis.RequiresDynamicCodeAttribute("JSON serialization and deserialization might require types that cannot be statically analyzed. Use the overload that takes a JsonTypeInfo or JsonSerializerContext.")]
-        public static System.Threading.Tasks.Task<object?> DeleteFromJsonAsync(this System.Net.Http.HttpClient client, [System.Diagnostics.CodeAnalysis.StringSyntaxAttribute("Uri")] string? requestUri, System.Type type, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
         [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("JSON serialization and deserialization might require types that cannot be statically analyzed. Use the overload that takes a JsonTypeInfo or JsonSerializerContext, or make sure all of the required types are preserved.")]
+        public static System.Threading.Tasks.Task<object?> DeleteFromJsonAsync(this System.Net.Http.HttpClient client, [System.Diagnostics.CodeAnalysis.StringSyntaxAttribute("Uri")] string? requestUri, System.Type type, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
         [System.Diagnostics.CodeAnalysis.RequiresDynamicCodeAttribute("JSON serialization and deserialization might require types that cannot be statically analyzed. Use the overload that takes a JsonTypeInfo or JsonSerializerContext.")]
+        [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("JSON serialization and deserialization might require types that cannot be statically analyzed. Use the overload that takes a JsonTypeInfo or JsonSerializerContext, or make sure all of the required types are preserved.")]
         public static System.Threading.Tasks.Task<object?> DeleteFromJsonAsync(this System.Net.Http.HttpClient client, System.Uri? requestUri, System.Type type, System.Text.Json.JsonSerializerOptions? options, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
         public static System.Threading.Tasks.Task<object?> DeleteFromJsonAsync(this System.Net.Http.HttpClient client, System.Uri? requestUri, System.Type type, System.Text.Json.Serialization.JsonSerializerContext context, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
-        [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("JSON serialization and deserialization might require types that cannot be statically analyzed. Use the overload that takes a JsonTypeInfo or JsonSerializerContext, or make sure all of the required types are preserved.")]
         [System.Diagnostics.CodeAnalysis.RequiresDynamicCodeAttribute("JSON serialization and deserialization might require types that cannot be statically analyzed. Use the overload that takes a JsonTypeInfo or JsonSerializerContext.")]
-        public static System.Threading.Tasks.Task<object?> DeleteFromJsonAsync(this System.Net.Http.HttpClient client, System.Uri? requestUri, System.Type type, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
         [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("JSON serialization and deserialization might require types that cannot be statically analyzed. Use the overload that takes a JsonTypeInfo or JsonSerializerContext, or make sure all of the required types are preserved.")]
+        public static System.Threading.Tasks.Task<object?> DeleteFromJsonAsync(this System.Net.Http.HttpClient client, System.Uri? requestUri, System.Type type, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
         [System.Diagnostics.CodeAnalysis.RequiresDynamicCodeAttribute("JSON serialization and deserialization might require types that cannot be statically analyzed. Use the overload that takes a JsonTypeInfo or JsonSerializerContext.")]
+        [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("JSON serialization and deserialization might require types that cannot be statically analyzed. Use the overload that takes a JsonTypeInfo or JsonSerializerContext, or make sure all of the required types are preserved.")]
         public static System.Threading.Tasks.Task<TValue?> DeleteFromJsonAsync<TValue>(this System.Net.Http.HttpClient client, [System.Diagnostics.CodeAnalysis.StringSyntaxAttribute("Uri")] string? requestUri, System.Text.Json.JsonSerializerOptions? options, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
         public static System.Threading.Tasks.Task<TValue?> DeleteFromJsonAsync<TValue>(this System.Net.Http.HttpClient client, [System.Diagnostics.CodeAnalysis.StringSyntaxAttribute("Uri")] string? requestUri, System.Text.Json.Serialization.Metadata.JsonTypeInfo<TValue> jsonTypeInfo, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
-        [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("JSON serialization and deserialization might require types that cannot be statically analyzed. Use the overload that takes a JsonTypeInfo or JsonSerializerContext, or make sure all of the required types are preserved.")]
         [System.Diagnostics.CodeAnalysis.RequiresDynamicCodeAttribute("JSON serialization and deserialization might require types that cannot be statically analyzed. Use the overload that takes a JsonTypeInfo or JsonSerializerContext.")]
-        public static System.Threading.Tasks.Task<TValue?> DeleteFromJsonAsync<TValue>(this System.Net.Http.HttpClient client, [System.Diagnostics.CodeAnalysis.StringSyntaxAttribute("Uri")] string? requestUri, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
         [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("JSON serialization and deserialization might require types that cannot be statically analyzed. Use the overload that takes a JsonTypeInfo or JsonSerializerContext, or make sure all of the required types are preserved.")]
+        public static System.Threading.Tasks.Task<TValue?> DeleteFromJsonAsync<TValue>(this System.Net.Http.HttpClient client, [System.Diagnostics.CodeAnalysis.StringSyntaxAttribute("Uri")] string? requestUri, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
         [System.Diagnostics.CodeAnalysis.RequiresDynamicCodeAttribute("JSON serialization and deserialization might require types that cannot be statically analyzed. Use the overload that takes a JsonTypeInfo or JsonSerializerContext.")]
+        [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("JSON serialization and deserialization might require types that cannot be statically analyzed. Use the overload that takes a JsonTypeInfo or JsonSerializerContext, or make sure all of the required types are preserved.")]
         public static System.Threading.Tasks.Task<TValue?> DeleteFromJsonAsync<TValue>(this System.Net.Http.HttpClient client, System.Uri? requestUri, System.Text.Json.JsonSerializerOptions? options, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
         public static System.Threading.Tasks.Task<TValue?> DeleteFromJsonAsync<TValue>(this System.Net.Http.HttpClient client, System.Uri? requestUri, System.Text.Json.Serialization.Metadata.JsonTypeInfo<TValue> jsonTypeInfo, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
-        [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("JSON serialization and deserialization might require types that cannot be statically analyzed. Use the overload that takes a JsonTypeInfo or JsonSerializerContext, or make sure all of the required types are preserved.")]
         [System.Diagnostics.CodeAnalysis.RequiresDynamicCodeAttribute("JSON serialization and deserialization might require types that cannot be statically analyzed. Use the overload that takes a JsonTypeInfo or JsonSerializerContext.")]
+        [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("JSON serialization and deserialization might require types that cannot be statically analyzed. Use the overload that takes a JsonTypeInfo or JsonSerializerContext, or make sure all of the required types are preserved.")]
         public static System.Threading.Tasks.Task<TValue?> DeleteFromJsonAsync<TValue>(this System.Net.Http.HttpClient client, System.Uri? requestUri, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
+        [System.Diagnostics.CodeAnalysis.RequiresDynamicCodeAttribute("JSON serialization and deserialization might require types that cannot be statically analyzed. Use the overload that takes a JsonTypeInfo or JsonSerializerContext.")]
+        [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("JSON serialization and deserialization might require types that cannot be statically analyzed. Use the overload that takes a JsonTypeInfo or JsonSerializerContext, or make sure all of the required types are preserved.")]
+        public static System.Collections.Generic.IAsyncEnumerable<TValue?> GetFromJsonAsAsyncEnumerable<TValue>(this System.Net.Http.HttpClient client, [System.Diagnostics.CodeAnalysis.StringSyntaxAttribute("Uri")] string? requestUri, System.Text.Json.JsonSerializerOptions? options, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
+        public static System.Collections.Generic.IAsyncEnumerable<TValue?> GetFromJsonAsAsyncEnumerable<TValue>(this System.Net.Http.HttpClient client, [System.Diagnostics.CodeAnalysis.StringSyntaxAttribute("Uri")] string? requestUri, System.Text.Json.Serialization.Metadata.JsonTypeInfo<TValue> jsonTypeInfo, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
+        [System.Diagnostics.CodeAnalysis.RequiresDynamicCodeAttribute("JSON serialization and deserialization might require types that cannot be statically analyzed. Use the overload that takes a JsonTypeInfo or JsonSerializerContext.")]
+        [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("JSON serialization and deserialization might require types that cannot be statically analyzed. Use the overload that takes a JsonTypeInfo or JsonSerializerContext, or make sure all of the required types are preserved.")]
+        public static System.Collections.Generic.IAsyncEnumerable<TValue?> GetFromJsonAsAsyncEnumerable<TValue>(this System.Net.Http.HttpClient client, [System.Diagnostics.CodeAnalysis.StringSyntaxAttribute("Uri")] string? requestUri, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
+        [System.Diagnostics.CodeAnalysis.RequiresDynamicCodeAttribute("JSON serialization and deserialization might require types that cannot be statically analyzed. Use the overload that takes a JsonTypeInfo or JsonSerializerContext.")]
+        [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("JSON serialization and deserialization might require types that cannot be statically analyzed. Use the overload that takes a JsonTypeInfo or JsonSerializerContext, or make sure all of the required types are preserved.")]
+        public static System.Collections.Generic.IAsyncEnumerable<TValue?> GetFromJsonAsAsyncEnumerable<TValue>(this System.Net.Http.HttpClient client, System.Uri? requestUri, System.Text.Json.JsonSerializerOptions? options, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
+        public static System.Collections.Generic.IAsyncEnumerable<TValue?> GetFromJsonAsAsyncEnumerable<TValue>(this System.Net.Http.HttpClient client, System.Uri? requestUri, System.Text.Json.Serialization.Metadata.JsonTypeInfo<TValue> jsonTypeInfo, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
+        [System.Diagnostics.CodeAnalysis.RequiresDynamicCodeAttribute("JSON serialization and deserialization might require types that cannot be statically analyzed. Use the overload that takes a JsonTypeInfo or JsonSerializerContext.")]
         [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("JSON serialization and deserialization might require types that cannot be statically analyzed. Use the overload that takes a JsonTypeInfo or JsonSerializerContext, or make sure all of the required types are preserved.")]
+        public static System.Collections.Generic.IAsyncEnumerable<TValue?> GetFromJsonAsAsyncEnumerable<TValue>(this System.Net.Http.HttpClient client, System.Uri? requestUri, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
         [System.Diagnostics.CodeAnalysis.RequiresDynamicCodeAttribute("JSON serialization and deserialization might require types that cannot be statically analyzed. Use the overload that takes a JsonTypeInfo or JsonSerializerContext.")]
+        [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("JSON serialization and deserialization might require types that cannot be statically analyzed. Use the overload that takes a JsonTypeInfo or JsonSerializerContext, or make sure all of the required types are preserved.")]
         public static System.Threading.Tasks.Task<object?> GetFromJsonAsync(this System.Net.Http.HttpClient client, [System.Diagnostics.CodeAnalysis.StringSyntaxAttribute("Uri")] string? requestUri, System.Type type, System.Text.Json.JsonSerializerOptions? options, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
         public static System.Threading.Tasks.Task<object?> GetFromJsonAsync(this System.Net.Http.HttpClient client, [System.Diagnostics.CodeAnalysis.StringSyntaxAttribute("Uri")] string? requestUri, System.Type type, System.Text.Json.Serialization.JsonSerializerContext context, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
-        [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("JSON serialization and deserialization might require types that cannot be statically analyzed. Use the overload that takes a JsonTypeInfo or JsonSerializerContext, or make sure all of the required types are preserved.")]
         [System.Diagnostics.CodeAnalysis.RequiresDynamicCodeAttribute("JSON serialization and deserialization might require types that cannot be statically analyzed. Use the overload that takes a JsonTypeInfo or JsonSerializerContext.")]
-        public static System.Threading.Tasks.Task<object?> GetFromJsonAsync(this System.Net.Http.HttpClient client, [System.Diagnostics.CodeAnalysis.StringSyntaxAttribute("Uri")] string? requestUri, System.Type type, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
         [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("JSON serialization and deserialization might require types that cannot be statically analyzed. Use the overload that takes a JsonTypeInfo or JsonSerializerContext, or make sure all of the required types are preserved.")]
+        public static System.Threading.Tasks.Task<object?> GetFromJsonAsync(this System.Net.Http.HttpClient client, [System.Diagnostics.CodeAnalysis.StringSyntaxAttribute("Uri")] string? requestUri, System.Type type, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
         [System.Diagnostics.CodeAnalysis.RequiresDynamicCodeAttribute("JSON serialization and deserialization might require types that cannot be statically analyzed. Use the overload that takes a JsonTypeInfo or JsonSerializerContext.")]
+        [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("JSON serialization and deserialization might require types that cannot be statically analyzed. Use the overload that takes a JsonTypeInfo or JsonSerializerContext, or make sure all of the required types are preserved.")]
         public static System.Threading.Tasks.Task<object?> GetFromJsonAsync(this System.Net.Http.HttpClient client, System.Uri? requestUri, System.Type type, System.Text.Json.JsonSerializerOptions? options, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
         public static System.Threading.Tasks.Task<object?> GetFromJsonAsync(this System.Net.Http.HttpClient client, System.Uri? requestUri, System.Type type, System.Text.Json.Serialization.JsonSerializerContext context, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
-        [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("JSON serialization and deserialization might require types that cannot be statically analyzed. Use the overload that takes a JsonTypeInfo or JsonSerializerContext, or make sure all of the required types are preserved.")]
         [System.Diagnostics.CodeAnalysis.RequiresDynamicCodeAttribute("JSON serialization and deserialization might require types that cannot be statically analyzed. Use the overload that takes a JsonTypeInfo or JsonSerializerContext.")]
-        public static System.Threading.Tasks.Task<object?> GetFromJsonAsync(this System.Net.Http.HttpClient client, System.Uri? requestUri, System.Type type, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
         [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("JSON serialization and deserialization might require types that cannot be statically analyzed. Use the overload that takes a JsonTypeInfo or JsonSerializerContext, or make sure all of the required types are preserved.")]
+        public static System.Threading.Tasks.Task<object?> GetFromJsonAsync(this System.Net.Http.HttpClient client, System.Uri? requestUri, System.Type type, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
         [System.Diagnostics.CodeAnalysis.RequiresDynamicCodeAttribute("JSON serialization and deserialization might require types that cannot be statically analyzed. Use the overload that takes a JsonTypeInfo or JsonSerializerContext.")]
+        [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("JSON serialization and deserialization might require types that cannot be statically analyzed. Use the overload that takes a JsonTypeInfo or JsonSerializerContext, or make sure all of the required types are preserved.")]
         public static System.Threading.Tasks.Task<TValue?> GetFromJsonAsync<TValue>(this System.Net.Http.HttpClient client, [System.Diagnostics.CodeAnalysis.StringSyntaxAttribute("Uri")] string? requestUri, System.Text.Json.JsonSerializerOptions? options, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
         public static System.Threading.Tasks.Task<TValue?> GetFromJsonAsync<TValue>(this System.Net.Http.HttpClient client, [System.Diagnostics.CodeAnalysis.StringSyntaxAttribute("Uri")] string? requestUri, System.Text.Json.Serialization.Metadata.JsonTypeInfo<TValue> jsonTypeInfo, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
-        [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("JSON serialization and deserialization might require types that cannot be statically analyzed. Use the overload that takes a JsonTypeInfo or JsonSerializerContext, or make sure all of the required types are preserved.")]
         [System.Diagnostics.CodeAnalysis.RequiresDynamicCodeAttribute("JSON serialization and deserialization might require types that cannot be statically analyzed. Use the overload that takes a JsonTypeInfo or JsonSerializerContext.")]
-        public static System.Threading.Tasks.Task<TValue?> GetFromJsonAsync<TValue>(this System.Net.Http.HttpClient client, [System.Diagnostics.CodeAnalysis.StringSyntaxAttribute("Uri")] string? requestUri, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
         [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("JSON serialization and deserialization might require types that cannot be statically analyzed. Use the overload that takes a JsonTypeInfo or JsonSerializerContext, or make sure all of the required types are preserved.")]
+        public static System.Threading.Tasks.Task<TValue?> GetFromJsonAsync<TValue>(this System.Net.Http.HttpClient client, [System.Diagnostics.CodeAnalysis.StringSyntaxAttribute("Uri")] string? requestUri, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
         [System.Diagnostics.CodeAnalysis.RequiresDynamicCodeAttribute("JSON serialization and deserialization might require types that cannot be statically analyzed. Use the overload that takes a JsonTypeInfo or JsonSerializerContext.")]
+        [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("JSON serialization and deserialization might require types that cannot be statically analyzed. Use the overload that takes a JsonTypeInfo or JsonSerializerContext, or make sure all of the required types are preserved.")]
         public static System.Threading.Tasks.Task<TValue?> GetFromJsonAsync<TValue>(this System.Net.Http.HttpClient client, System.Uri? requestUri, System.Text.Json.JsonSerializerOptions? options, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
         public static System.Threading.Tasks.Task<TValue?> GetFromJsonAsync<TValue>(this System.Net.Http.HttpClient client, System.Uri? requestUri, System.Text.Json.Serialization.Metadata.JsonTypeInfo<TValue> jsonTypeInfo, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
-        [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("JSON serialization and deserialization might require types that cannot be statically analyzed. Use the overload that takes a JsonTypeInfo or JsonSerializerContext, or make sure all of the required types are preserved.")]
         [System.Diagnostics.CodeAnalysis.RequiresDynamicCodeAttribute("JSON serialization and deserialization might require types that cannot be statically analyzed. Use the overload that takes a JsonTypeInfo or JsonSerializerContext.")]
-        public static System.Threading.Tasks.Task<TValue?> GetFromJsonAsync<TValue>(this System.Net.Http.HttpClient client, System.Uri? requestUri, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
         [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("JSON serialization and deserialization might require types that cannot be statically analyzed. Use the overload that takes a JsonTypeInfo or JsonSerializerContext, or make sure all of the required types are preserved.")]
+        public static System.Threading.Tasks.Task<TValue?> GetFromJsonAsync<TValue>(this System.Net.Http.HttpClient client, System.Uri? requestUri, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
         [System.Diagnostics.CodeAnalysis.RequiresDynamicCodeAttribute("JSON serialization and deserialization might require types that cannot be statically analyzed. Use the overload that takes a JsonTypeInfo or JsonSerializerContext.")]
-        public static System.Threading.Tasks.Task<System.Net.Http.HttpResponseMessage> PostAsJsonAsync<TValue>(this System.Net.Http.HttpClient client, [System.Diagnostics.CodeAnalysis.StringSyntaxAttribute("Uri")] string? requestUri, TValue value, System.Text.Json.JsonSerializerOptions? options = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
-        public static System.Threading.Tasks.Task<System.Net.Http.HttpResponseMessage> PostAsJsonAsync<TValue>(this System.Net.Http.HttpClient client, [System.Diagnostics.CodeAnalysis.StringSyntaxAttribute("Uri")] string? requestUri, TValue value, System.Text.Json.Serialization.Metadata.JsonTypeInfo<TValue> jsonTypeInfo, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
         [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("JSON serialization and deserialization might require types that cannot be statically analyzed. Use the overload that takes a JsonTypeInfo or JsonSerializerContext, or make sure all of the required types are preserved.")]
+        public static System.Threading.Tasks.Task<System.Net.Http.HttpResponseMessage> PatchAsJsonAsync<TValue>(this System.Net.Http.HttpClient client, [System.Diagnostics.CodeAnalysis.StringSyntaxAttribute("Uri")] string? requestUri, TValue value, System.Text.Json.JsonSerializerOptions? options = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
+        public static System.Threading.Tasks.Task<System.Net.Http.HttpResponseMessage> PatchAsJsonAsync<TValue>(this System.Net.Http.HttpClient client, [System.Diagnostics.CodeAnalysis.StringSyntaxAttribute("Uri")] string? requestUri, TValue value, System.Text.Json.Serialization.Metadata.JsonTypeInfo<TValue> jsonTypeInfo, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
         [System.Diagnostics.CodeAnalysis.RequiresDynamicCodeAttribute("JSON serialization and deserialization might require types that cannot be statically analyzed. Use the overload that takes a JsonTypeInfo or JsonSerializerContext.")]
-        public static System.Threading.Tasks.Task<System.Net.Http.HttpResponseMessage> PostAsJsonAsync<TValue>(this System.Net.Http.HttpClient client, [System.Diagnostics.CodeAnalysis.StringSyntaxAttribute("Uri")] string? requestUri, TValue value, System.Threading.CancellationToken cancellationToken) { throw null; }
         [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("JSON serialization and deserialization might require types that cannot be statically analyzed. Use the overload that takes a JsonTypeInfo or JsonSerializerContext, or make sure all of the required types are preserved.")]
+        public static System.Threading.Tasks.Task<System.Net.Http.HttpResponseMessage> PatchAsJsonAsync<TValue>(this System.Net.Http.HttpClient client, [System.Diagnostics.CodeAnalysis.StringSyntaxAttribute("Uri")] string? requestUri, TValue value, System.Threading.CancellationToken cancellationToken) { throw null; }
         [System.Diagnostics.CodeAnalysis.RequiresDynamicCodeAttribute("JSON serialization and deserialization might require types that cannot be statically analyzed. Use the overload that takes a JsonTypeInfo or JsonSerializerContext.")]
-        public static System.Threading.Tasks.Task<System.Net.Http.HttpResponseMessage> PostAsJsonAsync<TValue>(this System.Net.Http.HttpClient client, System.Uri? requestUri, TValue value, System.Text.Json.JsonSerializerOptions? options = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
-        public static System.Threading.Tasks.Task<System.Net.Http.HttpResponseMessage> PostAsJsonAsync<TValue>(this System.Net.Http.HttpClient client, System.Uri? requestUri, TValue value, System.Text.Json.Serialization.Metadata.JsonTypeInfo<TValue> jsonTypeInfo, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
         [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("JSON serialization and deserialization might require types that cannot be statically analyzed. Use the overload that takes a JsonTypeInfo or JsonSerializerContext, or make sure all of the required types are preserved.")]
+        public static System.Threading.Tasks.Task<System.Net.Http.HttpResponseMessage> PatchAsJsonAsync<TValue>(this System.Net.Http.HttpClient client, System.Uri? requestUri, TValue value, System.Text.Json.JsonSerializerOptions? options = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
+        public static System.Threading.Tasks.Task<System.Net.Http.HttpResponseMessage> PatchAsJsonAsync<TValue>(this System.Net.Http.HttpClient client, System.Uri? requestUri, TValue value, System.Text.Json.Serialization.Metadata.JsonTypeInfo<TValue> jsonTypeInfo, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
         [System.Diagnostics.CodeAnalysis.RequiresDynamicCodeAttribute("JSON serialization and deserialization might require types that cannot be statically analyzed. Use the overload that takes a JsonTypeInfo or JsonSerializerContext.")]
-        public static System.Threading.Tasks.Task<System.Net.Http.HttpResponseMessage> PostAsJsonAsync<TValue>(this System.Net.Http.HttpClient client, System.Uri? requestUri, TValue value, System.Threading.CancellationToken cancellationToken) { throw null; }
         [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("JSON serialization and deserialization might require types that cannot be statically analyzed. Use the overload that takes a JsonTypeInfo or JsonSerializerContext, or make sure all of the required types are preserved.")]
+        public static System.Threading.Tasks.Task<System.Net.Http.HttpResponseMessage> PatchAsJsonAsync<TValue>(this System.Net.Http.HttpClient client, System.Uri? requestUri, TValue value, System.Threading.CancellationToken cancellationToken) { throw null; }
         [System.Diagnostics.CodeAnalysis.RequiresDynamicCodeAttribute("JSON serialization and deserialization might require types that cannot be statically analyzed. Use the overload that takes a JsonTypeInfo or JsonSerializerContext.")]
-        public static System.Threading.Tasks.Task<System.Net.Http.HttpResponseMessage> PutAsJsonAsync<TValue>(this System.Net.Http.HttpClient client, [System.Diagnostics.CodeAnalysis.StringSyntaxAttribute("Uri")] string? requestUri, TValue value, System.Text.Json.JsonSerializerOptions? options = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
-        public static System.Threading.Tasks.Task<System.Net.Http.HttpResponseMessage> PutAsJsonAsync<TValue>(this System.Net.Http.HttpClient client, [System.Diagnostics.CodeAnalysis.StringSyntaxAttribute("Uri")] string? requestUri, TValue value, System.Text.Json.Serialization.Metadata.JsonTypeInfo<TValue> jsonTypeInfo, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
         [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("JSON serialization and deserialization might require types that cannot be statically analyzed. Use the overload that takes a JsonTypeInfo or JsonSerializerContext, or make sure all of the required types are preserved.")]
+        public static System.Threading.Tasks.Task<System.Net.Http.HttpResponseMessage> PostAsJsonAsync<TValue>(this System.Net.Http.HttpClient client, [System.Diagnostics.CodeAnalysis.StringSyntaxAttribute("Uri")] string? requestUri, TValue value, System.Text.Json.JsonSerializerOptions? options = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
+        public static System.Threading.Tasks.Task<System.Net.Http.HttpResponseMessage> PostAsJsonAsync<TValue>(this System.Net.Http.HttpClient client, [System.Diagnostics.CodeAnalysis.StringSyntaxAttribute("Uri")] string? requestUri, TValue value, System.Text.Json.Serialization.Metadata.JsonTypeInfo<TValue> jsonTypeInfo, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
         [System.Diagnostics.CodeAnalysis.RequiresDynamicCodeAttribute("JSON serialization and deserialization might require types that cannot be statically analyzed. Use the overload that takes a JsonTypeInfo or JsonSerializerContext.")]
-        public static System.Threading.Tasks.Task<System.Net.Http.HttpResponseMessage> PutAsJsonAsync<TValue>(this System.Net.Http.HttpClient client, [System.Diagnostics.CodeAnalysis.StringSyntaxAttribute("Uri")] string? requestUri, TValue value, System.Threading.CancellationToken cancellationToken) { throw null; }
         [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("JSON serialization and deserialization might require types that cannot be statically analyzed. Use the overload that takes a JsonTypeInfo or JsonSerializerContext, or make sure all of the required types are preserved.")]
+        public static System.Threading.Tasks.Task<System.Net.Http.HttpResponseMessage> PostAsJsonAsync<TValue>(this System.Net.Http.HttpClient client, [System.Diagnostics.CodeAnalysis.StringSyntaxAttribute("Uri")] string? requestUri, TValue value, System.Threading.CancellationToken cancellationToken) { throw null; }
         [System.Diagnostics.CodeAnalysis.RequiresDynamicCodeAttribute("JSON serialization and deserialization might require types that cannot be statically analyzed. Use the overload that takes a JsonTypeInfo or JsonSerializerContext.")]
-        public static System.Threading.Tasks.Task<System.Net.Http.HttpResponseMessage> PutAsJsonAsync<TValue>(this System.Net.Http.HttpClient client, System.Uri? requestUri, TValue value, System.Text.Json.JsonSerializerOptions? options = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
-        public static System.Threading.Tasks.Task<System.Net.Http.HttpResponseMessage> PutAsJsonAsync<TValue>(this System.Net.Http.HttpClient client, System.Uri? requestUri, TValue value, System.Text.Json.Serialization.Metadata.JsonTypeInfo<TValue> jsonTypeInfo, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
         [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("JSON serialization and deserialization might require types that cannot be statically analyzed. Use the overload that takes a JsonTypeInfo or JsonSerializerContext, or make sure all of the required types are preserved.")]
+        public static System.Threading.Tasks.Task<System.Net.Http.HttpResponseMessage> PostAsJsonAsync<TValue>(this System.Net.Http.HttpClient client, System.Uri? requestUri, TValue value, System.Text.Json.JsonSerializerOptions? options = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
+        public static System.Threading.Tasks.Task<System.Net.Http.HttpResponseMessage> PostAsJsonAsync<TValue>(this System.Net.Http.HttpClient client, System.Uri? requestUri, TValue value, System.Text.Json.Serialization.Metadata.JsonTypeInfo<TValue> jsonTypeInfo, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
         [System.Diagnostics.CodeAnalysis.RequiresDynamicCodeAttribute("JSON serialization and deserialization might require types that cannot be statically analyzed. Use the overload that takes a JsonTypeInfo or JsonSerializerContext.")]
-        public static System.Threading.Tasks.Task<System.Net.Http.HttpResponseMessage> PutAsJsonAsync<TValue>(this System.Net.Http.HttpClient client, System.Uri? requestUri, TValue value, System.Threading.CancellationToken cancellationToken) { throw null; }
         [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("JSON serialization and deserialization might require types that cannot be statically analyzed. Use the overload that takes a JsonTypeInfo or JsonSerializerContext, or make sure all of the required types are preserved.")]
+        public static System.Threading.Tasks.Task<System.Net.Http.HttpResponseMessage> PostAsJsonAsync<TValue>(this System.Net.Http.HttpClient client, System.Uri? requestUri, TValue value, System.Threading.CancellationToken cancellationToken) { throw null; }
         [System.Diagnostics.CodeAnalysis.RequiresDynamicCodeAttribute("JSON serialization and deserialization might require types that cannot be statically analyzed. Use the overload that takes a JsonTypeInfo or JsonSerializerContext.")]
-        public static System.Threading.Tasks.Task<System.Net.Http.HttpResponseMessage> PatchAsJsonAsync<TValue>(this System.Net.Http.HttpClient client, [System.Diagnostics.CodeAnalysis.StringSyntaxAttribute("Uri")] string? requestUri, TValue value, System.Text.Json.JsonSerializerOptions? options = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
-        public static System.Threading.Tasks.Task<System.Net.Http.HttpResponseMessage> PatchAsJsonAsync<TValue>(this System.Net.Http.HttpClient client, [System.Diagnostics.CodeAnalysis.StringSyntaxAttribute("Uri")] string? requestUri, TValue value, System.Text.Json.Serialization.Metadata.JsonTypeInfo<TValue> jsonTypeInfo, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
         [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("JSON serialization and deserialization might require types that cannot be statically analyzed. Use the overload that takes a JsonTypeInfo or JsonSerializerContext, or make sure all of the required types are preserved.")]
+        public static System.Threading.Tasks.Task<System.Net.Http.HttpResponseMessage> PutAsJsonAsync<TValue>(this System.Net.Http.HttpClient client, [System.Diagnostics.CodeAnalysis.StringSyntaxAttribute("Uri")] string? requestUri, TValue value, System.Text.Json.JsonSerializerOptions? options = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
+        public static System.Threading.Tasks.Task<System.Net.Http.HttpResponseMessage> PutAsJsonAsync<TValue>(this System.Net.Http.HttpClient client, [System.Diagnostics.CodeAnalysis.StringSyntaxAttribute("Uri")] string? requestUri, TValue value, System.Text.Json.Serialization.Metadata.JsonTypeInfo<TValue> jsonTypeInfo, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
         [System.Diagnostics.CodeAnalysis.RequiresDynamicCodeAttribute("JSON serialization and deserialization might require types that cannot be statically analyzed. Use the overload that takes a JsonTypeInfo or JsonSerializerContext.")]
-        public static System.Threading.Tasks.Task<System.Net.Http.HttpResponseMessage> PatchAsJsonAsync<TValue>(this System.Net.Http.HttpClient client, [System.Diagnostics.CodeAnalysis.StringSyntaxAttribute("Uri")] string? requestUri, TValue value, System.Threading.CancellationToken cancellationToken) { throw null; }
         [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("JSON serialization and deserialization might require types that cannot be statically analyzed. Use the overload that takes a JsonTypeInfo or JsonSerializerContext, or make sure all of the required types are preserved.")]
+        public static System.Threading.Tasks.Task<System.Net.Http.HttpResponseMessage> PutAsJsonAsync<TValue>(this System.Net.Http.HttpClient client, [System.Diagnostics.CodeAnalysis.StringSyntaxAttribute("Uri")] string? requestUri, TValue value, System.Threading.CancellationToken cancellationToken) { throw null; }
         [System.Diagnostics.CodeAnalysis.RequiresDynamicCodeAttribute("JSON serialization and deserialization might require types that cannot be statically analyzed. Use the overload that takes a JsonTypeInfo or JsonSerializerContext.")]
-        public static System.Threading.Tasks.Task<System.Net.Http.HttpResponseMessage> PatchAsJsonAsync<TValue>(this System.Net.Http.HttpClient client, System.Uri? requestUri, TValue value, System.Text.Json.JsonSerializerOptions? options = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
-        public static System.Threading.Tasks.Task<System.Net.Http.HttpResponseMessage> PatchAsJsonAsync<TValue>(this System.Net.Http.HttpClient client, System.Uri? requestUri, TValue value, System.Text.Json.Serialization.Metadata.JsonTypeInfo<TValue> jsonTypeInfo, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
         [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("JSON serialization and deserialization might require types that cannot be statically analyzed. Use the overload that takes a JsonTypeInfo or JsonSerializerContext, or make sure all of the required types are preserved.")]
+        public static System.Threading.Tasks.Task<System.Net.Http.HttpResponseMessage> PutAsJsonAsync<TValue>(this System.Net.Http.HttpClient client, System.Uri? requestUri, TValue value, System.Text.Json.JsonSerializerOptions? options = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
+        public static System.Threading.Tasks.Task<System.Net.Http.HttpResponseMessage> PutAsJsonAsync<TValue>(this System.Net.Http.HttpClient client, System.Uri? requestUri, TValue value, System.Text.Json.Serialization.Metadata.JsonTypeInfo<TValue> jsonTypeInfo, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
         [System.Diagnostics.CodeAnalysis.RequiresDynamicCodeAttribute("JSON serialization and deserialization might require types that cannot be statically analyzed. Use the overload that takes a JsonTypeInfo or JsonSerializerContext.")]
-        public static System.Threading.Tasks.Task<System.Net.Http.HttpResponseMessage> PatchAsJsonAsync<TValue>(this System.Net.Http.HttpClient client, System.Uri? requestUri, TValue value, System.Threading.CancellationToken cancellationToken) { throw null; }
+        [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("JSON serialization and deserialization might require types that cannot be statically analyzed. Use the overload that takes a JsonTypeInfo or JsonSerializerContext, or make sure all of the required types are preserved.")]
+        public static System.Threading.Tasks.Task<System.Net.Http.HttpResponseMessage> PutAsJsonAsync<TValue>(this System.Net.Http.HttpClient client, System.Uri? requestUri, TValue value, System.Threading.CancellationToken cancellationToken) { throw null; }
     }
     public static partial class HttpContentJsonExtensions
     {
         [System.Diagnostics.CodeAnalysis.RequiresDynamicCodeAttribute("JSON serialization and deserialization might require types that cannot be statically analyzed. Use the overload that takes a JsonTypeInfo or JsonSerializerContext.")]
         [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("JSON serialization and deserialization might require types that cannot be statically analyzed. Use the overload that takes a JsonTypeInfo or JsonSerializerContext, or make sure all of the required types are preserved.")]
+        public static System.Collections.Generic.IAsyncEnumerable<TValue?> ReadFromJsonAsAsyncEnumerable<TValue>(this System.Net.Http.HttpContent content, System.Text.Json.JsonSerializerOptions? options, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
+        public static System.Collections.Generic.IAsyncEnumerable<TValue?> ReadFromJsonAsAsyncEnumerable<TValue>(this System.Net.Http.HttpContent content, System.Text.Json.Serialization.Metadata.JsonTypeInfo<TValue> jsonTypeInfo, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
+        [System.Diagnostics.CodeAnalysis.RequiresDynamicCodeAttribute("JSON serialization and deserialization might require types that cannot be statically analyzed. Use the overload that takes a JsonTypeInfo or JsonSerializerContext.")]
+        [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("JSON serialization and deserialization might require types that cannot be statically analyzed. Use the overload that takes a JsonTypeInfo or JsonSerializerContext, or make sure all of the required types are preserved.")]
+        public static System.Collections.Generic.IAsyncEnumerable<TValue?> ReadFromJsonAsAsyncEnumerable<TValue>(this System.Net.Http.HttpContent content, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
+        [System.Diagnostics.CodeAnalysis.RequiresDynamicCodeAttribute("JSON serialization and deserialization might require types that cannot be statically analyzed. Use the overload that takes a JsonTypeInfo or JsonSerializerContext.")]
+        [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("JSON serialization and deserialization might require types that cannot be statically analyzed. Use the overload that takes a JsonTypeInfo or JsonSerializerContext, or make sure all of the required types are preserved.")]
         public static System.Threading.Tasks.Task<object?> ReadFromJsonAsync(this System.Net.Http.HttpContent content, System.Type type, System.Text.Json.JsonSerializerOptions? options, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
         public static System.Threading.Tasks.Task<object?> ReadFromJsonAsync(this System.Net.Http.HttpContent content, System.Type type, System.Text.Json.Serialization.JsonSerializerContext context, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
         [System.Diagnostics.CodeAnalysis.RequiresDynamicCodeAttribute("JSON serialization and deserialization might require types that cannot be statically analyzed. Use the overload that takes a JsonTypeInfo or JsonSerializerContext.")]
index 34f94be..9ed9b54 100644 (file)
@@ -11,7 +11,9 @@ System.Net.Http.Json.JsonContent</PackageDescription>
   </PropertyGroup>
 
   <ItemGroup>
+    <Compile Include="System\Net\Http\Json\HttpClientJsonExtensions.Get.AsyncEnumerable.cs" />
     <Compile Include="System\Net\Http\Json\HttpClientJsonExtensions.cs" />
+    <Compile Include="System\Net\Http\Json\HttpContentJsonExtensions.AsyncEnumerable.cs" />
     <Compile Include="System\Net\Http\Json\JsonHelpers.cs" />
     <Compile Include="System\Net\Http\Json\HttpClientJsonExtensions.Delete.cs" />
     <Compile Include="System\Net\Http\Json\HttpClientJsonExtensions.Get.cs" />
diff --git a/src/libraries/System.Net.Http.Json/src/System/Net/Http/Json/HttpClientJsonExtensions.Get.AsyncEnumerable.cs b/src/libraries/System.Net.Http.Json/src/System/Net/Http/Json/HttpClientJsonExtensions.Get.AsyncEnumerable.cs
new file mode 100644 (file)
index 0000000..057bf87
--- /dev/null
@@ -0,0 +1,180 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Diagnostics.CodeAnalysis;
+using System.IO;
+using System.Runtime.CompilerServices;
+using System.Text.Json;
+using System.Text.Json.Serialization.Metadata;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace System.Net.Http.Json
+{
+    public static partial class HttpClientJsonExtensions
+    {
+        /// <summary>
+        /// Sends an <c>HTTP GET</c> request to the specified <paramref name="requestUri"/> and returns the value that results
+        /// from deserializing the response body as JSON in an async enumerable operation.
+        /// </summary>
+        /// <typeparam name="TValue">The target type to deserialize to.</typeparam>
+        /// <param name="client">The client used to send the request.</param>
+        /// <param name="requestUri">The Uri the request is sent to.</param>
+        /// <param name="options"></param>
+        /// <param name="cancellationToken">A cancellation token that can be used by other objects or threads to receive notice of cancellation.</param>
+        /// <returns>An <see cref="IAsyncEnumerable{TValue}"/> that represents the deserialized response body.</returns>
+        /// <exception cref="ArgumentNullException">The <paramref name="client"/> is <see langword="null"/>.</exception>
+        [RequiresUnreferencedCode(HttpContentJsonExtensions.SerializationUnreferencedCodeMessage)]
+        [RequiresDynamicCode(HttpContentJsonExtensions.SerializationDynamicCodeMessage)]
+        public static IAsyncEnumerable<TValue?> GetFromJsonAsAsyncEnumerable<TValue>(
+            this HttpClient client,
+            [StringSyntax(StringSyntaxAttribute.Uri)] string? requestUri,
+            JsonSerializerOptions? options,
+            CancellationToken cancellationToken = default) =>
+            GetFromJsonAsAsyncEnumerable<TValue>(client, CreateUri(requestUri), options, cancellationToken);
+
+        /// <summary>
+        /// Sends an <c>HTTP GET</c>request to the specified <paramref name="requestUri"/> and returns the value that results
+        /// from deserializing the response body as JSON in an async enumerable operation.
+        /// </summary>
+        /// <typeparam name="TValue">The target type to deserialize to.</typeparam>
+        /// <param name="client">The client used to send the request.</param>
+        /// <param name="requestUri">The Uri the request is sent to.</param>
+        /// <param name="options"></param>
+        /// <param name="cancellationToken">A cancellation token that can be used by other objects or threads to receive notice of cancellation.</param>
+        /// <returns>An <see cref="IAsyncEnumerable{TValue}"/> that represents the deserialized response body.</returns>
+        /// <exception cref="ArgumentNullException">The <paramref name="client"/> is <see langword="null"/>.</exception>
+        [RequiresUnreferencedCode(HttpContentJsonExtensions.SerializationUnreferencedCodeMessage)]
+        [RequiresDynamicCode(HttpContentJsonExtensions.SerializationDynamicCodeMessage)]
+        public static IAsyncEnumerable<TValue?> GetFromJsonAsAsyncEnumerable<TValue>(
+            this HttpClient client,
+            Uri? requestUri,
+            JsonSerializerOptions? options,
+            CancellationToken cancellationToken = default) =>
+            FromJsonStreamAsyncCore<TValue>(client, requestUri, options, cancellationToken);
+
+        /// <summary>
+        /// Sends an <c>HTTP GET</c>request to the specified <paramref name="requestUri"/> and returns the value that results
+        /// from deserializing the response body as JSON in an async enumerable operation.
+        /// </summary>
+        /// <typeparam name="TValue">The target type to deserialize to.</typeparam>
+        /// <param name="client">The client used to send the request.</param>
+        /// <param name="requestUri">The Uri the request is sent to.</param>
+        /// <param name="jsonTypeInfo">Source generated JsonTypeInfo to control the behavior during deserialization.</param>
+        /// <param name="cancellationToken">A cancellation token that can be used by other objects or threads to receive notice of cancellation.</param>
+        /// <returns>An <see cref="IAsyncEnumerable{TValue}"/> that represents the deserialized response body.</returns>
+        /// <exception cref="ArgumentNullException">The <paramref name="client"/> is <see langword="null"/>.</exception>
+        public static IAsyncEnumerable<TValue?> GetFromJsonAsAsyncEnumerable<TValue>(
+            this HttpClient client,
+            [StringSyntax(StringSyntaxAttribute.Uri)] string? requestUri,
+            JsonTypeInfo<TValue> jsonTypeInfo,
+            CancellationToken cancellationToken = default) =>
+            GetFromJsonAsAsyncEnumerable(client, CreateUri(requestUri), jsonTypeInfo, cancellationToken);
+
+        /// <summary>
+        /// Sends an <c>HTTP GET</c>request to the specified <paramref name="requestUri"/> and returns the value that results
+        /// from deserializing the response body as JSON in an async enumerable operation.
+        /// </summary>
+        /// <typeparam name="TValue">The target type to deserialize to.</typeparam>
+        /// <param name="client">The client used to send the request.</param>
+        /// <param name="requestUri">The Uri the request is sent to.</param>
+        /// <param name="jsonTypeInfo">Source generated JsonTypeInfo to control the behavior during deserialization.</param>
+        /// <param name="cancellationToken">A cancellation token that can be used by other objects or threads to receive notice of cancellation.</param>
+        /// <returns>An <see cref="IAsyncEnumerable{TValue}"/> that represents the deserialized response body.</returns>
+        /// <exception cref="ArgumentNullException">The <paramref name="client"/> is <see langword="null"/>.</exception>
+        public static IAsyncEnumerable<TValue?> GetFromJsonAsAsyncEnumerable<TValue>(
+            this HttpClient client,
+            Uri? requestUri,
+            JsonTypeInfo<TValue> jsonTypeInfo,
+            CancellationToken cancellationToken = default) =>
+            FromJsonStreamAsyncCore(client, requestUri, jsonTypeInfo, cancellationToken);
+
+        /// <summary>
+        /// Sends an <c>HTTP GET</c>request to the specified <paramref name="requestUri"/> and returns the value that results
+        /// from deserializing the response body as JSON in an async enumerable operation.
+        /// </summary>
+        /// <typeparam name="TValue">The target type to deserialize to.</typeparam>
+        /// <param name="client">The client used to send the request.</param>
+        /// <param name="requestUri">The Uri the request is sent to.</param>
+        /// <param name="cancellationToken">A cancellation token that can be used by other objects or threads to receive notice of cancellation.</param>
+        /// <returns>An <see cref="IAsyncEnumerable{TValue}"/> that represents the deserialized response body.</returns>
+        /// <exception cref="ArgumentNullException">The <paramref name="client"/> is <see langword="null"/>.</exception>
+        [RequiresUnreferencedCode(HttpContentJsonExtensions.SerializationUnreferencedCodeMessage)]
+        [RequiresDynamicCode(HttpContentJsonExtensions.SerializationDynamicCodeMessage)]
+        public static IAsyncEnumerable<TValue?> GetFromJsonAsAsyncEnumerable<TValue>(
+            this HttpClient client,
+            [StringSyntax(StringSyntaxAttribute.Uri)] string? requestUri,
+            CancellationToken cancellationToken = default) =>
+            GetFromJsonAsAsyncEnumerable<TValue>(client, requestUri, options: null, cancellationToken);
+
+        /// <summary>
+        /// Sends an <c>HTTP GET</c>request to the specified <paramref name="requestUri"/> and returns the value that results
+        /// from deserializing the response body as JSON in an async enumerable operation.
+        /// </summary>
+        /// <typeparam name="TValue">The target type to deserialize to.</typeparam>
+        /// <param name="client">The client used to send the request.</param>
+        /// <param name="requestUri">The Uri the request is sent to.</param>
+        /// <param name="cancellationToken">A cancellation token that can be used by other objects or threads to receive notice of cancellation.</param>
+        /// <returns>An <see cref="IAsyncEnumerable{TValue}"/> that represents the deserialized response body.</returns>
+        /// <exception cref="ArgumentNullException">The <paramref name="client"/> is <see langword="null"/>.</exception>
+        [RequiresUnreferencedCode(HttpContentJsonExtensions.SerializationUnreferencedCodeMessage)]
+        [RequiresDynamicCode(HttpContentJsonExtensions.SerializationDynamicCodeMessage)]
+        public static IAsyncEnumerable<TValue?> GetFromJsonAsAsyncEnumerable<TValue>(
+            this HttpClient client,
+            Uri? requestUri,
+            CancellationToken cancellationToken = default) =>
+            GetFromJsonAsAsyncEnumerable<TValue>(client, requestUri, options: null, cancellationToken);
+
+        [RequiresUnreferencedCode(HttpContentJsonExtensions.SerializationUnreferencedCodeMessage)]
+        [RequiresDynamicCode(HttpContentJsonExtensions.SerializationDynamicCodeMessage)]
+        private static IAsyncEnumerable<TValue?> FromJsonStreamAsyncCore<TValue>(
+            HttpClient client,
+            Uri? requestUri,
+            JsonSerializerOptions? options,
+            CancellationToken cancellationToken)
+        {
+            options ??= JsonSerializerOptions.Default;
+            options.MakeReadOnly();
+
+            var jsonTypeInfo = (JsonTypeInfo<TValue>)options.GetTypeInfo(typeof(TValue));
+
+            return FromJsonStreamAsyncCore(client, requestUri, jsonTypeInfo, cancellationToken);
+        }
+
+        private static IAsyncEnumerable<TValue?> FromJsonStreamAsyncCore<TValue>(
+            HttpClient client,
+            Uri? requestUri,
+            JsonTypeInfo<TValue> jsonTypeInfo,
+            CancellationToken cancellationToken)
+        {
+            if (client is null)
+            {
+                throw new ArgumentNullException(nameof(client));
+            }
+
+            return Core(client, requestUri, jsonTypeInfo, cancellationToken);
+
+            static async IAsyncEnumerable<TValue?> Core(
+                HttpClient client,
+                Uri? requestUri,
+                JsonTypeInfo<TValue> jsonTypeInfo,
+                [EnumeratorCancellation] CancellationToken cancellationToken)
+            {
+                using HttpResponseMessage response = await client.GetAsync(requestUri, HttpCompletionOption.ResponseHeadersRead, cancellationToken)
+                    .ConfigureAwait(false);
+                response.EnsureSuccessStatusCode();
+
+                using Stream readStream = await GetHttpResponseStreamAsync(client, response, false, cancellationToken)
+                    .ConfigureAwait(false);
+
+                await foreach (TValue? value in JsonSerializer.DeserializeAsyncEnumerable<TValue>(
+                    readStream, jsonTypeInfo, cancellationToken).ConfigureAwait(false))
+                {
+                    yield return value;
+                }
+            }
+        }
+    }
+}
index 234f8c3..4aa114c 100644 (file)
@@ -84,22 +84,10 @@ namespace System.Net.Http.Json
                     using HttpResponseMessage response = await responseTask.ConfigureAwait(false);
                     response.EnsureSuccessStatusCode();
 
-                    Debug.Assert(client.MaxResponseContentBufferSize is > 0 and <= int.MaxValue);
-                    int contentLengthLimit = (int)client.MaxResponseContentBufferSize;
-
-                    if (response.Content.Headers.ContentLength is long contentLength && contentLength > contentLengthLimit)
-                    {
-                        LengthLimitReadStream.ThrowExceededBufferLimit(contentLengthLimit);
-                    }
-
                     try
                     {
-                        using Stream contentStream = await HttpContentJsonExtensions.GetContentStreamAsync(response.Content, linkedCTS?.Token ?? cancellationToken).ConfigureAwait(false);
-
-                        // If ResponseHeadersRead wasn't used, HttpClient will have already buffered the whole response upfront. No need to check the limit again.
-                        Stream readStream = usingResponseHeadersRead
-                            ? new LengthLimitReadStream(contentStream, (int)client.MaxResponseContentBufferSize)
-                            : contentStream;
+                        using Stream readStream = await GetHttpResponseStreamAsync(client, response, usingResponseHeadersRead, cancellationToken)
+                            .ConfigureAwait(false);
 
                         return await deserializeMethod(readStream, jsonOptions, linkedCTS?.Token ?? cancellationToken).ConfigureAwait(false);
                     }
@@ -123,5 +111,31 @@ namespace System.Net.Http.Json
 
         private static Uri? CreateUri(string? uri) =>
             string.IsNullOrEmpty(uri) ? null : new Uri(uri, UriKind.RelativeOrAbsolute);
+
+        private static async Task<Stream> GetHttpResponseStreamAsync(
+            HttpClient client,
+            HttpResponseMessage response,
+            bool usingResponseHeadersRead,
+            CancellationToken cancellationToken)
+        {
+            Debug.Assert(client.MaxResponseContentBufferSize is > 0 and <= int.MaxValue);
+            int contentLengthLimit = (int)client.MaxResponseContentBufferSize;
+
+            if (response.Content.Headers.ContentLength is long contentLength && contentLength > contentLengthLimit)
+            {
+                LengthLimitReadStream.ThrowExceededBufferLimit(contentLengthLimit);
+            }
+
+            Stream contentStream = await HttpContentJsonExtensions.GetContentStreamAsync(response.Content, cancellationToken)
+                .ConfigureAwait(false);
+
+            // If ResponseHeadersRead wasn't used, HttpClient will have already buffered the whole response upfront.
+            // No need to check the limit again.
+            Stream readStream = usingResponseHeadersRead
+                ? new LengthLimitReadStream(contentStream, (int)client.MaxResponseContentBufferSize)
+                : contentStream;
+
+            return readStream;
+        }
     }
 }
diff --git a/src/libraries/System.Net.Http.Json/src/System/Net/Http/Json/HttpContentJsonExtensions.AsyncEnumerable.cs b/src/libraries/System.Net.Http.Json/src/System/Net/Http/Json/HttpContentJsonExtensions.AsyncEnumerable.cs
new file mode 100644 (file)
index 0000000..c42f51d
--- /dev/null
@@ -0,0 +1,107 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System.Collections.Generic;
+using System.Diagnostics.CodeAnalysis;
+using System.IO;
+using System.Runtime.CompilerServices;
+using System.Text.Json;
+using System.Text.Json.Serialization.Metadata;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace System.Net.Http.Json
+{
+    public static partial class HttpContentJsonExtensions
+    {
+        /// <summary>
+        /// Reads the HTTP content and returns the value that results from deserializing the content as
+        /// JSON in an async enumerable operation.
+        /// </summary>
+        /// <typeparam name="TValue">The target type to deserialize to.</typeparam>
+        /// <param name="content"></param>
+        /// <param name="cancellationToken"></param>
+        /// <returns>An <see cref="IAsyncEnumerable{TValue}"/> that represents the deserialized response body.</returns>
+        /// <exception cref="ArgumentNullException">
+        /// The <paramref name="content"/> is <see langword="null"/>.
+        /// </exception>
+        [RequiresUnreferencedCode(SerializationUnreferencedCodeMessage)]
+        [RequiresDynamicCode(SerializationDynamicCodeMessage)]
+        public static IAsyncEnumerable<TValue?> ReadFromJsonAsAsyncEnumerable<TValue>(
+            this HttpContent content,
+            CancellationToken cancellationToken = default) =>
+            ReadFromJsonAsAsyncEnumerable<TValue>(content, options: null, cancellationToken: cancellationToken);
+
+        /// <summary>
+        /// Reads the HTTP content and returns the value that results from deserializing the content as
+        /// JSON in an async enumerable operation.
+        /// </summary>
+        /// <typeparam name="TValue">The target type to deserialize to.</typeparam>
+        /// <param name="content">The content to read from.</param>
+        /// <param name="options">Options to control the behavior during deserialization.
+        /// The default options are those specified by <see cref="JsonSerializerDefaults.Web"/>.</param>
+        /// <param name="cancellationToken"></param>
+        /// <returns>An <see cref="IAsyncEnumerable{TValue}"/> that represents the deserialized response body.</returns>
+        /// <exception cref="ArgumentNullException">
+        /// The <paramref name="content"/> is <see langword="null"/>.
+        /// </exception>
+        [RequiresUnreferencedCode(SerializationUnreferencedCodeMessage)]
+        [RequiresDynamicCode(SerializationDynamicCodeMessage)]
+        public static IAsyncEnumerable<TValue?> ReadFromJsonAsAsyncEnumerable<TValue>(
+            this HttpContent content,
+            JsonSerializerOptions? options,
+            CancellationToken cancellationToken = default)
+        {
+            if (content is null)
+            {
+                throw new ArgumentNullException(nameof(content));
+            }
+
+            return ReadFromJsonAsAsyncEnumerableCore<TValue>(content, options, cancellationToken);
+        }
+
+        [RequiresUnreferencedCode(SerializationUnreferencedCodeMessage)]
+        [RequiresDynamicCode(SerializationDynamicCodeMessage)]
+        private static IAsyncEnumerable<TValue?> ReadFromJsonAsAsyncEnumerableCore<TValue>(
+            HttpContent content,
+            JsonSerializerOptions? options,
+            CancellationToken cancellationToken)
+        {
+            options ??= JsonSerializerOptions.Default;
+            options.MakeReadOnly();
+
+            var jsonTypeInfo = (JsonTypeInfo<TValue>)options.GetTypeInfo(typeof(TValue));
+
+            return ReadFromJsonAsAsyncEnumerableCore(content, jsonTypeInfo, cancellationToken);
+        }
+
+        public static IAsyncEnumerable<TValue?> ReadFromJsonAsAsyncEnumerable<TValue>(
+            this HttpContent content,
+            JsonTypeInfo<TValue> jsonTypeInfo,
+            CancellationToken cancellationToken = default)
+        {
+            if (content is null)
+            {
+                throw new ArgumentNullException(nameof(content));
+            }
+
+            return ReadFromJsonAsAsyncEnumerableCore(content, jsonTypeInfo, cancellationToken);
+        }
+
+        private static async IAsyncEnumerable<TValue?> ReadFromJsonAsAsyncEnumerableCore<TValue>(
+            HttpContent content,
+            JsonTypeInfo<TValue> jsonTypeInfo,
+            [EnumeratorCancellation] CancellationToken cancellationToken)
+        {
+            using Stream contentStream = await GetContentStreamAsync(content, cancellationToken)
+                .ConfigureAwait(false);
+
+            await foreach (TValue? value in JsonSerializer.DeserializeAsyncEnumerable<TValue>(
+                contentStream, jsonTypeInfo, cancellationToken)
+                .ConfigureAwait(false))
+            {
+                yield return value;
+            }
+        }
+    }
+}
index 6c142df..328f28f 100644 (file)
@@ -1,8 +1,11 @@
 ï»¿// Licensed to the .NET Foundation under one or more agreements.
 // The .NET Foundation licenses this file to you under the MIT license.
 
+using System;
 using System.Collections.Generic;
+using System.ComponentModel;
 using System.Linq;
+using System.Net.Http;
 using System.Net.Test.Common;
 using System.Text.Json;
 using System.Threading;
@@ -115,7 +118,8 @@ namespace System.Net.Http.Json.Functional.Tests
                         Assert.True(response8.StatusCode == HttpStatusCode.OK);
                     }
                 },
-                async server => {
+                async server =>
+                {
                     HttpRequestData request = await server.HandleRequestAsync();
                     ValidateRequest(request, "POST");
                     Person per = JsonSerializer.Deserialize<Person>(request.Body, JsonOptions.DefaultSerializerOptions);
@@ -159,7 +163,8 @@ namespace System.Net.Http.Json.Functional.Tests
                         Assert.True(response8.StatusCode == HttpStatusCode.OK);
                     }
                 },
-                async server => {
+                async server =>
+                {
                     HttpRequestData request = await server.HandleRequestAsync();
                     ValidateRequest(request, "PUT");
 
@@ -210,7 +215,8 @@ namespace System.Net.Http.Json.Functional.Tests
                         Assert.True(response8.StatusCode == HttpStatusCode.OK);
                     }
                 },
-                async server => {
+                async server =>
+                {
                     HttpRequestData request = await server.HandleRequestAsync();
                     ValidateRequest(request, "PATCH");
                     byte[] json = request.Body;
@@ -260,7 +266,8 @@ namespace System.Net.Http.Json.Functional.Tests
                         Assert.IsType<Person>(response).Validate();
                     }
                 },
-                async server => {
+                async server =>
+                {
                     HttpRequestData request = await server.HandleRequestAsync();
                     Assert.Equal("DELETE", request.Method);
 
@@ -288,6 +295,13 @@ namespace System.Net.Http.Json.Functional.Tests
             AssertExtensions.Throws<ArgumentNullException>(clientParamName, () => client.GetFromJsonAsync(uriString, JsonContext.Default.Person));
             AssertExtensions.Throws<ArgumentNullException>(clientParamName, () => client.GetFromJsonAsync(uri, JsonContext.Default.Person));
 
+            AssertExtensions.Throws<ArgumentNullException>(clientParamName, () => client.GetFromJsonAsAsyncEnumerable<Person>(uriString));
+            AssertExtensions.Throws<ArgumentNullException>(clientParamName, () => client.GetFromJsonAsAsyncEnumerable<Person>(uri));
+            AssertExtensions.Throws<ArgumentNullException>(clientParamName, () => client.GetFromJsonAsAsyncEnumerable<Person>(uriString, options: null));
+            AssertExtensions.Throws<ArgumentNullException>(clientParamName, () => client.GetFromJsonAsAsyncEnumerable<Person>(uri, options: null));
+            AssertExtensions.Throws<ArgumentNullException>(clientParamName, () => client.GetFromJsonAsAsyncEnumerable<Person>(uriString, jsonTypeInfo: null));
+            AssertExtensions.Throws<ArgumentNullException>(clientParamName, () => client.GetFromJsonAsAsyncEnumerable<Person>(uri, jsonTypeInfo: null));
+
             AssertExtensions.Throws<ArgumentNullException>(clientParamName, () => client.PostAsJsonAsync<Person>(uriString, null));
             AssertExtensions.Throws<ArgumentNullException>(clientParamName, () => client.PostAsJsonAsync<Person>(uri, null));
             AssertExtensions.Throws<ArgumentNullException>(clientParamName, () => client.PostAsJsonAsync(uriString, null, JsonContext.Default.Person));
@@ -314,6 +328,9 @@ namespace System.Net.Http.Json.Functional.Tests
             AssertExtensions.Throws<ArgumentNullException>(jsonTypeInfoParamName, () => client.GetFromJsonAsync(uriString, JsonContext.Default.Person));
             AssertExtensions.Throws<ArgumentNullException>(jsonTypeInfoParamName, () => client.GetFromJsonAsync(uri, JsonContext.Default.Person));
 
+            AssertExtensions.Throws<ArgumentNullException>(jsonTypeInfoParamName, () => client.GetFromJsonAsAsyncEnumerable(uriString, JsonContext.Default.Person));
+            AssertExtensions.Throws<ArgumentNullException>(jsonTypeInfoParamName, () => client.GetFromJsonAsAsyncEnumerable(uri, JsonContext.Default.Person));
+
             AssertExtensions.Throws<ArgumentNullException>(jsonTypeInfoParamName, () => client.PostAsJsonAsync(uriString, null, JsonContext.Default.Person));
             AssertExtensions.Throws<ArgumentNullException>(jsonTypeInfoParamName, () => client.PostAsJsonAsync(uri, null, JsonContext.Default.Person));
 
@@ -347,7 +364,8 @@ namespace System.Net.Http.Json.Functional.Tests
                         per = await client.GetFromJsonAsync<Person>((Uri)null);
                     }
                 },
-                async server => {
+                async server =>
+                {
                     List<HttpHeaderData> headers = new List<HttpHeaderData> { new HttpHeaderData("Content-Type", "application/json") };
                     string json = Person.Create().Serialize();
 
@@ -355,6 +373,53 @@ namespace System.Net.Http.Json.Functional.Tests
                 });
         }
 
+        [Fact]
+        public async Task AllowNullRequestUrlAsAsyncEnumerable()
+        {
+            await HttpMessageHandlerLoopbackServer.CreateClientAndServerAsync(
+                async (handler, uri) =>
+                {
+                    using (HttpClient client = new HttpClient(handler))
+                    {
+                        client.BaseAddress = uri;
+
+                        static void AssertPeopleEquality(List<Person> actualPeople)
+                        {
+                            for (int i = 0; i < People.WomenOfProgramming.Length; i++)
+                            {
+                                var expected = People.WomenOfProgramming[i];
+                                var actual = actualPeople[i];
+
+                                Person.AssertPersonEquality(expected, actual);
+                            }
+                        }
+
+                        List<Person> people = new List<Person>();
+                        await foreach (Person? person in client.GetFromJsonAsAsyncEnumerable<Person>((string)null))
+                        {
+                            people.Add(Assert.IsType<Person>(person));
+                        }
+
+                        AssertPeopleEquality(people);
+
+                        people = new List<Person>();
+                        await foreach (Person? person in client.GetFromJsonAsAsyncEnumerable<Person>((Uri)null))
+                        {
+                            people.Add(Assert.IsType<Person>(person));
+                        }
+
+                        AssertPeopleEquality(people);
+                    }
+                },
+                async server =>
+                {
+                    List<HttpHeaderData> headers = new List<HttpHeaderData> { new HttpHeaderData("Content-Type", "application/json") };
+                    string json = People.Serialize();
+
+                    await server.HandleRequestAsync(content: json, headers: headers);
+                });
+        }
+
         public static IEnumerable<object[]> GetFromJsonAsync_EnforcesMaxResponseContentBufferSize_MemberData() =>
             from useDeleteAsync in new[] { true, false }
             from limit in new[] { 2, 100, 100000 }
@@ -413,7 +478,55 @@ namespace System.Net.Http.Json.Functional.Tests
                 Exception ex = await Assert.ThrowsAsync<TaskCanceledException>(() =>
                     useDeleteAsync ? client.DeleteFromJsonAsync<string>(uri) : client.GetFromJsonAsync<string>(uri));
 
-#if NETCORE
+#if NETCOREAPP
+                Assert.Contains("HttpClient.Timeout", ex.Message);
+                Assert.IsType<TimeoutException>(ex.InnerException);
+#endif
+
+                exceptionThrown.SetResult(0);
+            },
+            async server =>
+            {
+                // The client may timeout before even connecting the server
+                await Task.WhenAny(exceptionThrown.Task, Task.Run(async () =>
+                {
+                    try
+                    {
+                        await server.AcceptConnectionAsync(async connection =>
+                        {
+                            if (!slowHeaders)
+                            {
+                                await connection.SendPartialResponseHeadersAsync(headers: new[] { new HttpHeaderData("Content-Length", "42") });
+                            }
+
+                            await exceptionThrown.Task;
+                        });
+                    }
+                    catch { }
+                }));
+            });
+        }
+
+        [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))] // No Socket support
+        [InlineData(true)]
+        [InlineData(false)]
+        public async Task GetFromJsonAsAsyncEnumerable_EnforcesTimeout(bool slowHeaders)
+        {
+            TaskCompletionSource<byte> exceptionThrown = new(TaskCreationOptions.RunContinuationsAsynchronously);
+
+            await LoopbackServer.CreateClientAndServerAsync(async uri =>
+            {
+                using var client = new HttpClient { Timeout = TimeSpan.FromMilliseconds(100) };
+
+                Exception ex = await Assert.ThrowsAsync<TaskCanceledException>(async () =>
+                {
+                    await foreach (string? str in client.GetFromJsonAsAsyncEnumerable<string>(uri))
+                    {
+                        _ = str;
+                    }
+                });
+
+#if NETCOREAPP
                 Assert.Contains("HttpClient.Timeout", ex.Message);
                 Assert.IsType<TimeoutException>(ex.InnerException);
 #endif
@@ -441,5 +554,42 @@ namespace System.Net.Http.Json.Functional.Tests
                 }));
             });
         }
+
+        [Fact]
+        public async Task GetFromJsonAsAsyncEnumerable_EnforcesTimeoutOnInitialRequest()
+        {
+            // Using CustomResponseHandler here to effectively skip the Timeout for the initial request.
+            using var client = new HttpClient(new CustomResponseHandler((r, c) =>
+            {
+                string[] values = { "1", "2", "3", "4", "5", "6", "7", "8", "9", "10" };
+                string json = JsonSerializer.Serialize(values);
+                HttpResponseMessage response = new()
+                {
+                    Content = new StringContent(json)
+                };
+
+                return Task.FromResult(response);
+            }))
+            {
+                Timeout = TimeSpan.FromMilliseconds(1)
+            };
+
+            await foreach (string s in client.GetFromJsonAsAsyncEnumerable<string>("http://dummyUrl"))
+            {
+                // Wait longer than the timeout.
+                await Task.Delay(TimeSpan.FromMilliseconds(10));
+            }
+        }
     }
 }
+
+file sealed class CustomResponseHandler : HttpMessageHandler
+{
+    private readonly Func<HttpRequestMessage, CancellationToken, Task<HttpResponseMessage>> _func;
+
+    public CustomResponseHandler(
+        Func<HttpRequestMessage, CancellationToken, Task<HttpResponseMessage>> func) => _func = func;
+
+    protected override Task<HttpResponseMessage> SendAsync(
+        HttpRequestMessage request, CancellationToken cancellationToken) => _func(request, cancellationToken);
+}
index 450df41..6d2be61 100644 (file)
@@ -20,6 +20,10 @@ namespace System.Net.Http.Json.Functional.Tests
             HttpContent content = null;
             AssertExtensions.Throws<ArgumentNullException>("content", () => content.ReadFromJsonAsync<Person>());
             AssertExtensions.Throws<ArgumentNullException>("content", () => content.ReadFromJsonAsync(typeof(Person)));
+
+            AssertExtensions.Throws<ArgumentNullException>("content", () => content.ReadFromJsonAsAsyncEnumerable<Person>());
+            AssertExtensions.Throws<ArgumentNullException>("content", () => content.ReadFromJsonAsAsyncEnumerable<Person>(options: null));
+            AssertExtensions.Throws<ArgumentNullException>("content", () => content.ReadFromJsonAsAsyncEnumerable<Person>(jsonTypeInfo: null));
         }
 
         [Theory]
@@ -55,13 +59,6 @@ namespace System.Net.Http.Json.Functional.Tests
                 {
                     using (HttpClient client = new HttpClient(handler))
                     {
-                        static void AssertPersonEquality(Person first, Person second)
-                        {
-                            Assert.Equal(first.Age, second.Age);
-                            Assert.Equal(first.Name, second.Name);
-                            Assert.Equal(first.Parent, second.Parent);
-                            Assert.Equal(first.PlaceOfBirth, second.PlaceOfBirth);
-                        }
                         var request = new HttpRequestMessage(HttpMethod.Get, uri);
                         HttpResponseMessage response = await client.SendAsync(request);
                         Person per1 = (Person) await response.Content.ReadFromJsonAsync(typeof(Person));
@@ -71,7 +68,7 @@ namespace System.Net.Http.Json.Functional.Tests
                         response = await client.SendAsync(request);
                         Person per2 = (Person) await response.Content.ReadFromJsonAsync(typeof(Person), options: null);
                         per2.Validate();
-                        AssertPersonEquality(per1, per2);
+                        Person.AssertPersonEquality(per1, per2);
 
                         request = new HttpRequestMessage(HttpMethod.Get, uri);
                         response = await client.SendAsync(request);
@@ -82,7 +79,7 @@ namespace System.Net.Http.Json.Functional.Tests
                         response = await client.SendAsync(request);
                         per2 = await response.Content.ReadFromJsonAsync<Person>(options:null);
                         per2.Validate();
-                        AssertPersonEquality(per1, per2);
+                        Person.AssertPersonEquality(per1, per2);
                     }
                 },
                 server => server.HandleRequestAsync(headers: _headers, content: json));
@@ -118,6 +115,50 @@ namespace System.Net.Http.Json.Functional.Tests
         }
 
         [Fact]
+        public async Task HttpContentReturnValueIsNullWithAsAsyncEnumerable()
+        {
+            await HttpMessageHandlerLoopbackServer.CreateClientAndServerAsync(
+                async (handler, uri) =>
+                {
+                    using (HttpClient client = new HttpClient(handler))
+                    {
+                        var request = new HttpRequestMessage(HttpMethod.Get, uri);
+                        HttpResponseMessage response = await client.SendAsync(request);
+                        await foreach (Person? per in response.Content.ReadFromJsonAsAsyncEnumerable<Person>())
+                        {
+                            Assert.Null(per);
+                        }
+                    }
+                },
+                server => server.HandleRequestAsync(headers: _headers, content: "null"));
+        }
+
+        [Fact]
+        public async Task TestReadFromJsonAsAsyncEnumerableNoMessageBodyAsync()
+        {
+            await HttpMessageHandlerLoopbackServer.CreateClientAndServerAsync(
+                async (handler, uri) =>
+                {
+                    using (HttpClient client = new HttpClient(handler))
+                    {
+                        var request = new HttpRequestMessage(HttpMethod.Get, uri);
+                        HttpResponseMessage response = await client.SendAsync(request);
+
+                        // As of now, we pass the message body to the serializer even when its empty which causes the serializer to throw.
+                        JsonException ex = await Assert.ThrowsAsync<JsonException>(async () =>
+                        {
+                            await foreach (Person? per in response.Content.ReadFromJsonAsAsyncEnumerable<Person>())
+                            {
+                                _ = per;
+                            }
+                        });
+                        Assert.Contains("Path: $ | LineNumber: 0 | BytePositionInLine: 0", ex.Message);
+                    }
+                },
+                server => server.HandleRequestAsync(headers: _headers));
+        }
+
+        [Fact]
         public async Task TestReadFromJsonNoMessageBodyAsync()
         {
             await HttpMessageHandlerLoopbackServer.CreateClientAndServerAsync(
@@ -210,6 +251,7 @@ namespace System.Net.Http.Json.Functional.Tests
                     await server.HandleRequestAsync(statusCode: HttpStatusCode.OK, headers: headers, bytes: Encoding.Unicode.GetBytes(json));
                 });
         }
+
         [Fact]
         public async Task EnsureDefaultJsonSerializerOptionsAsync()
         {
index 7154772..a1c8eff 100644 (file)
@@ -38,6 +38,32 @@ namespace System.Net.Http.Json.Functional.Tests
             options.NumberHandling = options.NumberHandling | JsonNumberHandling.WriteAsString;
             return JsonSerializer.Serialize(this, options);
         }
+
+        public static void AssertPersonEquality(Person first, Person second)
+        {
+            Assert.Equal(first.Age, second.Age);
+            Assert.Equal(first.Name, second.Name);
+            Assert.Equal(first.Parent, second.Parent);
+            Assert.Equal(first.PlaceOfBirth, second.PlaceOfBirth);
+        }
+    }
+
+    internal class People
+    {
+        public static int PeopleCount => WomenOfProgramming.Length;
+
+        public static Person[] WomenOfProgramming = new[]
+        {
+            new Person { Name = "Ada Lovelace", Age = 13_140, PlaceOfBirth = "London, England" },
+            new Person { Name = "Jean Bartik", Age = 31_390, PlaceOfBirth = "Alanthus Grove, Missouri, U.S." },
+            new Person { Name = "Grace Hopper", Age = 31_025, PlaceOfBirth = "New York City, New York, U.S." },
+            new Person { Name = "Margaret Hamilton", Age = 31_390, PlaceOfBirth = "Paoli, Indiana, U.S." },
+        };
+
+        public static string Serialize(JsonSerializerOptions options = null)
+        {
+            return JsonSerializer.Serialize(WomenOfProgramming, options);
+        }
     }
 
     internal static class JsonOptions