Search code examples
c#streamasync-awaittask-parallel-librarystreamreader

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


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?


Solution

  • 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;
    }