James Moore James Moore - 3 months ago 13
C# Question

Periodically read from Task<Stream> returned from Http PostAsync response content

I have an application where after posting a file to a server, the server periodically returns messages to the client application about the upgrade process in it's response.

I used to have code that looks something like

using (HttpWebResponse httpResponse = (HttpWebResponse)httpRequest.GetResponse())
{
using (Stream responseStream = httpResponse.GetResponseStream())
{
using (var reader = new StreamReader(stream))
{
while(!streamReader.EndOfStream)
{
var str = streamReader.ReadLine();
// Do something with str
}
}
}
}


After updating my code to utilize the
HttpClient
class I am struggling to find a method that will do the same as the code above.

var response = client.PostAsync(uploadUrl, content).Result;

var stream = response.Content.ReadAsStreamAsync().Result;

var streamReader = new StreamReader(stream);

// Superfluous due to the fact we are already at end of stream
while(!streamReader.EndOfStream)
{
var str = streamReader.ReadLine();
// Do something with str
}


If I try something like the above then we wait until the entire stream has been populate before returning it all in one go due to the use of the
response.Content.ReadAsStreamAsync().Result
call. This is not suitable as I wish to display the information in real time when it is returned from the server.

Is it possible to periodically read from the stream as is done in the above example when we have an
Task<Stream>
object?

Answer

The reason why ReadAsStreamAsync() only returns after all content is received is because PostAsync() internally uses HttpCompletionOption.ResponseContentRead, what you want is HttpCompletionOption.ResponseHeadersRead.

Some methods on HttpClient have an overload that accepts HttpCompletionOption, which allows you to override the default. Unfortunately for you, PostAsync() does not. Apparently, this is because responses to POST requests are not supposed to be long.

But you can still do what you want by using the general SendAsync() method:

var response = client.SendAsync(
    new HttpRequestMessage(HttpMethod.Post, uploadUrl) { Content = content },
    HttpCompletionOption.ResponseHeadersRead).Result;
Comments