by Viper
16. June 2009 19:15
I am working on adding new features to Marketweet - Twitter Autofollow application. The new feature will show some details about followers of an account. And one of the details is showing image associated with user's profile. To get that to work, I have developed an image service that downloads the user images in the background. This is done using HttpWebRequest object to send request to image URL that is set as user's profile image. Following code shows you how you can download an image from a web site programatically using HttpWebRequest. Also notice how ContentType property of HttpWebResponse is utilized to make sure that response from the specified URL is of type type/xxxx.
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
DownloadImage(113467,
@"http://s3.amazonaws.com/twitter_production/profile_images/214863919/logo_normal.jpg");
}
static void DownloadImage(int userId, string url)
{
HttpWebRequest webRequest = HttpWebRequest.Create(url) as HttpWebRequest;
HttpWebResponse resp = webRequest.GetResponse() as HttpWebResponse;
if(resp.StatusCode == HttpStatusCode.OK)
{
if (resp.ContentType.Contains("image/"))
{
int idx = resp.ContentType.IndexOf("/");
string fileName = string.Format("{0}.{1}",
userId, resp.ContentType.Substring(idx + 1));
byte[] imageContent = ProcessImageStream(resp);
FileStream fs = new FileStream(fileName, FileMode.Create, FileAccess.Write);
fs.Write(imageContent, 0, imageContent.Length);
fs.Close();
}
}
}
private static byte[] ProcessImageStream(HttpWebResponse resp)
{
Int64 iContentLength = resp.ContentLength;
byte[] streamContent;
MemoryStream memStream = new MemoryStream();
const int BUFFER_SIZE = 4096;
int iRead = 0;
int idx = 0;
Int64 iSize = 0;
memStream.SetLength(BUFFER_SIZE);
try
{
using (memStream)
{
while (true)
{
iRead = 0;
byte[] respBuffer = new byte[BUFFER_SIZE];
iRead = resp.GetResponseStream().Read(respBuffer, 0, BUFFER_SIZE);
if (iRead == 0)
{break;}
iSize += iRead;
memStream.SetLength(iSize);
memStream.Write(respBuffer, 0, iRead);
idx += iRead;
}
streamContent = memStream.ToArray();
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
throw;
}
return streamContent;
}
}
}
Discussion
After this entry was posted, Mark pointed out in his comment that it could be achieved in 2 lines of code. I will post those two lines of code here.
Dim r As New System.Net.WebClient
r.DownloadFile("http://http://aspnetlibrary.com/images/logo.png",
"c:\aspnetlibrary.png")
This approach works perfectly fine if both variables in this method signature are very well known. What this means is that you know that target URL is what it says (that I am an image file of type PNG). Here are some issues that you have to think about when you are building a solution that involves downloading of files (image, multimedia or any kind).
- Lets start with evil that is lurking around these days called Tiny URLs. These started with some good intent but now these have become medium to disguise spam, tricking people into clicking on links that are click advertising, redirecting to questionable sites, key loggers. So if the image URL is like http://tinyurl.com/45fghty, you don't even know what it is. So you really don't know what to save this file as.
- If you don't know what mime type actually is associated with file that is being downloaded.
What you have to rely on is headers that are associated with response. You can see from code snippet how header information is utilized to establish file type and create file name on the fly.