42

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?

greg7gkb
  • 4,933
  • 4
  • 41
  • 55

3 Answers3

71

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;
}
Iain
  • 2,500
  • 1
  • 20
  • 24
  • 5
    One tiny suggestion here - I often see calls to Seek where the Position property would be simpler and more readable, e.g. ms.Position = 0; Just a thought for future code. – Jon Skeet Sep 29 '08 at 09:42
  • 10
    Another comment - the above doesn't end up closing the incoming stream, ever. It might be worth creating a "CopyAndClose" method which *does* close the stream, just so you could keep the simple calling syntax. – Jon Skeet Sep 29 '08 at 09:43
  • Wow, coming close to my heroes.. I'm currently reading your book, Mr. Skeet :-) What you suggested about closing (and telling with the method name) is exactly what I thought about the above code. – VVS Sep 29 '08 at 10:16
  • 10
    .net 4 and above have shorter way of copying streams: [CopyTo](http://stackoverflow.com/questions/230128/best-way-to-copy-between-two-stream-instances) – Endy Tjahjono Jan 10 '13 at 12:49
2

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.)

Jack Miller
  • 6,843
  • 3
  • 48
  • 66
-1

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.

Joachim Kerschbaumer
  • 9,695
  • 7
  • 49
  • 84