Caching Dynamically Generated Images

Location: BlogsKarin's BlogASP.NET   
Posted by: Karin Huber4/9/2008 12:15 PM

When I published my article about caching images in ASP.NET I got some questions if it is possible to do this with dynamically generated images. The answer is yes. In the following sample I will show how it works.

As explained in the article I implement a custom http handler for the image. But this time I do not load an image from the file system, but I generate a new one. For this purpose I create a new Bitmap object to which I add a string with the current date and time and a rectangle. Then I save the image to a MemoryStream object to convert it to a byte array. Now the interesting part starts. Just as with static files I configure the HttpCachePolicy object to cache the generated image on the client for one minute. Finally I add the content-disposition header to set the filename. This time I use BinaryWrite instead of WriteFile to send the image to the client.

namespace SoftwareArchitects.Web
{
  public class DateTimeImageHandler : IHttpHandler
  {
    public bool IsReusable
    {
      get { return true; }
    }

    public void ProcessRequest(HttpContext context)
    {
      Bitmap dateTimeImage = new Bitmap(220, 50);
      Graphics dateTimeGraphics = Graphics.FromImage(dateTimeImage);

      dateTimeGraphics.DrawString(
        DateTime.Now.ToString(),
        new Font("Verdana", 14),
        new SolidBrush(Color.Blue),
        new PointF(0, 0));

      dateTimeGraphics.DrawRectangle(
        new Pen(new SolidBrush(Color.Green)),
        new Rectangle(0, 0, 219, 49));

      MemoryStream stream = new MemoryStream();
      dateTimeImage.Save(stream, ImageFormat.Png);
      dateTimeGraphics.Dispose();

      byte[] image = new byte[stream.Length];
      stream.Position = 0;
      stream.Read(image, 0, (int)stream.Length);
      stream.Close();

      context.Response.Cache.SetExpires(DateTime.Now.AddMinutes(1));
      context.Response.Cache.SetCacheability(HttpCacheability.Public);
      context.Response.Cache.SetValidUntilExpires(false);

      context.Response.AddHeader("content-disposition", 
        "inline; filename=DateTime.png");
      context.Response.BinaryWrite(image);
    }
  }
}

All I have to do to use the new http handler is to add it to the httpHandlers section of web.config.


      type="SoftwareArchitects.Web.DateTimeImageHandler,
    SoftwareArchitects.Web.DateTimeImageHandler"/>

Now I can add an image to my .aspx page with the source "DateTime.png.ashx". As this file does not exist the path does not matter as long the filename does match the entry in the httpHandlers section in web.config. So I could as well choose the source "MyFolder/DateTime.png.ashx".

...


 

 


  Reload page ...

 


 


...

 

When I run the page the generated image is displayed. It shows the current date and time. For the next minute the image will not change when I reload the page by doing a post back or by clicking the link (I set the caching duration to one minute in the http handler). When I reload the page after the image has expired a new image will be generated and displayed. 

You can force IE to reload cached content by pressing CTRL + F5.

Permalink | Trackback

Comments (21)  Add Comment
Re: Caching Dynamically Generated Images  By chinagug on 1/18/2008 5:47 AM
wonderful

Re: Caching Dynamically Generated Images  By Shreedhar on 1/18/2008 7:30 PM
Very neat

Re: Caching Dynamically Generated Images  By Alec on 1/21/2008 2:22 AM
Thanks for the article, Karin. I can definitely see the value of having precise control over client-side caching, but don't most (all?) modern web browers cache images (and other content types) by default? I'm thinking of the many times I've instructed a client to hit ctrl-F5 when they couldn't see the latest changes on their web site. Also, at my last job as a web developer, we all knew to explicitly disable client-side caching in our browser settings (e.g. always get latest version from the server) while doing development. Otherwise, we'd get into a lot of hair-pulling wondering why the changes we just made weren't reflected in the browser.<br><br>I've no reason to doubt that network traffic and latency might be reduced by fine-tuning client-side caching of various content types, but it never struck me as a pressing issue because of the default client-side caching policies of most web browsers, which seem to handle the matter effectively (although I've never run the numbers on this). Am I missing something?

Re: Caching Dynamically Generated Images  By karin on 1/25/2008 3:36 PM
In my experience there are a lot of users who set the cache behavior to &quot;Every visit to the page&quot;. And even if images are cached by the client a conditional request to the server ensures that the file is still valid. So the clients sends a request for every single file (html, css, images, js, ...). This may lead to 20 and more requests for one single page. At best the client gets a smaller 304 response, which tells the client that it can use the cached file. By setting the Cache-Control and Expires headers the client knows that it can use the cached file without asking the server first. I found a nice article about this at http://msdn2.microsoft.com/en-us/library/bb250442.aspx. You are really lucky if performance does not matter that much. During the last years I had to deal with low bandwith problems all the time. Reducing the number of requests seemed to be an easy but efficient way.

Re: Caching Dynamically Generated Images  By Alec on 1/27/2008 1:09 AM
Thanks for the extra information. I didn't consider how the client makes a request to the server to check if it's OK to use the cached file. It's clear to me now how explicitly setting the Expires header will prevent this, thereby reducing bandwidth. Now you've got me thinking about old projects that probably could have benefited from using your technique! Oh well, maybe next time. Thanks again for the response.

Re: Caching Dynamically Generated Images  By William F on 1/29/2008 3:50 PM
And what about using URL for src attribute like src="DateTimeImage.aspx?IdImage=152356&amp;type=thumbnail ...". I've tried using your method but there's no caching on client side.<br>Those images are called from another application generating dynamic HTML.<br>Any ideas ?<br>I hope i've been clear enough.

Re: Caching Dynamically Generated Images  By William F on 1/29/2008 4:26 PM
And what about using URL for src attribute like src="DateTimeImage.aspx?IdImage=152356&amp;type=thumbnail ...". I've tried using your method but there's no caching on client side.<br>Those images are called from another application generating dynamic HTML.<br>Any ideas ?<br>I hope i've been clear enough.

Image Caching  By Prabu Veeramuthu on 4/22/2008 4:29 PM
Hi,<br>i found your artical about the Image caching. we are using the code which you written. but the browser loading the image. its not loading from the cache. can u help me, what we are doing wrong. <br><br>Thanks,<br>Prabu Veeramuthu<br>(prabu.veeramuthu@chimeratechnologies.com)

Re: Caching Dynamically Generated Images  By Jeffrey R on 5/17/2008 1:41 AM
I noted that when I do a refresh (just an F5, not a Ctrl-F5) I do not get any 304s--I get a new set of images. Whereas if I DO have access to IIS (and I don't on my host, but do in development) using normal header settings, I get both an expiration header and will still get a 304 when I hit refresh. I think this is the ideal. Any way to get this IHttpHandler to return a 304? I dinked for a few minutes but it wasn't immediately clear how I might enhance this. I can get the file date from the file, of course, but swithching the header to a 304 is something I would need to research further.

Re: Caching Dynamically Generated Images  By Jeffrey R on 5/17/2008 4:03 PM
I noted that when I do a refresh (just an F5, not a Ctrl-F5) I do not get any 304s--I get a new set of images. Whereas if I DO have access to IIS (and I don't on my host, but do in development) using normal header settings, I get both an expiration header and will still get a 304 when I hit refresh. I think this is the ideal. Any way to get this IHttpHandler to return a 304? I dinked for a few minutes but it wasn't immediately clear how I might enhance this. I can get the file date from the file, of course, but swithching the header to a 304 is something I would need to research further.

Re: Caching Dynamically Generated Images  By Mike Forsyth on 7/25/2008 10:45 AM
Helpful article - however, I too am having problems with <br><img src="/Asset.aspx?id=123&amp;name=myphoto.jpg" alt="test" /><br>which refuses to give 304 hence delivering images fresh each time - did William F (or anyone) solve this one?<br>

Re: Caching Dynamically Generated Images  By sun on 9/1/2008 7:07 AM
i have a solution,same as Karin Huber's code, the url you get image is like"abc.aspx?name=somepicture",<br><br> string file = "...some jpg image path";<br> Response.Cache.SetExpires(DateTime.Now.AddDays(1));<br> Response.Cache.SetCacheability(HttpCacheability.Public);<br> Response.Cache.SetValidUntilExpires(false); Response.ContentType = "image\\jpeg";<br> Response.WriteFile(file);<br><br>i have listern in Wireshark, first load have a GET request, after this ,all 1 days request do not request server, only get image at client cache

Re: Caching Dynamically Generated Images  By sun on 9/1/2008 9:02 AM
i have a solution,same as Karin Huber's code, the url you get image is like"abc.aspx?name=somepicture",<br><br> string file = "...some jpg image path";<br> Response.Cache.SetExpires(DateTime.Now.AddDays(1));<br> Response.Cache.SetCacheability(HttpCacheability.Public);<br> Response.Cache.SetValidUntilExpires(false); Response.ContentType = "image\\jpeg";<br> Response.WriteFile(file);<br><br>i have listern in Wireshark, first load have a GET request, after this ,all 1 days request do not request server, only get image at client cache

How to remove image from cache when image changes  By dotnetguts on 5/5/2009 1:17 PM
Thanks for gr8 article.<br><br><br>I have one question. What if I have a portal in which user can change their profile image, and as soon as user change their profile image, new image should display rather than cache image, is it possible that i can remove previously stored user image from cache?<br><br>One way is to change name of image, but it is not possible because of nature of application, so how can i change image instantly on change of user image? Example: User4.jpg is name of image, this image name will remain same when User upload new image, but new image will never appears until cache expires so he will always see old User4.jpg image despite he just changed the image.<br><br>Is there any way I can disallow caching of Image for particular folder? or any solution for this problem?<br><br>Its very hard for me to figure out solution for this problem, your help would very much appreciated.<br><br>Thank you so much.

ASPX (Web Page) versus ASHX differences (HttpHandler)  By Nick Gilbert on 6/23/2009 4:57 PM
It's worth mentioning that setting Cache headers on aspx pages doesn't seem to work. I couldn't get caching working until I'd converted my dynamic thumbnail generator to ashx (HttpHandler) format! I wasted hours of time trying to do that, but FireBug always showed the response headers as being "no cache".

Re: Caching Dynamically Generated Images  By Casser on 1/7/2010 9:11 PM
<a href="http://mosdolg.ru">Долги</a> в России больше чем долги. Всех с Новым Годом!!!

Re: Caching Dynamically Generated Images  By annaberta on 1/11/2010 2:36 PM
Votre blog est un petit mais très intéressant! Je vous souhaite du succès et le développement!<br><a href="http://www.jouercasino.eu">casinos virtuels</a>

Re: Caching Dynamically Generated Images  By Jerry mabem on 3/6/2010 1:34 PM
Web based project management software is a tool which assists project managers and team leaders in productive planning, executing and managing different jobs that are involved in each project.<br><br>http://www.project-drive.net/

Re: Caching Dynamically Generated Images  By Home Theater Seating on 3/12/2010 6:33 AM
It is very important to know exactly what to look for when hiring computer service consulting services. The quality of your decision will impact the way in which you do business and the quality of your own services, so it is imperative that you select the best possible professional computer service consulting services.<br><br>=======================<br><b><a href="http://www.theaterseatstore.com/">Home Theater Seating</a></b> | <b><a href="http://www.project-drive.net/">Web Based Project Management Software</a></b>

Re: Caching Dynamically Generated Images  By James on 4/2/2010 2:06 PM
Thank you for the awesome info. I look forward to seeing more of such great articles that I could learn an inspiring stuff from!<br><br><br><a href=" http://www.flashcoms.com/products/chat_roullete/">chat roulette software</a><br>

Re: Caching Dynamically Generated Images  By d on 4/8/2010 7:35 AM
<h1 style="font--size:12px"><br><A href="http://www.salelouboutin.com/christian-louboutin-pumps-c-78.html">christian louboutin</A>--<A href="http://www.buylouboutin.com">louboutin</A>--<A href="http://www.discount--christianlouboutin.com">christian louboutin</A>--<A href="http://www.discount--christianlouboutin.com">louboutin shoes</A>--<A href="http://www.discount--christianlouboutin.com">christian louboutin boots</A>--<A href="http://www.bestlouisvuitton.com">lv handbags</A>--<A href="http://www.sale--mbt.com">mbt shoes</A>--<A href="http://www.discount--christianlouboutin.com">christian louboutin</A>--<A href="http://www.sale--mbt.com/nike--shox--c--29.html">nike shoes</A>--<A href="http://www.sale--mbt.com/nike--shox--c--29.html">cheap nike shoes</A>--<A href="http://www.sale--mbt.com/nike--shox--c--29.html">discount nike shoes</A>--<A href="http://www.sale--mbt.com/nike--shox--c--29.html">nike shoes sale</A>--<A href="http://www.discount--christianlouboutin.com/jimmy--choo--shoes--c--47.html">Jimmy choo</A>--<A href="http://www.discount--christianlouboutin.com/jimmy--choo--shoes--c--47.html">Jimmy choo shoes</A>--<A href="http://www.discount--christianlouboutin.com/jimmy--choo--shoes--c--47.html">cheap Jimmy choo</A>--<A href="http://www.discount--christianlouboutin.com/jimmy--choo--shoes--c--47.html">discount Jimmy choo</A>--<A href="http://www.discount--christianlouboutin.com/jimmy--choo--shoes--c--47.html">Jimmy choo shoes sale</A>--<A href="http://www.sale--mbt.com/moncler--women--c--19.html">moncler women</A>--<A href="http://www.sale--mbt.com/moncler--women--c--19.html">cheap moncler women</A>--<A href="http://www.sale--mbt.com/moncler--women--c--19.html">discount moncler women</A>--<A href="http://www.sale--mbt.com/moncler--women--c--19.html">moncler women sale</A>--<A href="http://www.discount--christianlouboutin.com/manolo--blahnik--c--48.html">Manolo Blahnik</A>--<A href="http://www.discount--christianlouboutin.com/manolo--blahnik--c--48.html">Manolo Blahnik shoes</A>--<A href="http://www.discount--christianlouboutin.com/manolo--blahnik--c--48.html">cheap Manolo Blahnik</A>--<A href="http://www.discount--christianlouboutin.com/manolo--blahnik--c--48.html">discount Manolo Blahnik</A>--<A href="http://www.discount--christianlouboutin.com/manolo--blahnik--c--48.html">Manolo Blahnik sale</A>--<A href="http://www.sale--mbt.com/moncler--men--c--17.html">moncler men</A>--<A href="http://www.sale--mbt.com/moncler--men--c--17.html">cheap moncler men</A>--<A href="http://www.sale--mbt.com/moncler--men--c--17.html">discount moncler men</A>--<A href="http://www.sale--mbt.com/moncler--men--c--17.html">moncler men sale</A>--<A href="http://www.discount--christianlouboutin.com/balmain--shoes--c--50.html">Balmain Shoes</A>--<A href="http://www.discount--christianlouboutin.com/balmain--shoes--c--50.html">cheap Balmain Shoes</A>--<A href="http://www.discount--christianlouboutin.com/balmain--shoes--c--50.html">discount Balmain Shoes</A>--<A href="http://www.discount--christianlouboutin.com/balmain--shoes--c--50.html">Balmain Shoes sale</A>--<A href="http://www.sale--mbt.com/moncler--kids--c--18.html">moncler kids</A>--<A href="http://www.sale--mbt.com/moncler--kids--c--18.html">cheap moncler kids</A>--<A href="http://www.sale--mbt.com/moncler--kids--c--18.html">discount moncler kids</A>--<A href="http://www.sale--mbt.com/moncler--kids--c--18.html">moncler kids sale</A>--<A href="http://www.discount--christianlouboutin.com/yves--saint--laurent--c--49.html">Yves saint Laurent</A>--<A href="http://www.discount--christianlouboutin.com/yves--saint--laurent--c--49.html">Yves saint Laurent shoes</A>--<A href="http://www.discount--christianlouboutin.com/yves--saint--laurent--c--49.html">cheap Yves saint Laurent</A>--<A href="http://www.discount--christianlouboutin.com/yves--saint--laurent--c--49.html">discount Yves saint Laurent</A>--<A href="http://www.discount--christianlouboutin.com/yves--saint--laurent--c--49.html">Yves saint Laurent sale</A>--<A href="http://www.sale--mbt.com/">cheap mbt shoes</A>--<A href="http://www.sale--mbt.com/">discount mbt shoes</A>--<A href="http://www.sale--mbt.com/">mbt shoes sale</A>--<A href="http://www.discount--christianlouboutin.com/ed--hardy--c--46.html">Ed Hardy</A>--<A href="http://www.discount--christianlouboutin.com/ed--hardy--c--46.html">Ed Hardy shoes</A>--<A href="http://www.discount--christianlouboutin.com/ed--hardy--c--46.html">cheap Ed Hardy</A>--<A href="http://www.discount--christianlouboutin.com/ed--hardy--c--46.html">discount Ed Hardy</A>--<A href="http://www.discount--christianlouboutin.com/ed--hardy--c--46.html">Ed Hardy sale</A>--<A href="http://www.discount--christianlouboutin.com/ugg--boots--c--57.html">UGG boots</A>--<A href="http://www.discount--christianlouboutin.com/ugg--boots--c--57.html">cheap UGG boots</A>--<A href="http://www.discount--christianlouboutin.com/ugg--boots--c--57.html">discount UGG boots</A>--<A href="http://www.discount--christianlouboutin.com/ugg--boots--c--57.html">UGG boots sale</A>--<A href="http://www.discount--christianlouboutin.com/alexander--mcqueen--c--51.html">Alexander McQueen</A>--<A href="http://www.discount--christianlouboutin.com/alexander--mcqueen--c--51.html">Alexander McQueen shoes</A>--<A href="http://www.discount--christianlouboutin.com/alexander--mcqueen--c--51.html">cheap Alexander McQueen</A>--<A href="http://www.discount--christianlouboutin.com/alexander--mcqueen--c--51.html">discount Alexander McQueen</A>--<A href="http://www.discount--christianlouboutin.com/alexander--mcqueen--c--51.html">Alexander McQueen sale</A>--<A href="http://www.discount--christianlouboutin.com/chanel--shoes--c--52.html">Chanel Shoes</A>--<A href="http://www.discount--christianlouboutin.com/chanel--shoes--c--52.html">cheap Chanel Shoes</A>--<A href="http://www.discount--christianlouboutin.com/chanel--shoes--c--52.html">discount Chanel Shoes</A>--<A href="http://www.discount--christianlouboutin.com/chanel--shoes--c--52.html">Chanel Shoes sale</A>--<A href="http://www.discount--christianlouboutin.com/gucci--shoes--c--53.html">Gucci Shoes</A>--<A href="http://www.discount--christianlouboutin.com/gucci--shoes--c--53.html">cheap Gucci Shoes</A>--<A href="http://www.discount--christianlouboutin.com/gucci--shoes--c--53.html">discount Gucci Shoes</A>--<A href="http://www.discount--christianlouboutin.com/gucci--shoes--c--53.html">Gucci Shoes sale</A>--<A href="http://www.discount--christianlouboutin.com/tory--burch--shoes--c--54.html">Tory Burch Shoes</A>--<A href="http://www.discount--christianlouboutin.com/tory--burch--shoes--c--54.html">Tory Burch</A>--<A href="http://www.discount--christianlouboutin.com/tory--burch--shoes--c--54.html">cheap Tory Burch Shoes</A>--<A href="http://www.discount--christianlouboutin.com/tory--burch--shoes--c--54.html">discount Tory Burch Shoes</A>--<A href="http://www.discount--christianlouboutin.com/tory--burch--shoes--c--54.html">Tory Burch Shoes sale</A>--<A href="http://www.discount--christianlouboutin.com/lanvin--shoes--c--56.html">Lanvin Shoes</A>--<A href="http://www.discount--christianlouboutin.com/lanvin--shoes--c--56.html">cheap Lanvin Shoes</A>--<A href="http://www.discount--christianlouboutin.com/lanvin--shoes--c--56.html">Lanvin Shoes</A>--<A href="http://www.discount--christianlouboutin.com/lanvin--shoes--c--56.html">Lanvin Shoes sale</A>--<A href="http://www.discount--christianlouboutin.com/bottega--veneta--c--55.html">Bottega Veneta</A>--<A href="http://www.discount--christianlouboutin.com/bottega--veneta--c--55.html">Bottega Veneta shoes</A>--<A href="http://www.discount--christianlouboutin.com/bottega--veneta--c--55.html">cheap Bottega Veneta</A>--<A href="http://www.discount--christianlouboutin.com/bottega--veneta--c--55.html">discount Bottega Veneta</A>--<A href="http://www.discount--christianlouboutin.com/bottega--veneta--c--55.html">Bottega Veneta sale</A>--<br></h1>


Your name:
Title:
Comment:
Add Comment  Cancel 

Search Blog

Blog List

Blog Archive