"stream was not readable" ArgumentException when using ReadAsStreamAsync with StreamReader

Romonov picture Romonov · Jun 23, 2015 · Viewed 7.5k times · Source

I have the following piece of code to read and process the response of a Http get request using StreamReader:

try
{
    Stream stream = await ExecuteRequestAsync(uriBuilder.Uri, HttpMethod.Get).ConfigureAwait(false);
    if (stream != null)
    {
        using (StreamReader sr = new StreamReader(stream))
        {
            using (JsonTextReader reader = new JsonTextReader(sr))
            {
                ...
            }
        }
    }
}
catch (Exception ReadingStreamException)
{

}

private async Task<stream> ExecuteRequestAsync(Uri uri, HttpMethod method)
{
    Stream stream;
    using (HttpRequestMessage httpRequestMessage = new HttpRequestMessage(method, uri))
    {
    try
    {
        stopwatch.Start();
        using (HttpResponseMessage responseMessage = await this.httpClient.SendAsync(httpRequestMessage).ConfigureAwait(false))
        {
            stream = await responseMessage.Content.ReadAsStreamAsync().ConfigureAwait(false);
        }
    }
    catch(Exception GettingStreamException)
    {
        // Error checking code
    }

    return stream;
}

The line using (StreamReader sr = new StreamReader(stream)), is throwing an exception to ReadingStreamException of type ArgumentException with the detail "Stream was not readable". Is there something wrong with the above code?

Answer

Yuval Itzchakov picture Yuval Itzchakov · Jun 23, 2015

This happens because when you dispose HttpResponseMessage, it disposes the underlying stream. From the source:

private HttpContent content;
protected virtual void Dispose(bool disposing)
{
    if (disposing && !disposed)
    {
        disposed = true;
        if (content != null)
        {
            content.Dispose();
        }
    }
}

You can either copy the stream, or simply not dispose HttpResponseMessage, as you'll dispose the underlying stream anyway when passing it to StreamReader. I'd go with the latter:

private async Task<Stream> ExecuteRequestAsync(Uri uri, HttpMethod method)
{
    Stream stream = null;
    using (HttpRequestMessage httpRequestMessage = new HttpRequestMessage(method, uri))
    {
       try
       {
          stopwatch.Start();
          HttpResponseMessage responseMessage = await httpClient
                                                      .SendAsync(httpRequestMessage)
                                                      .ConfigureAwait(false);

          stream = await responseMessage.Content.ReadAsStreamAsync()
                                                .ConfigureAwait(false);
       }
       catch(Exception GettingStreamException)
       {
          // Error checking code
       }  
    }
    return stream;
}