Category Archives

9 Articles

Posted by .Ronald on

Prevent caching of stylesheet and javascript files

First something about caching

The numerous caching options you have in ASP.NET (MVC) are mainly focused on data and page output caching. But caching also occurs at the webserver, network and browser level.  These you can’t always control from within your code.

When your content leaves your application, it is processed by the webserver, depending on the server and version it has numerous options to control how and when it is cached. When your content is processed by the webserver and sent to the browser, there is also the network that can control the caching, namely proxy and web acceleration servers. Finally the content arrives in the browser and the browser itself has also numerous options related to caching. Generally spoken, they all use the same parameters, or at least some of them, to determine when, what and how long the content should be cached.

How does this caching work? Generally spoken, following rules apply:

  1. If the response header says not to cache, it doesn’t cache
  2. If we use a secure or authenticated transfer, like HTTPS, it doesn’t cache either
  3. If the cache expiring time or any other age-controlling header says it’s still ‘fresh’, it doesn’t cache
  4. If there’s an old version in the cache, the server will be asked to validate the version.  If the version is still good, it is served from the cache.
  5. Sometimes when the server cannot be reached due to network failure or disconnectivity, the content is also directly served from the cache.

Then what parameters are used, and how are they used?

  • HTTP Headers: these are sent in the request, but are not visible in the content
    • Expires: tells the cache how long the content stays fresh. After that time, the cache will always check back with the server. It uses an HTTP date in Greenwich Mean Time (GMT), any other or invalid format will be interpreted as in the pas and makes the content uncachable.  For static data you can set a time in the very far future, for highly dynamic content, you can set a time much closer, or even in the past to have the cache refresh the content more often or at every request.
    • Cache-Control: In response to some of the drawbacks of the Expired header, the Cache-Control header class was introduced. It includes (some, not all):
      • max-age=[seconds]
      • public / private
      • no-cache / no-store
      • must-revalidate
    • Pragma: no-cache: the HTTP specifications aren’t clear of what it means, so don’t rely on it, use the ones above
  • HTML meta tags: Unlike HTTP Headers, HTML meta tags are present in the visible content, more precisely in the <HEAD> section of your HTML page. A huge drawback of the us of HTML meta tags is, is that they can only be interpreted by browsers, and not all of them use them like you would expect. So prefer HTTP headers over HTML meta tags

A great Caching Tutorial can be found here:, and another one here: Save Some Cash: Optimize Your Browser Cache

An easy solution

Now, all of the caching systems rely in some way on the full request string to identify the content that is being cached.

So, the easiest solution would be to request a new unique URL every time the resource has changed, with a new version number.

How we do it in ASP.NET MVC

ASP.NET MVC (and ASP.NET Webforms also) doesn’t generate a new version number automatically.  You need to tell it to do so in the AssemblyInfo.cs file.  After a default project setup it contains a line like:

[assembly: AssemblyVersion("")]

The version number is a four-part string with the following format: <major version>.<minor version>.<build number>.<revision>.  You usually set the major and minor version manually, as they are used as the type library version number when the assembly is exported, and don’t (need to) care of the build and revision number.  Well, now we do.

When you change this line to (or add it if it doesn’t exist):

[assembly: AssemblyVersion("1.0.*")]

We tell the compiler to generate a build and revision number for us. The generated build number is the number of days since 1-01-2000 (so 9-08-2010 gives 3873) and the revision number is the number of two second intervals since midnight local time (so a build at 11:59:12 gives 19776).

Now we have instructed our application to generate a new unique build number for us with every build, and every (possible) change of a resource, we can use this number as a unique parameter value in the URL of the the resource.

First we need to pass this version number from controller to view.  In the constructor of the (base)controller we put the version number in the ViewData Dictionary. With the ViewData you easily can pass data from the controller to the view using a key-value pattern.

protected BaseController(){
ViewData["version"] = Assembly.GetExecutingAssembly().GetName().Version;

And finally in the view, all you need to do is append this version number to the URL of the files you want to be prevented from caching:

<script type="text/javascript" language="javascript" src="<%: Url.Content("~/Scripts/commonFunctions.js?" + ViewData["version"]) %>"></script>

This makes sure we have a unique URL for our resources and they are not cached by the browser or a proxy.

Of course, like stated above, there are other ways of preventing files from being cached anywhere between the server and the browser, but the advantage of this method is that you don’t need to poke around in IIS settings (in case when you don’t have access to it) and you can define when and which version of the file you want to be cached.  And you can of course use any other method to generate a unique URL.

One more remark: When building a multi-tier application, make sure you set the version number in the AssemblyInfo.cs of the project where you use it, meaning, that if you put your base controller in a shared assembly, you need to specify the version number in the shared assembly project.

Posted by .Ronald on

Migrate apps from Internet Explorer to Mozilla

When Netscape started the Mozilla browser, it made the conscious decision to support W3C standards. As a result, Mozilla is not fully backwards-compatible with Netscape Navigator 4.x and Microsoft Internet Explorer legacy code; for example, Mozilla does not support as I will discuss later. Browsers, like Internet Explorer 4, that were built before the conception of W3C standards inherited many quirks. In this article, I will describe Mozilla’s quirks mode, which provides strong backwards HTML compatibility with Internet Explorer and other legacy browsers.

MDCMigrate apps from Internet Explorer to Mozilla

Posted by .Ronald on

URL Rewriting in IIS 7

I started to use URL Rewriting on a Windows 2008 Server running Internet Information Server 7.  At the time of writing, a technical preview of the module is available here: Using URL Rewrite Module.

After installing the module, I was able to configure a first rule that rewrote an incoming URL in the form of http://server/en/catalogue/123/abc123 to http://server/Catalogue.aspx?l=en&cat=123&sub=abc123, exactly the way I wanted it.

But when opening the page, I saw my layout and styles were gone.  Not difficult to know where the problem is, because stylesheets and images are loaded from the client with their path relative to the requested page.  In this case a reference to "style.css" will be loaded from http://server/en/catalogue/123/style.css instead of http://server/style.css, as the client doesn’t know we’re using URL rewriting on the server.

To get around this problem, several options are possible.  I’ll list few of them here, some good, some even worse.  Of course, these are not the only ones, but these were the ones I looked at to solve my problem.  Other solutions might be even better, so any input and feedback is welcome. My solution is much easier and fits my needs.  It’s posted below the other options.

  1. Override the Render() method of your base page or masterpage: URL rewriting breaks ASP.NET 2’s themes
  2. Use RewritePath Method (String, Boolean) with the second parameter (rebaseClientPath) set to false. (Huh? custom code?)
  3. Move your images and stylesheets out of the App_Themes folder (WTF?): URL Rewriting and folders with dashcommerce
  4. Hardcode your links to stylesheets and images (OMG!)
  5. I’m not going to list any more options as it’s getting worse and worse…

But why don’t you use the power when you’re using the force?

I wrote a rule that is processed before any other rule, and which takes any url pointing to file in an App_Themes folder (or just a stylesheet, which is also possible in the same way):

  • Pattern: ^(.+)/App_Themes/(.+)
  • Rewrite URL: App_Themes/{R:2}
  • and check "Stop processing of subsequent rules"

If you make sure that this rule is processed before the other regular rules by moving it to the top in the ordered list, than all references to theme files (stylesheets, images,…) are correctly served and your layout remains correct.

Posted by .Ronald on

ASP.Net Load Testing and Optimization Toolkit – So you want to be a hero

One of my passions is optimization. There’s no code related task I like more than making something run better, faster, snappier – from tweaking UI registry keys to stripping out crap code – I want results. Usually if something is noticeably slow on the user’s end, there’s something fundamentally wrong that can be made faster – a lot faster.

PHP vs .NetASP.Net Load Testing and Optimization Toolkit – So you want to be a hero

Posted by .Ronald on

Troubleshooting Expired ASP.NET Session State and Your Options

I have a love/hate relationship with the ASP.NET Session. It’s such a convenient place to put things, but when you start putting applications into production there are a number of less-than-obvious edge cases that can come up and bite you.

Most often the Session is used when managing state over a long process like a multi-step wizard or questionnaire. However, when people use the Session, they often lean on it a little. They’ll bake it into their design so deep that when it doesn’t work, they’re screwed. That’s not to say they shouldn’t be able to lean on it, I’m just saying that there’s a lot of things going on with Session (not just on ASP.NET, but other frameworks as well) in order to get it to look seamless.

Scott Hanselman’s Computer ZenTroubleshooting Expired ASP.NET Session State and Your Options