From: David Pine Date: Mon, 24 Jul 2023 16:51:40 +0000 (-0500) Subject: Implement new streaming APIs for the `System.Net.Http.Json` extensions (#89258) X-Git-Tag: accepted/tizen/unified/riscv/20231226.055536~817 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=08e3814f1011292621b2f0cc377257d313bb04c0;p=platform%2Fupstream%2Fdotnet%2Fruntime.git Implement new streaming APIs for the `System.Net.Http.Json` extensions (#89258) * 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 * 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 * Update src/libraries/System.Net.Http.Json/src/System/Net/Http/Json/HttpClientJsonExtensions.Get.AsyncEnumerable.cs Co-authored-by: Eirik Tsarpalis * 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 Co-authored-by: Miha Zupan --- diff --git a/src/libraries/System.Net.Http.Json/ref/System.Net.Http.Json.cs b/src/libraries/System.Net.Http.Json/ref/System.Net.Http.Json.cs index b1520a4..efde74c 100644 --- a/src/libraries/System.Net.Http.Json/ref/System.Net.Http.Json.cs +++ b/src/libraries/System.Net.Http.Json/ref/System.Net.Http.Json.cs @@ -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 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 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 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 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 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 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 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 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 DeleteFromJsonAsync(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 DeleteFromJsonAsync(this System.Net.Http.HttpClient client, [System.Diagnostics.CodeAnalysis.StringSyntaxAttribute("Uri")] string? requestUri, System.Text.Json.Serialization.Metadata.JsonTypeInfo 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 DeleteFromJsonAsync(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 DeleteFromJsonAsync(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 DeleteFromJsonAsync(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 DeleteFromJsonAsync(this System.Net.Http.HttpClient client, System.Uri? requestUri, System.Text.Json.Serialization.Metadata.JsonTypeInfo 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 DeleteFromJsonAsync(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 GetFromJsonAsAsyncEnumerable(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 GetFromJsonAsAsyncEnumerable(this System.Net.Http.HttpClient client, [System.Diagnostics.CodeAnalysis.StringSyntaxAttribute("Uri")] string? requestUri, System.Text.Json.Serialization.Metadata.JsonTypeInfo 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 GetFromJsonAsAsyncEnumerable(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 GetFromJsonAsAsyncEnumerable(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 GetFromJsonAsAsyncEnumerable(this System.Net.Http.HttpClient client, System.Uri? requestUri, System.Text.Json.Serialization.Metadata.JsonTypeInfo 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 GetFromJsonAsAsyncEnumerable(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 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 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 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 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 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 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 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 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 GetFromJsonAsync(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 GetFromJsonAsync(this System.Net.Http.HttpClient client, [System.Diagnostics.CodeAnalysis.StringSyntaxAttribute("Uri")] string? requestUri, System.Text.Json.Serialization.Metadata.JsonTypeInfo 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 GetFromJsonAsync(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 GetFromJsonAsync(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 GetFromJsonAsync(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 GetFromJsonAsync(this System.Net.Http.HttpClient client, System.Uri? requestUri, System.Text.Json.Serialization.Metadata.JsonTypeInfo 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 GetFromJsonAsync(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 GetFromJsonAsync(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 PostAsJsonAsync(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 PostAsJsonAsync(this System.Net.Http.HttpClient client, [System.Diagnostics.CodeAnalysis.StringSyntaxAttribute("Uri")] string? requestUri, TValue value, System.Text.Json.Serialization.Metadata.JsonTypeInfo 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 PatchAsJsonAsync(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 PatchAsJsonAsync(this System.Net.Http.HttpClient client, [System.Diagnostics.CodeAnalysis.StringSyntaxAttribute("Uri")] string? requestUri, TValue value, System.Text.Json.Serialization.Metadata.JsonTypeInfo 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 PostAsJsonAsync(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 PatchAsJsonAsync(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 PostAsJsonAsync(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 PostAsJsonAsync(this System.Net.Http.HttpClient client, System.Uri? requestUri, TValue value, System.Text.Json.Serialization.Metadata.JsonTypeInfo 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 PatchAsJsonAsync(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 PatchAsJsonAsync(this System.Net.Http.HttpClient client, System.Uri? requestUri, TValue value, System.Text.Json.Serialization.Metadata.JsonTypeInfo 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 PostAsJsonAsync(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 PatchAsJsonAsync(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 PutAsJsonAsync(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 PutAsJsonAsync(this System.Net.Http.HttpClient client, [System.Diagnostics.CodeAnalysis.StringSyntaxAttribute("Uri")] string? requestUri, TValue value, System.Text.Json.Serialization.Metadata.JsonTypeInfo 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 PostAsJsonAsync(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 PostAsJsonAsync(this System.Net.Http.HttpClient client, [System.Diagnostics.CodeAnalysis.StringSyntaxAttribute("Uri")] string? requestUri, TValue value, System.Text.Json.Serialization.Metadata.JsonTypeInfo 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 PutAsJsonAsync(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 PostAsJsonAsync(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 PutAsJsonAsync(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 PutAsJsonAsync(this System.Net.Http.HttpClient client, System.Uri? requestUri, TValue value, System.Text.Json.Serialization.Metadata.JsonTypeInfo 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 PostAsJsonAsync(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 PostAsJsonAsync(this System.Net.Http.HttpClient client, System.Uri? requestUri, TValue value, System.Text.Json.Serialization.Metadata.JsonTypeInfo 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 PutAsJsonAsync(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 PostAsJsonAsync(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 PatchAsJsonAsync(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 PatchAsJsonAsync(this System.Net.Http.HttpClient client, [System.Diagnostics.CodeAnalysis.StringSyntaxAttribute("Uri")] string? requestUri, TValue value, System.Text.Json.Serialization.Metadata.JsonTypeInfo 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 PutAsJsonAsync(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 PutAsJsonAsync(this System.Net.Http.HttpClient client, [System.Diagnostics.CodeAnalysis.StringSyntaxAttribute("Uri")] string? requestUri, TValue value, System.Text.Json.Serialization.Metadata.JsonTypeInfo 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 PatchAsJsonAsync(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 PutAsJsonAsync(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 PatchAsJsonAsync(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 PatchAsJsonAsync(this System.Net.Http.HttpClient client, System.Uri? requestUri, TValue value, System.Text.Json.Serialization.Metadata.JsonTypeInfo 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 PutAsJsonAsync(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 PutAsJsonAsync(this System.Net.Http.HttpClient client, System.Uri? requestUri, TValue value, System.Text.Json.Serialization.Metadata.JsonTypeInfo 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 PatchAsJsonAsync(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 PutAsJsonAsync(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 ReadFromJsonAsAsyncEnumerable(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 ReadFromJsonAsAsyncEnumerable(this System.Net.Http.HttpContent content, System.Text.Json.Serialization.Metadata.JsonTypeInfo 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 ReadFromJsonAsAsyncEnumerable(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 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 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.")] diff --git a/src/libraries/System.Net.Http.Json/src/System.Net.Http.Json.csproj b/src/libraries/System.Net.Http.Json/src/System.Net.Http.Json.csproj index 34f94be..9ed9b54 100644 --- a/src/libraries/System.Net.Http.Json/src/System.Net.Http.Json.csproj +++ b/src/libraries/System.Net.Http.Json/src/System.Net.Http.Json.csproj @@ -11,7 +11,9 @@ System.Net.Http.Json.JsonContent + + 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 index 0000000..057bf87 --- /dev/null +++ b/src/libraries/System.Net.Http.Json/src/System/Net/Http/Json/HttpClientJsonExtensions.Get.AsyncEnumerable.cs @@ -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 + { + /// + /// Sends an HTTP GET request to the specified and returns the value that results + /// from deserializing the response body as JSON in an async enumerable operation. + /// + /// The target type to deserialize to. + /// The client used to send the request. + /// The Uri the request is sent to. + /// + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// An that represents the deserialized response body. + /// The is . + [RequiresUnreferencedCode(HttpContentJsonExtensions.SerializationUnreferencedCodeMessage)] + [RequiresDynamicCode(HttpContentJsonExtensions.SerializationDynamicCodeMessage)] + public static IAsyncEnumerable GetFromJsonAsAsyncEnumerable( + this HttpClient client, + [StringSyntax(StringSyntaxAttribute.Uri)] string? requestUri, + JsonSerializerOptions? options, + CancellationToken cancellationToken = default) => + GetFromJsonAsAsyncEnumerable(client, CreateUri(requestUri), options, cancellationToken); + + /// + /// Sends an HTTP GETrequest to the specified and returns the value that results + /// from deserializing the response body as JSON in an async enumerable operation. + /// + /// The target type to deserialize to. + /// The client used to send the request. + /// The Uri the request is sent to. + /// + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// An that represents the deserialized response body. + /// The is . + [RequiresUnreferencedCode(HttpContentJsonExtensions.SerializationUnreferencedCodeMessage)] + [RequiresDynamicCode(HttpContentJsonExtensions.SerializationDynamicCodeMessage)] + public static IAsyncEnumerable GetFromJsonAsAsyncEnumerable( + this HttpClient client, + Uri? requestUri, + JsonSerializerOptions? options, + CancellationToken cancellationToken = default) => + FromJsonStreamAsyncCore(client, requestUri, options, cancellationToken); + + /// + /// Sends an HTTP GETrequest to the specified and returns the value that results + /// from deserializing the response body as JSON in an async enumerable operation. + /// + /// The target type to deserialize to. + /// The client used to send the request. + /// The Uri the request is sent to. + /// Source generated JsonTypeInfo to control the behavior during deserialization. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// An that represents the deserialized response body. + /// The is . + public static IAsyncEnumerable GetFromJsonAsAsyncEnumerable( + this HttpClient client, + [StringSyntax(StringSyntaxAttribute.Uri)] string? requestUri, + JsonTypeInfo jsonTypeInfo, + CancellationToken cancellationToken = default) => + GetFromJsonAsAsyncEnumerable(client, CreateUri(requestUri), jsonTypeInfo, cancellationToken); + + /// + /// Sends an HTTP GETrequest to the specified and returns the value that results + /// from deserializing the response body as JSON in an async enumerable operation. + /// + /// The target type to deserialize to. + /// The client used to send the request. + /// The Uri the request is sent to. + /// Source generated JsonTypeInfo to control the behavior during deserialization. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// An that represents the deserialized response body. + /// The is . + public static IAsyncEnumerable GetFromJsonAsAsyncEnumerable( + this HttpClient client, + Uri? requestUri, + JsonTypeInfo jsonTypeInfo, + CancellationToken cancellationToken = default) => + FromJsonStreamAsyncCore(client, requestUri, jsonTypeInfo, cancellationToken); + + /// + /// Sends an HTTP GETrequest to the specified and returns the value that results + /// from deserializing the response body as JSON in an async enumerable operation. + /// + /// The target type to deserialize to. + /// The client used to send the request. + /// The Uri the request is sent to. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// An that represents the deserialized response body. + /// The is . + [RequiresUnreferencedCode(HttpContentJsonExtensions.SerializationUnreferencedCodeMessage)] + [RequiresDynamicCode(HttpContentJsonExtensions.SerializationDynamicCodeMessage)] + public static IAsyncEnumerable GetFromJsonAsAsyncEnumerable( + this HttpClient client, + [StringSyntax(StringSyntaxAttribute.Uri)] string? requestUri, + CancellationToken cancellationToken = default) => + GetFromJsonAsAsyncEnumerable(client, requestUri, options: null, cancellationToken); + + /// + /// Sends an HTTP GETrequest to the specified and returns the value that results + /// from deserializing the response body as JSON in an async enumerable operation. + /// + /// The target type to deserialize to. + /// The client used to send the request. + /// The Uri the request is sent to. + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// An that represents the deserialized response body. + /// The is . + [RequiresUnreferencedCode(HttpContentJsonExtensions.SerializationUnreferencedCodeMessage)] + [RequiresDynamicCode(HttpContentJsonExtensions.SerializationDynamicCodeMessage)] + public static IAsyncEnumerable GetFromJsonAsAsyncEnumerable( + this HttpClient client, + Uri? requestUri, + CancellationToken cancellationToken = default) => + GetFromJsonAsAsyncEnumerable(client, requestUri, options: null, cancellationToken); + + [RequiresUnreferencedCode(HttpContentJsonExtensions.SerializationUnreferencedCodeMessage)] + [RequiresDynamicCode(HttpContentJsonExtensions.SerializationDynamicCodeMessage)] + private static IAsyncEnumerable FromJsonStreamAsyncCore( + HttpClient client, + Uri? requestUri, + JsonSerializerOptions? options, + CancellationToken cancellationToken) + { + options ??= JsonSerializerOptions.Default; + options.MakeReadOnly(); + + var jsonTypeInfo = (JsonTypeInfo)options.GetTypeInfo(typeof(TValue)); + + return FromJsonStreamAsyncCore(client, requestUri, jsonTypeInfo, cancellationToken); + } + + private static IAsyncEnumerable FromJsonStreamAsyncCore( + HttpClient client, + Uri? requestUri, + JsonTypeInfo jsonTypeInfo, + CancellationToken cancellationToken) + { + if (client is null) + { + throw new ArgumentNullException(nameof(client)); + } + + return Core(client, requestUri, jsonTypeInfo, cancellationToken); + + static async IAsyncEnumerable Core( + HttpClient client, + Uri? requestUri, + JsonTypeInfo 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( + readStream, jsonTypeInfo, cancellationToken).ConfigureAwait(false)) + { + yield return value; + } + } + } + } +} diff --git a/src/libraries/System.Net.Http.Json/src/System/Net/Http/Json/HttpClientJsonExtensions.cs b/src/libraries/System.Net.Http.Json/src/System/Net/Http/Json/HttpClientJsonExtensions.cs index 234f8c3..4aa114c 100644 --- a/src/libraries/System.Net.Http.Json/src/System/Net/Http/Json/HttpClientJsonExtensions.cs +++ b/src/libraries/System.Net.Http.Json/src/System/Net/Http/Json/HttpClientJsonExtensions.cs @@ -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 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 index 0000000..c42f51d --- /dev/null +++ b/src/libraries/System.Net.Http.Json/src/System/Net/Http/Json/HttpContentJsonExtensions.AsyncEnumerable.cs @@ -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 + { + /// + /// Reads the HTTP content and returns the value that results from deserializing the content as + /// JSON in an async enumerable operation. + /// + /// The target type to deserialize to. + /// + /// + /// An that represents the deserialized response body. + /// + /// The is . + /// + [RequiresUnreferencedCode(SerializationUnreferencedCodeMessage)] + [RequiresDynamicCode(SerializationDynamicCodeMessage)] + public static IAsyncEnumerable ReadFromJsonAsAsyncEnumerable( + this HttpContent content, + CancellationToken cancellationToken = default) => + ReadFromJsonAsAsyncEnumerable(content, options: null, cancellationToken: cancellationToken); + + /// + /// Reads the HTTP content and returns the value that results from deserializing the content as + /// JSON in an async enumerable operation. + /// + /// The target type to deserialize to. + /// The content to read from. + /// Options to control the behavior during deserialization. + /// The default options are those specified by . + /// + /// An that represents the deserialized response body. + /// + /// The is . + /// + [RequiresUnreferencedCode(SerializationUnreferencedCodeMessage)] + [RequiresDynamicCode(SerializationDynamicCodeMessage)] + public static IAsyncEnumerable ReadFromJsonAsAsyncEnumerable( + this HttpContent content, + JsonSerializerOptions? options, + CancellationToken cancellationToken = default) + { + if (content is null) + { + throw new ArgumentNullException(nameof(content)); + } + + return ReadFromJsonAsAsyncEnumerableCore(content, options, cancellationToken); + } + + [RequiresUnreferencedCode(SerializationUnreferencedCodeMessage)] + [RequiresDynamicCode(SerializationDynamicCodeMessage)] + private static IAsyncEnumerable ReadFromJsonAsAsyncEnumerableCore( + HttpContent content, + JsonSerializerOptions? options, + CancellationToken cancellationToken) + { + options ??= JsonSerializerOptions.Default; + options.MakeReadOnly(); + + var jsonTypeInfo = (JsonTypeInfo)options.GetTypeInfo(typeof(TValue)); + + return ReadFromJsonAsAsyncEnumerableCore(content, jsonTypeInfo, cancellationToken); + } + + public static IAsyncEnumerable ReadFromJsonAsAsyncEnumerable( + this HttpContent content, + JsonTypeInfo jsonTypeInfo, + CancellationToken cancellationToken = default) + { + if (content is null) + { + throw new ArgumentNullException(nameof(content)); + } + + return ReadFromJsonAsAsyncEnumerableCore(content, jsonTypeInfo, cancellationToken); + } + + private static async IAsyncEnumerable ReadFromJsonAsAsyncEnumerableCore( + HttpContent content, + JsonTypeInfo jsonTypeInfo, + [EnumeratorCancellation] CancellationToken cancellationToken) + { + using Stream contentStream = await GetContentStreamAsync(content, cancellationToken) + .ConfigureAwait(false); + + await foreach (TValue? value in JsonSerializer.DeserializeAsyncEnumerable( + contentStream, jsonTypeInfo, cancellationToken) + .ConfigureAwait(false)) + { + yield return value; + } + } + } +} diff --git a/src/libraries/System.Net.Http.Json/tests/FunctionalTests/HttpClientJsonExtensionsTests.cs b/src/libraries/System.Net.Http.Json/tests/FunctionalTests/HttpClientJsonExtensionsTests.cs index 6c142df..328f28f 100644 --- a/src/libraries/System.Net.Http.Json/tests/FunctionalTests/HttpClientJsonExtensionsTests.cs +++ b/src/libraries/System.Net.Http.Json/tests/FunctionalTests/HttpClientJsonExtensionsTests.cs @@ -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(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(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(clientParamName, () => client.GetFromJsonAsync(uriString, JsonContext.Default.Person)); AssertExtensions.Throws(clientParamName, () => client.GetFromJsonAsync(uri, JsonContext.Default.Person)); + AssertExtensions.Throws(clientParamName, () => client.GetFromJsonAsAsyncEnumerable(uriString)); + AssertExtensions.Throws(clientParamName, () => client.GetFromJsonAsAsyncEnumerable(uri)); + AssertExtensions.Throws(clientParamName, () => client.GetFromJsonAsAsyncEnumerable(uriString, options: null)); + AssertExtensions.Throws(clientParamName, () => client.GetFromJsonAsAsyncEnumerable(uri, options: null)); + AssertExtensions.Throws(clientParamName, () => client.GetFromJsonAsAsyncEnumerable(uriString, jsonTypeInfo: null)); + AssertExtensions.Throws(clientParamName, () => client.GetFromJsonAsAsyncEnumerable(uri, jsonTypeInfo: null)); + AssertExtensions.Throws(clientParamName, () => client.PostAsJsonAsync(uriString, null)); AssertExtensions.Throws(clientParamName, () => client.PostAsJsonAsync(uri, null)); AssertExtensions.Throws(clientParamName, () => client.PostAsJsonAsync(uriString, null, JsonContext.Default.Person)); @@ -314,6 +328,9 @@ namespace System.Net.Http.Json.Functional.Tests AssertExtensions.Throws(jsonTypeInfoParamName, () => client.GetFromJsonAsync(uriString, JsonContext.Default.Person)); AssertExtensions.Throws(jsonTypeInfoParamName, () => client.GetFromJsonAsync(uri, JsonContext.Default.Person)); + AssertExtensions.Throws(jsonTypeInfoParamName, () => client.GetFromJsonAsAsyncEnumerable(uriString, JsonContext.Default.Person)); + AssertExtensions.Throws(jsonTypeInfoParamName, () => client.GetFromJsonAsAsyncEnumerable(uri, JsonContext.Default.Person)); + AssertExtensions.Throws(jsonTypeInfoParamName, () => client.PostAsJsonAsync(uriString, null, JsonContext.Default.Person)); AssertExtensions.Throws(jsonTypeInfoParamName, () => client.PostAsJsonAsync(uri, null, JsonContext.Default.Person)); @@ -347,7 +364,8 @@ namespace System.Net.Http.Json.Functional.Tests per = await client.GetFromJsonAsync((Uri)null); } }, - async server => { + async server => + { List headers = new List { 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 actualPeople) + { + for (int i = 0; i < People.WomenOfProgramming.Length; i++) + { + var expected = People.WomenOfProgramming[i]; + var actual = actualPeople[i]; + + Person.AssertPersonEquality(expected, actual); + } + } + + List people = new List(); + await foreach (Person? person in client.GetFromJsonAsAsyncEnumerable((string)null)) + { + people.Add(Assert.IsType(person)); + } + + AssertPeopleEquality(people); + + people = new List(); + await foreach (Person? person in client.GetFromJsonAsAsyncEnumerable((Uri)null)) + { + people.Add(Assert.IsType(person)); + } + + AssertPeopleEquality(people); + } + }, + async server => + { + List headers = new List { new HttpHeaderData("Content-Type", "application/json") }; + string json = People.Serialize(); + + await server.HandleRequestAsync(content: json, headers: headers); + }); + } + public static IEnumerable 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(() => useDeleteAsync ? client.DeleteFromJsonAsync(uri) : client.GetFromJsonAsync(uri)); -#if NETCORE +#if NETCOREAPP + Assert.Contains("HttpClient.Timeout", ex.Message); + Assert.IsType(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 exceptionThrown = new(TaskCreationOptions.RunContinuationsAsynchronously); + + await LoopbackServer.CreateClientAndServerAsync(async uri => + { + using var client = new HttpClient { Timeout = TimeSpan.FromMilliseconds(100) }; + + Exception ex = await Assert.ThrowsAsync(async () => + { + await foreach (string? str in client.GetFromJsonAsAsyncEnumerable(uri)) + { + _ = str; + } + }); + +#if NETCOREAPP Assert.Contains("HttpClient.Timeout", ex.Message); Assert.IsType(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("http://dummyUrl")) + { + // Wait longer than the timeout. + await Task.Delay(TimeSpan.FromMilliseconds(10)); + } + } } } + +file sealed class CustomResponseHandler : HttpMessageHandler +{ + private readonly Func> _func; + + public CustomResponseHandler( + Func> func) => _func = func; + + protected override Task SendAsync( + HttpRequestMessage request, CancellationToken cancellationToken) => _func(request, cancellationToken); +} diff --git a/src/libraries/System.Net.Http.Json/tests/FunctionalTests/HttpContentJsonExtensionsTests.cs b/src/libraries/System.Net.Http.Json/tests/FunctionalTests/HttpContentJsonExtensionsTests.cs index 450df41..6d2be61 100644 --- a/src/libraries/System.Net.Http.Json/tests/FunctionalTests/HttpContentJsonExtensionsTests.cs +++ b/src/libraries/System.Net.Http.Json/tests/FunctionalTests/HttpContentJsonExtensionsTests.cs @@ -20,6 +20,10 @@ namespace System.Net.Http.Json.Functional.Tests HttpContent content = null; AssertExtensions.Throws("content", () => content.ReadFromJsonAsync()); AssertExtensions.Throws("content", () => content.ReadFromJsonAsync(typeof(Person))); + + AssertExtensions.Throws("content", () => content.ReadFromJsonAsAsyncEnumerable()); + AssertExtensions.Throws("content", () => content.ReadFromJsonAsAsyncEnumerable(options: null)); + AssertExtensions.Throws("content", () => content.ReadFromJsonAsAsyncEnumerable(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(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()) + { + 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(async () => + { + await foreach (Person? per in response.Content.ReadFromJsonAsAsyncEnumerable()) + { + _ = 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() { diff --git a/src/libraries/System.Net.Http.Json/tests/FunctionalTests/TestClasses.cs b/src/libraries/System.Net.Http.Json/tests/FunctionalTests/TestClasses.cs index 7154772..a1c8eff 100644 --- a/src/libraries/System.Net.Http.Json/tests/FunctionalTests/TestClasses.cs +++ b/src/libraries/System.Net.Http.Json/tests/FunctionalTests/TestClasses.cs @@ -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