Tuesday, May 12, 2009

How to remove image from cache when Image is changed

How to remove image from cache when Image is changed.  If you are looking for How to Remove Cache Image from Client Browser than this post will be useful to you.


How Image Caching Starts
I was in search of Image Caching Technique which can load images which are comonly used in my application from cache, but should also support to display new image when it is replace.  
Example:  Images like Website Logo, Menu Images, and other commonly used images should be load from cache and so that user experience faster performance, but it should also be capable to display new image when changes is occur.  i.e. If user changes their user profile image, than it should display new image and invalidate old image on client browser.

To implement image caching in website which can perform above task i have implemented Image Caching Technique as mentioned in article

So after implementing it, i found that it will Cache the images and you have no control to invalidate cached image as it is stored on user browser, it can only be invalidated if user manually delete cache data, and it is certainly not in control of webmaster.

As first part works like charm (Caching commonly used images), so how should i remove cached image when user change his profile image or display most current image when cached image is changed.  Moreover my application has a dependency wherein name of image cannot be change on changing image.  i.e. User5.jpg is name of image, now whenever user changes his image, old image will be replaced with new image and will be stored with same name User5.jpg, but user browser has cached User5.jpg so how can i invalidate old image and instruct browser to display most current image.

This solution was provided by TechFriend on Asp.net Forum Thanks Mate!

Solution to remove or invalidate image from cache which is stored on user browser

Whenever you are trying to save image append querystring to it and save in database

Example:  if your image name is User5.jpg append querystring like
"~/Image/User5.jpg?" + DateTime.Now.ToString("ddyyhhmmss")

Now whenever User5.jpg image is retrieved from database it has unique querystring append which changes everytime you change image, so if user images changed, its associated name of image will also change and browser will display the latest image, rather than displaying old image as browser identifies it as unique image, which is never cache by browser.

Now whenever you display the image like
<img src="~/Image/User5.jpg?" + DateTime.Now.ToString("ddyyhhmmss")>

It will always display latest image, wherein image name is retrieved from database, and good thing is it will display that image from cache until that image is changed.

Supplement to solution in case Thumbnail Image is generated.
What if you are generating Thumbnail based on above image?  It can be problem as their is no image with name "~/Image/User5.jpg?" + DateTime.Now.ToString("ddyyhhmmss") stored physically on server.

Rest of logic for generating thumbnail image will work good, you just need to add few lines more to perform extra care in our case.  lines which needs to be added is marked in bold.

//Take Original Image Path and Returns Thumbnail Image Path
private string GetThumbnailView(string OriginalImagePath, int height, int width)
{
    string ImgLastVersionNumber = string.Empty;
    if (OriginalImagePath.IndexOf("?") != -1)
    {
        ImgLastVersionNumber = OriginalImagePath.Substring(OriginalImagePath.IndexOf("?"));
        OriginalImagePath = OriginalImagePath.Replace(ImgLastVersionNumber, string.Empty);
    }

    //Consider Image is stored at path like "UserImage\\user9.jpg"
    //Now we have created one another folder UserThumbnail to store thumbnail image of User Image.
    //So let name of image be same, just change the foldername while storing image.
    string thumbnailImagePath = OriginalImagePath.Replace("UserImages", "UserThumbnail");

    //If thumbnail image is not available, generate it.
    if (!System.IO.File.Exists(Server.MapPath(thumbnailImagePath)))
    {
        System.Drawing.Image imgThumbnailImage;

        System.Drawing.Image imgOriginalImage;
        if (!System.IO.File.Exists(Server.MapPath(OriginalImagePath)))
            imgOriginalImage = System.Drawing.Image.FromFile(Server.MapPath(clsGeneral.URLOfDefaultUserImage));
        else
            imgOriginalImage = System.Drawing.Image.FromFile(Server.MapPath(OriginalImagePath));

        imgThumbnailImage = imgOriginalImage.GetThumbnailImage(width, height, new System.Drawing.Image.GetThumbnailImageAbort(ThumbnailCallback), IntPtr.Zero);
        imgThumbnailImage.Save(Server.MapPath(thumbnailImagePath), System.Drawing.Imaging.ImageFormat.Jpeg);

        if (!System.IO.File.Exists(Server.MapPath(OriginalImagePath)))
            imgThumbnailImage.Save(Server.MapPath(OriginalImagePath), System.Drawing.Imaging.ImageFormat.Jpeg);

        imgThumbnailImage.Dispose();
        imgOriginalImage.Dispose();
    }
    return thumbnailImagePath + ImgLastVersionNumber;
}

5 comments:

Nishantha said...

Thanks for Your Article.i was very Intresting and its worked.
Nishantha Hevavitharana

Amazed said...

Frankly it's a damn good solution. I've been seeking the web over this for a few long hours and I've seen tons of topics on the matter but none with a good and easy solution. Thanks!

Sai U said...

thanks.

Đỗ Trang Vương said...

Thanks a lot! It worked!

rtpHarry said...

Hi this works to break the cache but works a little too well. I recommend you read this article which explains why using a querystring isnt a good idea. Basically it breaks the cache -every- time which is not what you want. The best solution is to use url rewriting to map the querystring into the filename.

Most Recent Post

Community Updates

Subscribe Blog via Email

Enter your email address:



Disclaimers:We have tried hard to provide accurate information, as a user, you agree that you bear sole responsibility for your own decisions to use any programs, documents, source code, tips, articles or any other information provided on this Blog.
Page copy protected against web site content infringement by Copyscape