views:

424

answers:

3

How do I force IIS 7 to not cache images for a particular page?

+1  A: 

I've had to deal with this a lot but i need to better understand your end goal as IIS7 will update it's cache if an image is changed on the server, so maybe what you are seeing is the browser cache, have you looked into etags?

The old fall back is to stick a random query string at the end of the image path which keeps the browser guessing.

One sure way to prevent it from caching is to make custom file handler for .gif, .jpg, .png extention (lookup iHttpHandler) (code below lifted from http://www.codeguru.com/csharp/csharp/cs%5Fnetwork/http/article.php/c12641/

using System.IO;
using System.Web;
using System.Globalization;

namespace MVPHacks
{
public class ImageHandler: IHttpHandler
{
 public void ProcessRequest(System.Web.HttpContext ctx)
 {
     HttpRequest req = ctx.Request;
     string path = req.PhysicalPath;
     string extension = null;

     string contentType = null;
     extension = Path.GetExtension(path).ToLower();
     switch (extension)
     {
         case ".gif":
             contentType = "image/gif";
             break;
         case ".jpg":
             contentType = "image/jpeg";
             break;
         case ".png":
             contentType = "image/png";
             break;
         default:
          throw new NotSupportedException("Unrecognized image type.");
     }    if (!File.Exists (path))
     {
         ctx.Response.Status = "Image not found";
         ctx.Response.StatusCode = 404;
     }
     else
     {
         ctx.Response.StatusCode = 200;
         ctx.Response.ContentType = contentType;
         ctx.Response.WriteFile (path);
     }
 }

     public bool IsReusable { get {return true; } }
 }
}

And don't forget to remove the default image handlers and add your in both sections of the web.config

<httpHandlers>
      <clear /> 
      <add verb="*" path="*.jpg" type="MVPHacks.ImageHandler" />
      <add verb="*" path="*.gif" type="MVPHacks.ImageHandler" />
      <add verb="*" path="*.png" type="MVPHacks.ImageHandler" />
</httpHandlers>

<handlers>
      <clear />
      <add verb="*" path="*.png" type="MVPHacks.ImageHandler" name="png" /> 
      <add verb="*" path="*.gif" type="MVPHacks.ImageHandler" name="gif" />
      <add verb="*" path="*.jpg" type="MVPHacks.ImageHandler" name="jpg />
</handlers>
rizzle
Yes, it could be client side cache issue. However, wouldn't the browser have to honor the no-cache? I don't know if the handler works for us because it's only certain images that we don't want to cache. Everything else should still cache.
Esteban Araya
Actually you could set the handler to respond to a string matched set and forward the rest of the requests to the staticfilehandler
rizzle
+2  A: 

I would have thought that it is your browser doing the caching.

In any case one way around this as long as your link is not statically declared in the html, is to append a random number on the end of the images url:

<img src="http://mywebsite/images/mypic.png?a=123456" />

the argument means nothing because you are doing nothing with it, but to the browser it looks like a new uncached link.

How you put that random number on the end is up to you:

<img src="javascript:getMyLink();" />

or from the code behind:

Image myImage = new Image();
myImage.Source = "myurl?a=" + Guid.NewGuid().ToString();
someOtherControl.Controls.Add(myImage);

(of course this is pseudo code, you need to check that the property names are correct).

slugster
Yes, this also works. I was trying to avoid the random query string, however.
Esteban Araya
+3  A: 

In IIS7, you can do this either declaratively in your web.config, or programmatically.

<location path="YourPath">
  <system.webServer>
    <staticContent>
      <clientCache cacheControlMode="DisableCache" />
    </staticContent>
  </system.webServer>
</location>

The programmatic solution requires a simple HttpModule that's registered to run for all requests in Integrated mode, where you look for the URLs that you're concerned about. Then call:

context.Response.Cache.SetCacheability(HttpCacheability.NoCache);

FWIW, you may want to consider disabling client-side caching only, while enabling server-side caching, by using HttpCacheability.ServerAndNoCache. Also, if you add a query string on the image names, you will prevent server-side caching by http.sys.

In case it helps, I cover techniques like these in detail in my book: Ultra-Fast ASP.NET.

RickNZ
I'll give it a try on Monday, but this looks exactly like what I was looking for.
Esteban Araya