ASP.NET Performance – Part 4 – CDN

In part 3 we created three helper functions to use when including css, js and images in our pages. As you might expect, YSlow has something to say about how to maximize the performance of such files beyond caching. Specifically, YSlow makes the following three recommendations:

  • Use a Content Delivery Network (CDN),
  • Use cookie-free domains, and
  • Split Components Across Domains

All three are super-easy to implement, and are all “fixed” by the same code (we won’t actually use a CDN, but we’ll make it so that its easy to use if the need ever arises). To be honest, I hadn’t even considered the possibility of using separate domains to minimize the overhead associated with sending cookie information. Some may say that this is a microoptimization, but it takes less than five minutes to implement, so why not? (if you aren’t using cookies, you won’t see any benefits of this, except for the parallel downloading and flexibility of using a cdn in the future).

If you recall, the initial version of our helper functions, without our cache busting, looked like:

public static string IncludeCss(this HtmlHelper html, string name)
    return string.Format("<link href=\"/assets/styles/{0}.css\" rel=\"stylesheet\" type=\"text/css\"></link>", name);
public static string IncludeJs(this HtmlHelper html, string name)
    return string.Format("<script src=\"/assets/js/{0}.js\" type=\"text/javascript\"></script>", name);
public static string Image(this HtmlHelper html, string name, int width, int height, string alt)
    return string.Format("<img src=\"/assets/mages/{0}\" width=\"{1}\" height=\"{2}\" alt=\"{3}\" />", name, width, height, alt);

(I’m doing this against the initial version just to keep things simple, but integrating our Part 3 and Part 4 end-results should be trivial).

All we need to do is a little change:

private static readonly string _assetUrl = ConfigurationManager.AppSettings["assetUrl"];
public static string IncludeCss(this HtmlHelper html, string name)
    return string.Format("<link href=\"{0}assets/styles/{1}.css\" rel=\"stylesheet\" type=\"text/css\"></link>", _assetUrl, name);
//...similar changes the for js and image method.

and change our web.config to include the value:

    <add key="assetUrl" value=""/>

Finally you’ll need to setup the subdomain.

While we aren’t using a CDN, we’ve made it very easy to start using a CDN by making the root URL path for our assets configurable. We’ve also ensured that cookies defined for aren’t going to add overhead when requesting assets sitting on

For the curious, YSlow doesn’t know whether the domain is a CDN or not, you have to tell it that it is by adding it to a list.

A final word of caution, YSlow also warns against too many DNS lookups – so while its important to use a cdn, use non-cookie domains and split up our content to allow for greater parallel downloads, don’t over do it. They generally recommend less than 4, but their own website uses 6. We’ve added 1, which, in my opinion is worth it, but try not to add too many (consider that you’ll likely add one for google analytics and possible for ads…).

Part 5 will be our last part in the series, and will be very different than what we’ve looked at so far.

This entry was posted in Uncategorized. Bookmark the permalink. Follow any comments here with the RSS feed for this post.

4 Responses to ASP.NET Performance – Part 4 – CDN

  1. Agreed with @alberto, if you are using a parent domain for the main site…, then any cookies assigned, will be passed down to, best to use www. or use another domain for the assets.

  2. alberto says:

    IIRC, if you use and the latter will still have access to cookies from the former. You should use instead or a completely different domain name.

  3. karl says:

    Jonathan: good point on the ssl stuff. As for the revision numbers, I covered that in part 2 and 3 (and there are some useful comments about using querystring vs filenames, but readers should get the idea).

  4. Remember to purchase and install an SSL certificate for the subdomain so that your HTTPS pages display properly.

    You may also may also want to tweak the code above slightly to detect secure connections and change the asset URL protocol accordingly.

    Large websites, such as Yahoo, Google, and eBay have an interesting step in their website publishing process. They append the revision number to each script/CSS/image filename , e.g. logo1.jpg, logo2.jpg, etc. Then they have a compilation step that modifies their HTML pages accordingly. Finally, they mark each static with an expiration policy of 10 years.

    The above set of steps accomplishes two things:
    1. Local ISPs now cache each static resource. This allows users to receive the content much more quickly and to make your page load faster.
    2. Because ISPs are caching those resources locally and requests are not hitting your server, it frees up CPU cycles on your server and enables a single server to handle more users concurrently (if you’re hosting the static files yourself instead of a CDN).