1

I'm writing a ASP.NET server in C# that needs to go get a bunch of images from an external server. The problem that I'm having is that the images are getting returned from my method, but it looks like they're only half loaded.

This is what the tile looks like when loaded thru my server (it's an OSM cycle map tile):

tile.png

And this is what the tile looks like if I just open it in the browser (from the same URL, of course):

5.png

It's pretty clear to me that all of the bytes aren't making it over the wire, but I'm not sure where they're getting lost. This is what my code looks like:

private byte[] GetTile(string url)
{
    var response = WebRequest.Create(url).GetResponse();

    Stream respStr = response.GetResponseStream();

    byte[] buf = new byte[response.ContentLength];
    respStr.Read(buf, 0, buf.Length);

    return buf;
}

This also doesn't feel like the right way to do this. Where are my bytes going? Is there a recommended way to wait for all of the bytes from the server to arrive before I return from the function?

Matthew Kennedy
  • 616
  • 4
  • 19
  • 1
    Jon Skeet has an answer an explanation here: http://stackoverflow.com/questions/221925/creating-a-byte-array-from-a-stream – JoshVarty Nov 04 '12 at 23:58

2 Answers2

4

respStr.Read(buf, 0, buf.Length); Read does not guarentee that it will read buf.Length bytes. you should check its return value. Or simply, you can copy it to another stream using CopyTo

private byte[] GetTile(string url)
{
    var response = WebRequest.Create(url).GetResponse();

    Stream respStr = response.GetResponseStream();

    MemoryStream m = new MemoryStream();
    respStr.CopyTo(m);

    return m.ToArray();
}

You can also use WebClient for this

private byte[] GetTile(string url)
{
    using (WebClient wc = new WebClient())
    {
        return wc.DownloadData(url);
    }
}
L.B
  • 114,136
  • 19
  • 178
  • 224
1

I'm simply parroting Jon Skeet's answer because it applies directly to your problem. Creating a byte array from a stream

Perhaps if someone searches for similar keywords this answer can point them in the right direction. You aren't the first and definitely won't be the last person to have this problem.

The Stream.Read() method does not guarantee that all bytes will be read in the Stream, and this is especially evident when referring to network streams. You need to ensure you check the return value to be absolutely certain that the whole stream has been consumed:

public static byte[] ReadFully(Stream input)
{
    byte[] buffer = new byte[16*1024];
    using (MemoryStream ms = new MemoryStream())
    {
        int read;
        while ((read = input.Read(buffer, 0, buffer.Length)) > 0)
        {
            ms.Write(buffer, 0, read);
        }
        return ms.ToArray();
    }
}
Community
  • 1
  • 1
JoshVarty
  • 9,066
  • 4
  • 52
  • 80