0

I'm trying (and failing) to get the actual JSON string from a Request.HttpContent object.

Here's what I'm doing:

private async Task<string> GetRequestBodyAsString(HttpContent content)
{
    string result;

    using (var streamCopy = new MemoryStream())
    {
        await content.CopyToAsync(streamCopy);
        streamCopy.Position = 0;
        result = new StreamReader(streamCopy).ReadToEnd();
    }

    return result;
}

My problem is, on executing this code, I always get an empty string -- unless I use a breakpoint on the line that sets the streamCopy position to zero, which leads me to think that the code just keeps executing after firing up the CopyToAsync method.

If I change it to:

using (var streamCopy = new MemoryStream())
    {
        do
        {
            count++;
            await content.CopyToAsync(streamCopy);
        } while (streamCopy.Length == 0);

        streamCopy.Position = 0;
        result = new StreamReader(streamCopy).ReadToEnd();
    }

it invariably works correctly (as in, result will contain the JSON, but this smells... foul.

What am I doing wrong here?

Peter Huppertz
  • 361
  • 3
  • 7
  • If it's going to end up in `result` anyway, why muck about with streams? - just use `ReadAsStringAsync` and be done with it. – Damien_The_Unbeliever Feb 26 '19 at 11:17
  • 1
    Because the Request.Content has already been used to fill a parameter of the endpoint, and for some reason, we only seem to be allowed to read the request content once (I can't find a way to reset the position of the Request.Content to 0). And if I take the parameter out of the endpoint, and read it into a stream that I can re-use, my Swagger documentation doesn't include the example anymore... – Peter Huppertz Feb 26 '19 at 11:57
  • Well, yes. That's due to the fact that the client may be streaming the content up to the server, the server may never have a complete copy itself and there's no HTTP mechanism to re-request it. There aren't many workarounds here - make sure you only access the content *once*. Once you've accessed it, share it around by other means. – Damien_The_Unbeliever Feb 26 '19 at 11:59

1 Answers1

1

I met the same issue and was trying to adopt your solution. But some further googling leads me to a better solution given here. The original code writes to a file but the idea still applies.

The trick is avoiding using CopyToAsync, but using ReadAsStreamAsync directly. Here is what it looks like after minor changes:

using (Stream ms = await content.ReadAsStreamAsync())
{
    using (var reader = new StreamReader(ms))
    {
        return reader.ReadToEnd();
    }
} 
Bob
  • 381
  • 4
  • 14