by Jörg Jooss
20. February 2007 03:55
Judging from the recurrence of certain really frequently asked questions in microsoft.public.dotnet.framework.aspnet, one of the greater mysteries of ASP.NET web development remains caching, or HTTP caching to be more precisely. So let's review some of the seminal caching issues in ASP.NET web development.
Problem: You reference one or more static resources (e.g. an image or a style sheet) in your ASP.NET page, either through server controls or plain old HTML. But when you update such a resource, your browser continues to use its previous version. Only after an end-to-end reload (typically, this means hitting Ctrl-F5) does the browser use the updated resource.
Reason: IIS 5/6 don't add any HTTP Cache-Control headers to static resources by default, which makes caches apply their own heuristics to consider whether such a resource is to be considered "fresh" or "stale". That's deliberate lack of control coupled with implementation specific behavior, which in turn is just a fancy way of saying you're asking for trouble.
Solution: Put all static resources with similar caching requirements in a common folder in your web application, and set specific caching instructions for this folder in IIS Manager. Here you have three options:

- Let IIS apply expiration rules
- "Expire immediately" sets "Cache-Control: no-cache", and "Expires" to the same timestamp as "Date". Any resource served like this becomes immediately stale.
- The other two options let you specify either a relative point in time or an absolute point in time for expiration. These options set both the "Cache-Control: max-age" and "Expires" headers.
- Set your own HTTP Cache-Control headers.
- Both of the above.
If you can not or do not want to use folders for this purpose, you can also apply the same options to individual files.
Each time you update a static resource, make sure that the resource's file modification time is updated to the current time (i.e. "touch" the resource). If the modification time doesn't change, IIS may fail to recognize that the resource has been updated (which is a topic for another blog entry).