0

I'm developing a WPF web client using dotnet Core 3.x, and I'm utilising the System.Text.Json APIs. I am trying to use a Stream to pass the data between objects to minimise peak memory usage, as some large messages are being sent.

The wrapper method I've written thus far looks like the following:

        public async Task<TResponse> PutItem<TItem, TResponse>(string path, TItem item)
        {
            HttpResponseMessage response;
            await using (Stream stream = new MemoryStream())
            {
                await JsonSerializer.SerializeAsync(stream, item);
                var requestContent = new StreamContent(stream);
                requestContent.Headers.ContentType = new MediaTypeHeaderValue("application/json");
                response = await _client.PutAsync(path, requestContent);
            }

            if (!response.IsSuccessStatusCode || response.Content == null)
            {
                return default;
            }

            string content = await response.Content.ReadAsStringAsync();
            TResponse decodedResponse = JsonSerializer.Deserialize<TResponse>(content);
            return decodedResponse;
        }

However it does not appear to be writing any content when PUTting to the server.

I have seen users of earlier APIs utilise the PushStreamContent class, however this doesn't appear to exist in dotnet Core.

Any ideas would be very much appreciated, thanks!

dbc
  • 104,963
  • 20
  • 228
  • 340
David G
  • 172
  • 2
  • 10

1 Answers1

3

I suppose the reason your current code does not work because you do not reset the stream position to 0 after serializing. However, because you create a MemoryStream you are still serializing to JSON in memory.

PushStreamContent is available by referencing the NuGet package Microsoft.AspNet.WebApi.Client.

Try something like:

var requestContent = new PushStreamContent(async (outputStream, httpContext, transportContext) =>
{
    await JsonSerializer.SerializeAsync(outputStream, item);
});
requestContent.Headers.ContentType = new MediaTypeHeaderValue("application/json");
var response = await _client.PutAsync(path, requestContent);
skwas
  • 56
  • 3
  • Many thanks for that nugget of information - documentation on `PushStreamContent` appears to be scant at best! The above solution didn't quite work as expected however. Having read this document: https://blog.stephencleary.com/2016/10/async-pushstreamcontent-historical-note.html It would appear that it is necessary to call `outputStream.Close()` inside the lambda before the Stream Content is sent?! Please can you add this to your answer? Thanks. – David G Dec 06 '19 at 10:28
  • I don't believe that is the case anymore when using the async delegate – skwas Dec 06 '19 at 11:48