How can I read an Http response stream twice in C#?

Viewed 35123

I am trying to read an Http response stream twice via the following:

HttpWebResponse response = (HttpWebResponse)request.GetResponse();
stream = response.GetResponseStream();
RssReader reader = new RssReader(stream);
do
{
  element = reader.Read();
  if (element is RssChannel)
  {
    feed.Channels.Add((RssChannel)element);
  }
} while (element != null);

StreamReader sr = new StreamReader(stream);
feed._FeedRawData = sr.ReadToEnd();

However when the StreamReader code executes there is no data returned because the stream has now reached the end. I tried to reset the stream via stream.Position = 0 but this throws an exception (I think because the stream can't have its position changed manually).

Basically, I would like to parse the stream for XML and have access to the raw data (in string format).

Any ideas?

3 Answers

Copy it into a new MemoryStream first. Then you can re-read the MemoryStream as many times as you like:

Stream responseStream = CopyAndClose(resp.GetResponseStream());
// Do something with the stream
responseStream.Position = 0;
// Do something with the stream again


private static Stream CopyAndClose(Stream inputStream)
{
    const int readSize = 256;
    byte[] buffer = new byte[readSize];
    MemoryStream ms = new MemoryStream();

    int count = inputStream.Read(buffer, 0, readSize);
    while (count > 0)
    {
        ms.Write(buffer, 0, count);
        count = inputStream.Read(buffer, 0, readSize);
    }
    ms.Position = 0;
    inputStream.Close();
    return ms;
}

Copying the stream to a MemoryStream as suggested by Iain is the right approach. But since .NET Framework 4 (released 2010) we have Stream.CopyTo. Example from the docs:

// Create the streams.
MemoryStream destination = new MemoryStream();

using (FileStream source = File.Open(@"c:\temp\data.dat",
    FileMode.Open))
{

    Console.WriteLine("Source length: {0}", source.Length.ToString());

    // Copy source to destination.
    source.CopyTo(destination);
}

Console.WriteLine("Destination length: {0}", destination.Length.ToString());

Afterwards you can read destination as many times as you like:

// re-set to beginning and convert stream to string
destination.Position = 0;
StreamReader streamReader = new StreamReader(destination);
string text = streamReader.ReadToEnd();
// re-set to beginning and read again
destination.Position = 0;
RssReader cssReader = new RssReader(destination);

(I have seen Endy's comment but since it is an appropriate, current answer, it should have its own answer entry.)

have you tried resetting the stream position? if this does not work you can copy the stream to a MemoryStream and there you can reset the position (i.e. to 0) as often as you want.

Related