HttpWebRequest can use the IE cache, so if all the images are in this cache anyway, and the cost of overwriting the file (but not for downloading it) is acceptable, you can simply use this.
If you need to deal with this yourself, then:
Given:
string uri; //URI of the image. DateTime? lastMod; // lastModification date of image previously recorded. Null if not known yet. string eTag; //eTag of image previously recorded. Null if not known yet.
You will need to save them at the end of this and return them again (when this is not a new image) at the beginning. This is for you, given that everything works:
var req = (HttpWebRequest)WebRequest.Create(uri); if(lastMod.HasValue) req.IfModifiedSince = lastMod.Value;//note: must be UTC, use lastMod.Value.ToUniversalTime() if you store it somewhere that converts to localtime, like SQLServer does. if(eTag != null) req.AddHeader("If-None-Match", eTag); try { using(var rsp = (HttpWebResponse)req.GetResponse()) { lastMod = rsp.LastModified; if(lastMod.Year == 1)//wasn't sent. We're just going to have to download the whole thing next time to be sure. lastMod = null; eTag = rsp.GetResponseHeader("ETag");//will be null if absent. using(var stm = rsp.GetResponseStream()) { //your code to save the stream here. } } } catch(WebException we) { var hrsp = we.Response as HttpWebResponse; if(hrsp != null && hrsp.StatusCode == HttpStatusCode.NotModified) { //unfortunately, 304 when dealt with directly (rather than letting //the IE cache be used automatically), is treated as an error. Which is a bit of //a nuisance, but manageable. Note that if we weren't doing this manually, //304s would be disguised to look like 200s to our code. //update these, because possibly only one of them was the same. lastMod = hrsp.LastModified; if(lastMod.Year == 1)//wasn't sent. lastMod = null; eTag = hrsp.GetResponseHeader("ETag");//will be null if absent. } else //some other exception happened! throw; //or other handling of your choosing }
E-tags are more reliable than the last ones; they are modified if implemented correctly (noting seatpost permissions for changes and reflecting different answers due to different Accept- * headers). However, some implementations are erroneous (IIS6 on a web farm without much configuration, Apache with mod-gzip), so itโs worth extracting the code related to electronic tags and just go to the date.
Edit: if you want to implement HTTP caching even more, you can also keep the expiration date and the maximum age (use the latter if both are present and he does not agree with the first) and fully downloaded if it is earlier than these values. I did this and it works well (I had a cache in memory of objects created from XML returned by different URIs, and if the XML was fresh or not changed, I reused the object), but this may not be appropriate for your needs ( if you want to be fresher than the server offers, or if you will always be outside this window).