From 670e2eae4aeaeb017116aef2a3413e3883ddf08d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B8rn=20Moe?= Date: Thu, 26 Nov 2020 14:31:58 +0100 Subject: [PATCH 1/2] Add failing test --- Refit.Tests/RestService.cs | 45 +++++++++++++++++++ ...PooledBufferWriter.Stream.NETStandard21.cs | 2 +- 2 files changed, 46 insertions(+), 1 deletion(-) diff --git a/Refit.Tests/RestService.cs b/Refit.Tests/RestService.cs index 660a634b4..95c3c2837 100644 --- a/Refit.Tests/RestService.cs +++ b/Refit.Tests/RestService.cs @@ -27,6 +27,11 @@ public class RootObject } #pragma warning restore IDE1006 // Naming Styles + public class BigObject + { + public byte[] BigData { get; set; } + } + [Headers("User-Agent: Refit Integration Tests")] public interface INpmJs { @@ -50,7 +55,11 @@ public interface IRequestBin [Post("/1h3a5jm1")] Task PostGeneric(T param); + + [Post("/big")] + Task PostBig(BigObject big); } + public interface IApiBindPathToObject { [Get("/foos/{request.someProperty}/bar/{request.someProperty2}")] @@ -1312,6 +1321,42 @@ public async Task CanGetDataOutOfErrorResponses() } } + [Fact] + public async Task CanSerializeBigData() + { + var mockHttp = new MockHttpMessageHandler(); + + var settings = new RefitSettings + { + HttpMessageHandlerFactory = () => mockHttp, + ContentSerializer = new SystemTextJsonContentSerializer() + }; + + var bigObject = new BigObject + { + BigData = Enumerable.Range(0, 800000).Select(x => (byte)(x % 256)).ToArray() + }; + + mockHttp.Expect(HttpMethod.Post, "http://httpbin.org/big") + .With(m => + { + async Task T() + { + using var s = await m.Content.ReadAsStreamAsync(); + var it = await System.Text.Json.JsonSerializer.DeserializeAsync(s, new System.Text.Json.JsonSerializerOptions { PropertyNamingPolicy = System.Text.Json.JsonNamingPolicy.CamelCase }); + return it.BigData.SequenceEqual(bigObject.BigData); + } + + return T().Result; + }) + .Respond(HttpStatusCode.OK); + + var fixture = RestService.For("http://httpbin.org/", settings); + + await fixture.PostBig(bigObject); + + mockHttp.VerifyNoOutstandingExpectation(); + } [Fact] public async Task ErrorsFromApiReturnErrorContent() diff --git a/Refit/Buffers/PooledBufferWriter.Stream.NETStandard21.cs b/Refit/Buffers/PooledBufferWriter.Stream.NETStandard21.cs index 4b24b9dfa..69f2eb62e 100644 --- a/Refit/Buffers/PooledBufferWriter.Stream.NETStandard21.cs +++ b/Refit/Buffers/PooledBufferWriter.Stream.NETStandard21.cs @@ -1,4 +1,4 @@ -#if NETSTANDARD2_1 +#if NETSTANDARD2_1 || NET5_0 using System; using System.IO; From f01a96bc63d7837d619c9cef8fd0428225600002 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B8rn=20Moe?= Date: Thu, 26 Nov 2020 10:39:04 +0100 Subject: [PATCH 2/2] Fixes issue #952 - we did not actually write everything to output stream. --- Refit.Tests/RefitStubs.Net46.cs | 8 ++++++++ Refit.Tests/RefitStubs.Net5.cs | 8 ++++++++ Refit.Tests/RefitStubs.NetCore2.cs | 8 ++++++++ Refit.Tests/RefitStubs.NetCore3.cs | 8 ++++++++ Refit/Buffers/PooledBufferWriter.Stream.NETStandard21.cs | 7 +++---- Refit/Buffers/PooledBufferWriter.Stream.cs | 5 ++++- 6 files changed, 39 insertions(+), 5 deletions(-) diff --git a/Refit.Tests/RefitStubs.Net46.cs b/Refit.Tests/RefitStubs.Net46.cs index eec4ceca7..c3d8e5b98 100644 --- a/Refit.Tests/RefitStubs.Net46.cs +++ b/Refit.Tests/RefitStubs.Net46.cs @@ -2542,6 +2542,14 @@ Task IRequestBin.PostGeneric(T param) var func = requestBuilder.BuildRestResultFuncForMethod("PostGeneric", new Type[] { typeof(T) }, new Type[] { typeof(T) }); return (Task)func(Client, arguments); } + + /// + Task IRequestBin.PostBig(BigObject big) + { + var arguments = new object[] { big }; + var func = requestBuilder.BuildRestResultFuncForMethod("PostBig", new Type[] { typeof(BigObject) }); + return (Task)func(Client, arguments); + } } } diff --git a/Refit.Tests/RefitStubs.Net5.cs b/Refit.Tests/RefitStubs.Net5.cs index eec4ceca7..c3d8e5b98 100644 --- a/Refit.Tests/RefitStubs.Net5.cs +++ b/Refit.Tests/RefitStubs.Net5.cs @@ -2542,6 +2542,14 @@ Task IRequestBin.PostGeneric(T param) var func = requestBuilder.BuildRestResultFuncForMethod("PostGeneric", new Type[] { typeof(T) }, new Type[] { typeof(T) }); return (Task)func(Client, arguments); } + + /// + Task IRequestBin.PostBig(BigObject big) + { + var arguments = new object[] { big }; + var func = requestBuilder.BuildRestResultFuncForMethod("PostBig", new Type[] { typeof(BigObject) }); + return (Task)func(Client, arguments); + } } } diff --git a/Refit.Tests/RefitStubs.NetCore2.cs b/Refit.Tests/RefitStubs.NetCore2.cs index eec4ceca7..c3d8e5b98 100644 --- a/Refit.Tests/RefitStubs.NetCore2.cs +++ b/Refit.Tests/RefitStubs.NetCore2.cs @@ -2542,6 +2542,14 @@ Task IRequestBin.PostGeneric(T param) var func = requestBuilder.BuildRestResultFuncForMethod("PostGeneric", new Type[] { typeof(T) }, new Type[] { typeof(T) }); return (Task)func(Client, arguments); } + + /// + Task IRequestBin.PostBig(BigObject big) + { + var arguments = new object[] { big }; + var func = requestBuilder.BuildRestResultFuncForMethod("PostBig", new Type[] { typeof(BigObject) }); + return (Task)func(Client, arguments); + } } } diff --git a/Refit.Tests/RefitStubs.NetCore3.cs b/Refit.Tests/RefitStubs.NetCore3.cs index eec4ceca7..c3d8e5b98 100644 --- a/Refit.Tests/RefitStubs.NetCore3.cs +++ b/Refit.Tests/RefitStubs.NetCore3.cs @@ -2542,6 +2542,14 @@ Task IRequestBin.PostGeneric(T param) var func = requestBuilder.BuildRestResultFuncForMethod("PostGeneric", new Type[] { typeof(T) }, new Type[] { typeof(T) }); return (Task)func(Client, arguments); } + + /// + Task IRequestBin.PostBig(BigObject big) + { + var arguments = new object[] { big }; + var func = requestBuilder.BuildRestResultFuncForMethod("PostBig", new Type[] { typeof(BigObject) }); + return (Task)func(Client, arguments); + } } } diff --git a/Refit/Buffers/PooledBufferWriter.Stream.NETStandard21.cs b/Refit/Buffers/PooledBufferWriter.Stream.NETStandard21.cs index 69f2eb62e..a244fd7ee 100644 --- a/Refit/Buffers/PooledBufferWriter.Stream.NETStandard21.cs +++ b/Refit/Buffers/PooledBufferWriter.Stream.NETStandard21.cs @@ -14,18 +14,17 @@ internal sealed partial class PooledBufferWriter private sealed partial class PooledMemoryStream : Stream { /// - public override void CopyTo(Stream destination, int bufferSize) + public Task CopyToInternalAsync(Stream destination, CancellationToken cancellationToken) { if (pooledBuffer is null) ThrowObjectDisposedException(); var bytesAvailable = length - position; - var spanLength = Math.Min(bytesAvailable, bufferSize); - var source = pooledBuffer.AsSpan(position, spanLength); + var source = pooledBuffer.AsMemory(position, bytesAvailable); position += source.Length; - destination.Write(source); + return destination.WriteAsync(source, cancellationToken).AsTask(); } /// diff --git a/Refit/Buffers/PooledBufferWriter.Stream.cs b/Refit/Buffers/PooledBufferWriter.Stream.cs index 912eb54c6..363cf5810 100644 --- a/Refit/Buffers/PooledBufferWriter.Stream.cs +++ b/Refit/Buffers/PooledBufferWriter.Stream.cs @@ -91,9 +91,12 @@ public override Task CopyToAsync(Stream destination, int bufferSize, Cancellatio try { +#if NETSTANDARD2_1 || NET5_0 + return CopyToInternalAsync(destination, cancellationToken); +#else CopyTo(destination, bufferSize); - return Task.CompletedTask; +#endif } catch (OperationCanceledException e) {